ui enhancements

This commit is contained in:
miloschwartz
2025-12-24 15:53:08 -05:00
parent c5ece144d0
commit 9fba9bd6b7
13 changed files with 131 additions and 73 deletions

View File

@@ -37,7 +37,7 @@ export async function Layout({
(sidebarStateCookie !== "expanded" && defaultSidebarCollapsed);
return (
<div className="flex h-screen overflow-hidden">
<div className="flex h-screen-safe overflow-hidden">
{/* Desktop Sidebar */}
{showSidebar && (
<LayoutSidebar
@@ -75,7 +75,7 @@ export async function Layout({
<div
className={cn(
"container mx-auto max-w-12xl mb-12",
showHeader && "pt-16 md:pt-16" // Add top padding on mobile and desktop to account for fixed header
showHeader && "md:pt-16" // Add top padding only on desktop to account for fixed header
)}
>
{children}

View File

@@ -48,7 +48,7 @@ export function LayoutMobileMenu({
const t = useTranslations();
return (
<div className="shrink-0 md:hidden fixed top-0 left-0 right-0 z-50 bg-card border-b border-border">
<div className="shrink-0 md:hidden sticky top-0 z-50">
<div className="h-16 flex items-center px-2">
<div className="flex items-center gap-4">
{showSidebar && (

View File

@@ -198,7 +198,7 @@ export default function ProxyResourcesTable({
if (!targets || targets.length === 0) {
return (
<div className="flex items-center gap-2">
<div id="LOOK_FOR_ME" className="flex items-center gap-2">
<StatusIcon status="unknown" />
<span className="text-sm">
{t("resourcesTableNoTargets")}

View File

@@ -0,0 +1,79 @@
"use client";
import { useEffect } from "react";
/**
* Fixes mobile viewport height issues when keyboard opens/closes
* by setting a CSS variable with a stable viewport height
* Only applies on mobile devices (< 768px, matching Tailwind's md breakpoint)
*/
export function ViewportHeightFix() {
useEffect(() => {
// Check if we're on mobile (md breakpoint is typically 768px)
const isMobile = () => window.innerWidth < 768;
// On desktop, don't set --vh at all, let CSS use 100vh directly
if (!isMobile()) {
// Remove --vh if it was set, so CSS falls back to 100vh
document.documentElement.style.removeProperty("--vh");
return;
}
// Mobile-specific logic
let maxHeight = window.innerHeight;
let resizeTimer: NodeJS.Timeout;
// Set the viewport height as a CSS variable
const setViewportHeight = (height: number) => {
document.documentElement.style.setProperty("--vh", `${height}px`);
};
// Set initial value
setViewportHeight(maxHeight);
const handleResize = () => {
// If we switched to desktop, remove --vh and stop
if (!isMobile()) {
document.documentElement.style.removeProperty("--vh");
return;
}
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
const currentHeight = window.innerHeight;
// Track the maximum height we've seen (when keyboard is closed)
if (currentHeight > maxHeight) {
maxHeight = currentHeight;
setViewportHeight(maxHeight);
}
// If current height is close to max, update max (keyboard closed)
else if (currentHeight >= maxHeight * 0.9) {
maxHeight = currentHeight;
setViewportHeight(maxHeight);
}
// Otherwise, keep using the max height (keyboard is open)
}, 100);
};
const handleOrientationChange = () => {
// Reset on orientation change
setTimeout(() => {
maxHeight = window.innerHeight;
setViewportHeight(maxHeight);
}, 150);
};
window.addEventListener("resize", handleResize);
window.addEventListener("orientationchange", handleOrientationChange);
return () => {
window.removeEventListener("resize", handleResize);
window.removeEventListener("orientationchange", handleOrientationChange);
clearTimeout(resizeTimer);
};
}, []);
return null;
}

View File

@@ -73,35 +73,30 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
>
{asChild ? (
props.children
) : (
) : loading ? (
<span className="relative inline-flex items-center justify-center">
<span
className={cn(
"inline-flex items-center justify-center",
loading && "opacity-0"
)}
>
<span className="inline-flex items-center justify-center opacity-0">
{props.children}
</span>
{loading && (
<span className="absolute inset-0 flex items-center justify-center">
<span className="flex items-center gap-1">
<span
className="h-1 w-1 bg-current animate-dot-pulse"
style={{ animationDelay: "0ms" }}
/>
<span
className="h-1 w-1 bg-current animate-dot-pulse"
style={{ animationDelay: "200ms" }}
/>
<span
className="h-1 w-1 bg-current animate-dot-pulse"
style={{ animationDelay: "400ms" }}
/>
</span>
<span className="absolute inset-0 flex items-center justify-center">
<span className="flex items-center gap-1.5">
<span
className="h-1 w-1 bg-current animate-dot-pulse"
style={{ animationDelay: "0ms" }}
/>
<span
className="h-1 w-1 bg-current animate-dot-pulse"
style={{ animationDelay: "200ms" }}
/>
<span
className="h-1 w-1 bg-current animate-dot-pulse"
style={{ animationDelay: "400ms" }}
/>
</span>
)}
</span>
</span>
) : (
props.children
)}
</Comp>
);

View File

@@ -14,13 +14,13 @@ const checkboxVariants = cva(
variants: {
variant: {
outlinePrimary:
"border rounded-[5px] border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
"border rounded-[5px] border-input data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
outline:
"border rounded-[5px] border-input data-[state=checked]:bg-muted data-[state=checked]:text-accent-foreground",
"border rounded-[5px] border-input data-[state=checked]:border-primary data-[state=checked]:bg-muted data-[state=checked]:text-accent-foreground",
outlinePrimarySquare:
"border rounded-[5px] border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
"border rounded-[5px] border-input data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
outlineSquare:
"border rounded-[5px] border-input data-[state=checked]:bg-muted data-[state=checked]:text-accent-foreground"
"border rounded-[5px] border-input data-[state=checked]:border-primary data-[state=checked]:bg-muted data-[state=checked]:text-accent-foreground"
}
},
defaultVariants: {
@@ -30,8 +30,7 @@ const checkboxVariants = cva(
);
interface CheckboxProps
extends
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,
extends React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,
VariantProps<typeof checkboxVariants> {}
const Checkbox = React.forwardRef<
@@ -50,9 +49,8 @@ const Checkbox = React.forwardRef<
));
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
interface CheckboxWithLabelProps extends React.ComponentPropsWithoutRef<
typeof Checkbox
> {
interface CheckboxWithLabelProps
extends React.ComponentPropsWithoutRef<typeof Checkbox> {
label: string;
}