tables support

This commit is contained in:
2025-12-26 17:49:37 +01:00
parent 91554d36a5
commit 6bf0581497
6 changed files with 23 additions and 19 deletions

View File

@@ -34,7 +34,7 @@ export default function Layout() {
</Button> </Button>
</div> </div>
</header> </header>
<div className="flex-1 p-4 md:p-6 bg-muted/10"> <div className="flex-1 p-4 lg:p-6 bg-muted/10">
<Outlet /> <Outlet />
</div> </div>
</main> </main>

View File

@@ -141,7 +141,7 @@ export function NoteCard({ note }: NoteCardProps) {
</Badge> </Badge>
))} ))}
</div> </div>
<div className="flex justify-end w-full gap-1 opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity"> <div className="flex justify-end w-full gap-1 opacity-100 lg:opacity-0 lg:group-hover:opacity-100 transition-opacity">
<Button variant="ghost" size="icon" className="h-8 w-8 hover:bg-black/5 dark:hover:bg-white/10" onClick={(e) => { e.stopPropagation(); setHistoryOpen(true); }} title={t("History")}> <Button variant="ghost" size="icon" className="h-8 w-8 hover:bg-black/5 dark:hover:bg-white/10" onClick={(e) => { e.stopPropagation(); setHistoryOpen(true); }} title={t("History")}>
<History className="h-4 w-4" /> <History className="h-4 w-4" />
</Button> </Button>

View File

@@ -207,7 +207,7 @@ function Sidebar({
return ( return (
<div <div
className="group peer text-sidebar-foreground hidden md:block" className="group peer text-sidebar-foreground hidden lg:block"
data-state={state} data-state={state}
data-collapsible={state === "collapsed" ? collapsible : ""} data-collapsible={state === "collapsed" ? collapsible : ""}
data-variant={variant} data-variant={variant}
@@ -229,7 +229,7 @@ function Sidebar({
<div <div
data-slot="sidebar-container" data-slot="sidebar-container"
className={cn( className={cn(
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex", "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear lg:flex",
side === "left" side === "left"
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]", : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
@@ -310,7 +310,7 @@ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
data-slot="sidebar-inset" data-slot="sidebar-inset"
className={cn( className={cn(
"bg-background relative flex w-full flex-1 flex-col", "bg-background relative flex w-full flex-1 flex-col",
"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2", "lg:peer-data-[variant=inset]:m-2 lg:peer-data-[variant=inset]:ml-0 lg:peer-data-[variant=inset]:rounded-xl lg:peer-data-[variant=inset]:shadow-sm lg:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
className className
)} )}
{...props} {...props}
@@ -569,7 +569,7 @@ function SidebarMenuAction({
"peer-data-[size=lg]/menu-button:top-2.5", "peer-data-[size=lg]/menu-button:top-2.5",
"group-data-[collapsible=icon]:hidden", "group-data-[collapsible=icon]:hidden",
showOnHover && showOnHover &&
"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0", "peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
className className
)} )}
{...props} {...props}

View File

@@ -1,6 +1,6 @@
import * as React from "react" import * as React from "react"
const MOBILE_BREAKPOINT = 768 const MOBILE_BREAKPOINT = 1025
export function useIsMobile() { export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined) const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)

View File

@@ -5,6 +5,9 @@
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@theme inline { @theme inline {
/* Override lg breakpoint to include 1024px devices (tablets) in mobile layout */
--breakpoint-lg: 1025px;
--radius-sm: calc(var(--radius) - 4px); --radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px); --radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius); --radius-lg: var(--radius);

View File

@@ -14,12 +14,13 @@ import { useKeyboardShortcuts } from "@/hooks/use-keyboard-shortcuts";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
// Masonry breakpoint columns configuration // Masonry breakpoint columns configuration
// react-masonry-css: key = max-width, value = column count at that width and below
// Check order: finds first key >= viewport width
const masonryBreakpoints = { const masonryBreakpoints = {
default: 4, default: 4, // Default for very large screens
1280: 4, 1280: 4, // 1025-1280px: 4 columns (wide desktop)
1024: 3, 1024: 2, // 481-1024px: 2 columns (tablets - since sidebar is overlay)
768: 2, 480: 1, // 0-480px: 1 column (phones)
640: 1,
}; };
export default function DashboardPage() { export default function DashboardPage() {
@@ -93,10 +94,10 @@ export default function DashboardPage() {
}; };
return ( return (
<div className="max-w-7xl mx-auto pb-20 md:pb-0"> <div className="max-w-7xl mx-auto pb-20 lg:pb-0 overflow-x-hidden">
{/* Action Bar */} {/* Action Bar */}
<div className="flex flex-col md:flex-row gap-4 justify-between items-center mb-6"> <div className="flex flex-col lg:flex-row gap-4 justify-between items-center mb-6">
<div className="relative w-full md:w-96"> <div className="relative w-full lg:w-96">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input <Input
ref={searchInputRef} ref={searchInputRef}
@@ -108,7 +109,7 @@ export default function DashboardPage() {
/> />
</div> </div>
<div className="items-center gap-2 hidden md:flex"> <div className="items-center gap-2 hidden lg:flex">
<div className="flex items-center bg-muted/50 p-1 rounded-lg border"> <div className="flex items-center bg-muted/50 p-1 rounded-lg border">
<Button <Button
variant="ghost" variant="ghost"
@@ -130,7 +131,7 @@ export default function DashboardPage() {
</Button> </Button>
</div> </div>
{!isArchive && ( {!isArchive && (
<div className="hidden md:block"> <div className="hidden lg:block">
<CreateNoteDialog open={createNoteOpen} onOpenChange={setCreateNoteOpen} /> <CreateNoteDialog open={createNoteOpen} onOpenChange={setCreateNoteOpen} />
</div> </div>
)} )}
@@ -154,7 +155,7 @@ export default function DashboardPage() {
{isLoading && ( {isLoading && (
<div className={clsx( <div className={clsx(
viewMode === "grid" viewMode === "grid"
? "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4" ? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"
: "flex flex-col gap-4 max-w-3xl mx-auto" : "flex flex-col gap-4 max-w-3xl mx-auto"
)}> )}>
<NoteCardSkeletonGrid count={viewMode === "list" ? 4 : 8} /> <NoteCardSkeletonGrid count={viewMode === "list" ? 4 : 8} />
@@ -206,7 +207,7 @@ export default function DashboardPage() {
trigger={ trigger={
<Button <Button
size="icon" size="icon"
className="fixed bottom-6 right-6 h-14 w-14 rounded-full shadow-lg md:hidden z-50 hover:scale-105 transition-transform" className="fixed bottom-6 right-6 h-14 w-14 rounded-full shadow-lg lg:hidden z-50 hover:scale-105 transition-transform"
> >
<Plus className="h-6 w-6" /> <Plus className="h-6 w-6" />
</Button> </Button>