settings page responsive design fixes

This commit is contained in:
corgifist 2025-07-28 18:27:23 +03:00
parent fb5cf87b43
commit 2304b7223f
8 changed files with 71 additions and 51 deletions

View File

@ -2,6 +2,7 @@
@import "tw-animate-css"; @import "tw-animate-css";
@import "tailwindcss-safe-area"; @import "tailwindcss-safe-area";
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@custom-variant adjust (&:where([data-adjust="true"] *));
@theme inline { @theme inline {
--color-background: var(--background); --color-background: var(--background);

View File

@ -34,6 +34,7 @@ import StaticSidebarTrigger from "@/components/static-sidebar-trigger";
import SidebarTriggerAdjustable from "@/components/sidebar-trigger-adjustable"; import SidebarTriggerAdjustable from "@/components/sidebar-trigger-adjustable";
import ScrollFadingTitle from "@/components/scroll-fading-title"; import ScrollFadingTitle from "@/components/scroll-fading-title";
import { fa } from "zod/v4/locales"; import { fa } from "zod/v4/locales";
import AscendingCard from "@/components/ascending-card";
type SortingType = "byCreationDate" type SortingType = "byCreationDate"
| "byEditDate" | "byEditDate"
@ -412,7 +413,7 @@ const ProjectContainer = ({
return ( return (
<AspectRatio data-selectable="true" ratio={16 / 9} onClick={handleCheck}> <AspectRatio data-selectable="true" ratio={16 / 9} onClick={handleCheck}>
<Card className="relative rounded-lg shadow-md w-full h-full overflow-hidden hover:scale-[101%] hover:drop-shadow-xl duration-100" data-selectable="true"> <AscendingCard className="relative rounded-lg w-full h-full overflow-hidden" data-selectable="true">
<div className="absolute bottom-0 left-0 w-full h-full bg-gradient-to-t from-white dark:from-black to-transparent opacity-50" data-selectable="true" /> <div className="absolute bottom-0 left-0 w-full h-full bg-gradient-to-t from-white dark:from-black to-transparent opacity-50" data-selectable="true" />
<div className="absolute bottom-0 left-0 p-2 w-full flex flex-row justify-between items-center" data-selectable="true"> <div className="absolute bottom-0 left-0 p-2 w-full flex flex-row justify-between items-center" data-selectable="true">
<div data-selectable="true"> <div data-selectable="true">
@ -430,7 +431,7 @@ const ProjectContainer = ({
<Checkbox checked={selectedProjects.includes(project.uuid)} onCheckedChange={(_) => handleCheck} /> <Checkbox checked={selectedProjects.includes(project.uuid)} onCheckedChange={(_) => handleCheck} />
</div> </div>
)} )}
</Card> </AscendingCard>
</AspectRatio> </AspectRatio>
) )
}; };

View File

@ -3,7 +3,7 @@ import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { SidebarTrigger } from "@/components/ui/sidebar"; import { SidebarTrigger } from "@/components/ui/sidebar";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { ChartPieIcon, InfoIcon } from "lucide-react"; import { ChartPieIcon, ChevronRightIcon, InfoIcon } from "lucide-react";
import { ReactNode, useEffect, useState } from "react"; import { ReactNode, useEffect, useState } from "react";
import { usePersistenceContext } from "../persistence-provider"; import { usePersistenceContext } from "../persistence-provider";
import StaticSidebarTrigger from "@/components/static-sidebar-trigger"; import StaticSidebarTrigger from "@/components/static-sidebar-trigger";
@ -14,12 +14,12 @@ import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import AscendingCard from "@/components/ascending-card"; import AscendingCard from "@/components/ascending-card";
import Link from "next/link"; import Link from "next/link";
import WideAscendingCard from "@/components/wide-container";
import WideContainer from "@/components/wide-container";
export default function Settings(): ReactNode { export default function Settings(): ReactNode {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const cardWidth = isMobile ? "w-full" : "w-2xl";
return ( return (
<div className="p-5 w-full h-full"> <div className="p-5 w-full h-full">
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2">
@ -29,13 +29,17 @@ export default function Settings(): ReactNode {
</ScrollFadingTitle> </ScrollFadingTitle>
</div> </div>
<div className="flex flex-col sticky top-safe bg-background gap-2 mt-2 pb-2 pt-2 p-5 w-[100% + 5 * var(--spacing)] z-10 -mx-5"> <div className="flex flex-col sticky top-safe bg-background gap-2 mt-2 pb-2 pt-2 p-5 w-[100% + 5 * var(--spacing)] z-10 -mx-5">
<SidebarTriggerAdjustable className={cn("flex justify-center",)}> <SidebarTriggerAdjustable adjustWidth={!isMobile ? 0 : 12} className="flex items-center justify-center">
<Search placeholder="Search Settings" className={cardWidth} /> <WideContainer>
<Search />
</WideContainer>
</SidebarTriggerAdjustable> </SidebarTriggerAdjustable>
</div> </div>
<div className="flex flex-col justify-center items-center w-full gap-1 md:lg:gap-2 mt-2"> <div className="flex flex-col items-center gap-1 md:lg:gap-2 mt-2 h-screen">
<Link href="/settings/storage" className="w-full flex items-center justify-center"> <WideContainer>
<AscendingCard className={`flex flex-row gap-3 p-3 ${cardWidth}`}> <Link href="/settings/storage">
<AscendingCard className="flex flex-row justify-between items-center gap-2 p-4">
<div className="flex flex-row justify-between items-center gap-3">
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<ChartPieIcon /> <ChartPieIcon />
</div> </div>
@ -43,8 +47,11 @@ export default function Settings(): ReactNode {
<h3 className="font-semibold break-keep text-lg sm:text-xl">Storage</h3> <h3 className="font-semibold break-keep text-lg sm:text-xl">Storage</h3>
<p className="text-sm text-secondary-foreground">Memory usage, media, cache etc.</p> <p className="text-sm text-secondary-foreground">Memory usage, media, cache etc.</p>
</div> </div>
</div>
<ChevronRightIcon />
</AscendingCard> </AscendingCard>
</Link> </Link>
</WideContainer>
</div> </div>
</div> </div>
); );

View File

@ -1,11 +1,13 @@
"use client"; "use client";
import { usePersistenceContext } from "@/app/persistence-provider"; import { usePersistenceContext } from "@/app/persistence-provider";
import AscendingCard from "@/components/ascending-card";
import ScrollFadingTitle from "@/components/scroll-fading-title"; import ScrollFadingTitle from "@/components/scroll-fading-title";
import Search from "@/components/search"; import Search from "@/components/search";
import SidebarTriggerAdjustable from "@/components/sidebar-trigger-adjustable"; import SidebarTriggerAdjustable from "@/components/sidebar-trigger-adjustable";
import StaticSidebarTrigger from "@/components/static-sidebar-trigger"; import StaticSidebarTrigger from "@/components/static-sidebar-trigger";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import WideContainer from "@/components/wide-container";
import { useIsMobile } from "@/hooks/use-mobile"; import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { ArrowLeftIcon } from "lucide-react"; import { ArrowLeftIcon } from "lucide-react";
@ -33,8 +35,6 @@ export default function Storage() {
setStatus(localStorage.getItem("persistence-status")); setStatus(localStorage.getItem("persistence-status"));
}, []); }, []);
const cardWidth = isMobile ? "w-full" : "w-2xl";
return ( return (
<div className="p-5 w-full"> <div className="p-5 w-full">
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2">
@ -49,15 +49,21 @@ export default function Storage() {
</ScrollFadingTitle> </ScrollFadingTitle>
</div> </div>
<div className="flex flex-col sticky top-safe bg-background gap-2 mt-2 pb-2 pt-2 p-5 w-[100% + 5 * var(--spacing)] z-10 -mx-5"> <div className="flex flex-col sticky top-safe bg-background gap-2 mt-2 pb-2 pt-2 p-5 w-[100% + 5 * var(--spacing)] z-10 -mx-5">
<SidebarTriggerAdjustable adjustWidth="20" className={cn("flex justify-center", cardWidth)}> <SidebarTriggerAdjustable adjustWidth={!isMobile ? 0 : 12} className="flex items-center justify-center">
<Search placeholder="Search Settings" className={cardWidth} /> <WideContainer>
<Search />
</WideContainer>
</SidebarTriggerAdjustable> </SidebarTriggerAdjustable>
</div> </div>
<div className="flex flex-row justify-between items-center w-full max-w-96"> <div className="flex flex-col items-center justify-start gap-1 md:lg:gap-2 mt-2 h-screen">
<div className="flex flex-row gap-2 items-center"> <WideContainer>
<AscendingCard className="flex flex-row justify-between items-center p-4">
<div className="flex flex-row gap-2 ">
<Label>Persistent Storage</Label> <Label>Persistent Storage</Label>
</div> </div>
<PersistentStorageControl status={status} /> <PersistentStorageControl status={status} />
</AscendingCard>
</WideContainer>
</div> </div>
</div> </div>
) )

View File

@ -7,6 +7,7 @@ import { cn } from "@/lib/utils";
export const Search = (props: ComponentProps<typeof Input>): ReactNode => ( export const Search = (props: ComponentProps<typeof Input>): ReactNode => (
<div className={cn("relative", props.className)}> <div className={cn("relative", props.className)}>
<Input <Input
placeholder="Search"
{...props} {...props}
type="text" type="text"
className="peer block w-full rounded-md border py-[9px] pl-10" className="peer block w-full rounded-md border py-[9px] pl-10"

View File

@ -1,7 +1,5 @@
"use client"; "use client";
import { useIsMobile } from "@/hooks/use-mobile"; import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils";
import { sign } from "crypto";
import { ComponentProps, useEffect, useState } from "react"; import { ComponentProps, useEffect, useState } from "react";
const easeSlide = (x: number) => ( const easeSlide = (x: number) => (
@ -11,33 +9,20 @@ const easeSlide = (x: number) => (
const lerp = (a: number, b: number, t: number) => ( const lerp = (a: number, b: number, t: number) => (
a * t + b * (1 - t) a * t + b * (1 - t)
); );
const cssLerp = (a: string, b: string, t: string) => (
`${a} * ${t} + ${b} * (1 - ${t})`
);
export const SidebarTriggerAdjustable = (props: ComponentProps<"div"> & { export const SidebarTriggerAdjustable = (props: ComponentProps<"div"> & {
adjustWidth?: number | `${number}`; adjustWidth?: number | `${number}`
}) => { }) => {
const adjustWidth = props.adjustWidth ? +props.adjustWidth : 12; const adjustWidth = props.adjustWidth === undefined ? 12 : +props.adjustWidth;
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const [slideAmount, setSlideAmount] = useState(0);
useEffect(() => { useEffect(() => {
const triggerElement = document.querySelector('div[data-sidebar-trigger="true"]'); const handleScroll = () =>
setSlideAmount(easeSlide(
const handleScroll = () => {
if (!triggerElement) {
console.log("triggerElement is null");
return;
}
const triggerDiv = triggerElement as HTMLDivElement;
const slideAmount = easeSlide(
Math.max(0, Math.min(1, window.scrollY / (window.innerHeight / 20))) Math.max(0, Math.min(1, window.scrollY / (window.innerHeight / 20)))
); ));
triggerDiv.style.transform = `translateX(calc(var(--spacing) * ${adjustWidth * slideAmount}))`;
triggerDiv.style.paddingTop = `calc(var(--spacing) * ${(isMobile ? 1 : 3) * slideAmount})`;
triggerDiv.style.width = `calc(100% - var(--spacing) * ${lerp(0, adjustWidth, 1 - slideAmount)})`;
};
handleScroll(); handleScroll();
window.addEventListener('scroll', handleScroll, { passive: true }); window.addEventListener('scroll', handleScroll, { passive: true });
@ -47,5 +32,9 @@ export const SidebarTriggerAdjustable = (props: ComponentProps<"div"> & {
}; };
}, [isMobile]); }, [isMobile]);
return <div data-sidebar-trigger="true" className={props.className}>{props.children}</div>; return <div style={{
transform: `translateX(calc(var(--spacing) * ${adjustWidth * slideAmount}))`,
marginTop: `calc(var(--spacing) * ${(isMobile ? 1 : 3) * slideAmount})`,
width: `calc(100% - var(--spacing) * ${lerp(0, adjustWidth, 1 - slideAmount)})`
}} className={props.className}>{props.children}</div>;
} }

View File

@ -0,0 +1,12 @@
import { ComponentProps } from "react";
import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils";
export const WideContainer = (props: ComponentProps<"div">) => {
const isMobile = useIsMobile();
const cardWidth = "max-w-2xl w-full md:w-85 lg:w-130 xl:w-2xl";
return (
<div {...props} className={cn(`${isMobile ? "w-full" : cardWidth}`, props.className)}/>
);
};

View File

@ -0,0 +1,3 @@
import { WideContainer } from "./WideContainer";
export default WideContainer;