mirror of
https://github.com/ClipFusion-org/clipfusion.git
synced 2025-08-03 16:55:08 +00:00
settings page responsive design fixes
This commit is contained in:
parent
fb5cf87b43
commit
2304b7223f
@ -2,6 +2,7 @@
|
||||
@import "tw-animate-css";
|
||||
@import "tailwindcss-safe-area";
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
@custom-variant adjust (&:where([data-adjust="true"] *));
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
|
@ -34,6 +34,7 @@ import StaticSidebarTrigger from "@/components/static-sidebar-trigger";
|
||||
import SidebarTriggerAdjustable from "@/components/sidebar-trigger-adjustable";
|
||||
import ScrollFadingTitle from "@/components/scroll-fading-title";
|
||||
import { fa } from "zod/v4/locales";
|
||||
import AscendingCard from "@/components/ascending-card";
|
||||
|
||||
type SortingType = "byCreationDate"
|
||||
| "byEditDate"
|
||||
@ -412,7 +413,7 @@ const ProjectContainer = ({
|
||||
|
||||
return (
|
||||
<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 p-2 w-full flex flex-row justify-between items-center" data-selectable="true">
|
||||
<div data-selectable="true">
|
||||
@ -430,7 +431,7 @@ const ProjectContainer = ({
|
||||
<Checkbox checked={selectedProjects.includes(project.uuid)} onCheckedChange={(_) => handleCheck} />
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</AscendingCard>
|
||||
</AspectRatio>
|
||||
)
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { SidebarTrigger } from "@/components/ui/sidebar";
|
||||
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 { usePersistenceContext } from "../persistence-provider";
|
||||
import StaticSidebarTrigger from "@/components/static-sidebar-trigger";
|
||||
@ -14,12 +14,12 @@ import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { cn } from "@/lib/utils";
|
||||
import AscendingCard from "@/components/ascending-card";
|
||||
import Link from "next/link";
|
||||
import WideAscendingCard from "@/components/wide-container";
|
||||
import WideContainer from "@/components/wide-container";
|
||||
|
||||
export default function Settings(): ReactNode {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const cardWidth = isMobile ? "w-full" : "w-2xl";
|
||||
|
||||
return (
|
||||
<div className="p-5 w-full h-full">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
@ -29,22 +29,29 @@ export default function Settings(): ReactNode {
|
||||
</ScrollFadingTitle>
|
||||
</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">
|
||||
<SidebarTriggerAdjustable className={cn("flex justify-center",)}>
|
||||
<Search placeholder="Search Settings" className={cardWidth} />
|
||||
<SidebarTriggerAdjustable adjustWidth={!isMobile ? 0 : 12} className="flex items-center justify-center">
|
||||
<WideContainer>
|
||||
<Search />
|
||||
</WideContainer>
|
||||
</SidebarTriggerAdjustable>
|
||||
</div>
|
||||
<div className="flex flex-col justify-center items-center w-full gap-1 md:lg:gap-2 mt-2">
|
||||
<Link href="/settings/storage" className="w-full flex items-center justify-center">
|
||||
<AscendingCard className={`flex flex-row gap-3 p-3 ${cardWidth}`}>
|
||||
<div className="flex items-center justify-center">
|
||||
<ChartPieIcon />
|
||||
</div>
|
||||
<div className="flex flex-col items-start">
|
||||
<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>
|
||||
</div>
|
||||
</AscendingCard>
|
||||
</Link>
|
||||
<div className="flex flex-col items-center gap-1 md:lg:gap-2 mt-2 h-screen">
|
||||
<WideContainer>
|
||||
<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">
|
||||
<ChartPieIcon />
|
||||
</div>
|
||||
<div className="flex flex-col items-start">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRightIcon />
|
||||
</AscendingCard>
|
||||
</Link>
|
||||
</WideContainer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,11 +1,13 @@
|
||||
"use client";
|
||||
import { usePersistenceContext } from "@/app/persistence-provider";
|
||||
import AscendingCard from "@/components/ascending-card";
|
||||
import ScrollFadingTitle from "@/components/scroll-fading-title";
|
||||
import Search from "@/components/search";
|
||||
import SidebarTriggerAdjustable from "@/components/sidebar-trigger-adjustable";
|
||||
import StaticSidebarTrigger from "@/components/static-sidebar-trigger";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import WideContainer from "@/components/wide-container";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ArrowLeftIcon } from "lucide-react";
|
||||
@ -33,8 +35,6 @@ export default function Storage() {
|
||||
setStatus(localStorage.getItem("persistence-status"));
|
||||
}, []);
|
||||
|
||||
const cardWidth = isMobile ? "w-full" : "w-2xl";
|
||||
|
||||
return (
|
||||
<div className="p-5 w-full">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
@ -49,15 +49,21 @@ export default function Storage() {
|
||||
</ScrollFadingTitle>
|
||||
</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">
|
||||
<SidebarTriggerAdjustable adjustWidth="20" className={cn("flex justify-center", cardWidth)}>
|
||||
<Search placeholder="Search Settings" className={cardWidth} />
|
||||
<SidebarTriggerAdjustable adjustWidth={!isMobile ? 0 : 12} className="flex items-center justify-center">
|
||||
<WideContainer>
|
||||
<Search />
|
||||
</WideContainer>
|
||||
</SidebarTriggerAdjustable>
|
||||
</div>
|
||||
<div className="flex flex-row justify-between items-center w-full max-w-96">
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<Label>Persistent Storage</Label>
|
||||
</div>
|
||||
<PersistentStorageControl status={status} />
|
||||
<div className="flex flex-col items-center justify-start gap-1 md:lg:gap-2 mt-2 h-screen">
|
||||
<WideContainer>
|
||||
<AscendingCard className="flex flex-row justify-between items-center p-4">
|
||||
<div className="flex flex-row gap-2 ">
|
||||
<Label>Persistent Storage</Label>
|
||||
</div>
|
||||
<PersistentStorageControl status={status} />
|
||||
</AscendingCard>
|
||||
</WideContainer>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -7,6 +7,7 @@ import { cn } from "@/lib/utils";
|
||||
export const Search = (props: ComponentProps<typeof Input>): ReactNode => (
|
||||
<div className={cn("relative", props.className)}>
|
||||
<Input
|
||||
placeholder="Search"
|
||||
{...props}
|
||||
type="text"
|
||||
className="peer block w-full rounded-md border py-[9px] pl-10"
|
||||
|
@ -1,7 +1,5 @@
|
||||
"use client";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { sign } from "crypto";
|
||||
import { ComponentProps, useEffect, useState } from "react";
|
||||
|
||||
const easeSlide = (x: number) => (
|
||||
@ -11,41 +9,32 @@ const easeSlide = (x: number) => (
|
||||
const lerp = (a: number, b: number, t: number) => (
|
||||
a * t + b * (1 - t)
|
||||
);
|
||||
const cssLerp = (a: string, b: string, t: string) => (
|
||||
`${a} * ${t} + ${b} * (1 - ${t})`
|
||||
);
|
||||
|
||||
|
||||
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 [slideAmount, setSlideAmount] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const triggerElement = document.querySelector('div[data-sidebar-trigger="true"]');
|
||||
|
||||
const handleScroll = () => {
|
||||
if (!triggerElement) {
|
||||
console.log("triggerElement is null");
|
||||
return;
|
||||
}
|
||||
const triggerDiv = triggerElement as HTMLDivElement;
|
||||
const slideAmount = easeSlide(
|
||||
const handleScroll = () =>
|
||||
setSlideAmount(easeSlide(
|
||||
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();
|
||||
window.addEventListener('scroll', handleScroll, {passive: true});
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}, [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>;
|
||||
}
|
12
src/components/wide-container/WideContainer.tsx
Normal file
12
src/components/wide-container/WideContainer.tsx
Normal 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)}/>
|
||||
);
|
||||
};
|
3
src/components/wide-container/index.ts
Normal file
3
src/components/wide-container/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { WideContainer } from "./WideContainer";
|
||||
|
||||
export default WideContainer;
|
Loading…
Reference in New Issue
Block a user