From 8af9d140dab32faff1a65aa96fdc76588f507650 Mon Sep 17 00:00:00 2001 From: Aidan Date: Thu, 10 Apr 2025 21:15:38 -0400 Subject: [PATCH] feat: password change flow improvement, design improvements, css cleanup, move to shadcn canary --- app/globals.css | 277 ++++++++---------- components.json | 2 +- .../dashboard/Settings/ChangePassword.tsx | 93 ++++-- components/cards/dashboard/git/LinkGitea.tsx | 17 +- .../cards/dashboard/overview/QuickLinks.tsx | 17 +- package.json | 5 +- 6 files changed, 233 insertions(+), 178 deletions(-) diff --git a/app/globals.css b/app/globals.css index c407292..3bcb11f 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,71 +1,71 @@ @import 'tailwindcss'; +@import "tw-animate-css"; @custom-variant dark (&:is(.dark *)); @theme { - --color-border: hsl(var(--border)); - --color-input: hsl(var(--input)); - --color-ring: hsl(var(--ring)); - --color-background: hsl(var(--background)); - --color-foreground: hsl(var(--foreground)); + --color-background: oklch(var(--background)); + --color-foreground: oklch(var(--foreground)); + --color-card: oklch(var(--card)); + --color-card-foreground: oklch(var(--card-foreground)); + --color-popover: oklch(var(--popover)); + --color-popover-foreground: oklch(var(--popover-foreground)); + --color-primary: oklch(var(--primary)); + --color-primary-foreground: oklch(var(--primary-foreground)); + --color-secondary: oklch(var(--secondary)); + --color-secondary-foreground: oklch(var(--secondary-foreground)); + --color-muted: oklch(var(--muted)); + --color-muted-foreground: oklch(var(--muted-foreground)); + --color-accent: oklch(var(--accent)); + --color-accent-foreground: oklch(var(--accent-foreground)); + --color-destructive: oklch(var(--destructive)); + --color-destructive-foreground: oklch(var(--destructive-foreground)); + --color-border: oklch(var(--border)); + --color-input: oklch(var(--input)); + --color-ring: oklch(var(--ring)); - --color-primary: hsl(var(--primary)); - --color-primary-foreground: hsl(var(--primary-foreground)); + /* Sidebar */ + --color-sidebar: oklch(var(--sidebar)); + --color-sidebar-foreground: oklch(var(--sidebar-foreground)); + --color-sidebar-primary: oklch(var(--sidebar-primary)); + --color-sidebar-primary-foreground: oklch(var(--sidebar-primary-foreground)); + --color-sidebar-accent: oklch(var(--sidebar-accent)); + --color-sidebar-accent-foreground: oklch(var(--sidebar-accent-foreground)); + --color-sidebar-border: oklch(var(--sidebar-border)); + --color-sidebar-ring: oklch(var(--sidebar-ring)); - --color-secondary: hsl(var(--secondary)); - --color-secondary-foreground: hsl(var(--secondary-foreground)); + /* Chart */ + --color-chart-1: oklch(var(--chart-1)); + --color-chart-2: oklch(var(--chart-2)); + --color-chart-3: oklch(var(--chart-3)); + --color-chart-4: oklch(var(--chart-4)); + --color-chart-5: oklch(var(--chart-5)); - --color-destructive: hsl(var(--destructive)); - --color-destructive-foreground: hsl(var(--destructive-foreground)); - - --color-muted: hsl(var(--muted)); - --color-muted-foreground: hsl(var(--muted-foreground)); - - --color-accent: hsl(var(--accent)); - --color-accent-foreground: hsl(var(--accent-foreground)); - - --color-popover: hsl(var(--popover)); - --color-popover-foreground: hsl(var(--popover-foreground)); - - --color-card: hsl(var(--card)); - --color-card-foreground: hsl(var(--card-foreground)); - - --color-sidebar: hsl(var(--sidebar-background)); - --color-sidebar-foreground: hsl(var(--sidebar-foreground)); - --color-sidebar-primary: hsl(var(--sidebar-primary)); - --color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground)); - --color-sidebar-accent: hsl(var(--sidebar-accent)); - --color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground)); - --color-sidebar-border: hsl(var(--sidebar-border)); - --color-sidebar-ring: hsl(var(--sidebar-ring)); - - --radius-lg: var(--radius); - --radius-md: calc(var(--radius) - 2px); + /* Border radius */ + --radius: 0.625rem; --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); - --font-sans: - var(--font-sans), ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', + /* Typography */ + --font-sans: var(--font-sans), ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + /* Animations */ --animate-accordion-down: accordion-down 0.2s ease-out; --animate-accordion-up: accordion-up 0.2s ease-out; +} - @keyframes accordion-down { - from { - height: 0; - } - to { - height: var(--radix-accordion-content-height); - } - } - @keyframes accordion-up { - from { - height: var(--radix-accordion-content-height); - } - to { - height: 0; - } - } +/* Keyframes */ +@keyframes accordion-down { + from { height: 0; } + to { height: var(--radix-accordion-content-height); } +} + +@keyframes accordion-up { + from { height: var(--radix-accordion-content-height); } + to { height: 0; } } @utility container { @@ -79,14 +79,6 @@ } } -/* - The default border color has changed to `currentColor` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. - - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. -*/ @layer base { *, ::after, @@ -95,103 +87,90 @@ ::file-selector-button { border-color: var(--color-gray-200, currentColor); } -} -@layer base { :root { - --background: 30 20% 98%; - --foreground: 222.2 84% 4.9%; - - --muted: 210 40% 96.1%; - --muted-foreground: 215.4 16.3% 46.9%; - - --popover: 0 0% 100%; - --popover-foreground: 222.2 84% 4.9%; - - --card: 0 0% 100%; - --card-foreground: 222.2 84% 4.9%; - - --border: 214.3 31.8% 91.4%; - --input: 214.3 31.8% 91.4%; - - --primary: 222.2 47.4% 11.2%; - --primary-foreground: 210 40% 98%; - - --secondary: 210 40% 96.1%; - --secondary-foreground: 222.2 47.4% 11.2%; - - --accent: 210 60% 95%; - --accent-foreground: 222.2 47.4% 11.2%; - - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 210 40% 98%; - - --ring: 215 20.2% 65.1%; - - --radius: 0.5rem; - - --sidebar-background: 215 25% 97%; - --sidebar-foreground: 240 5.3% 26.1%; - --sidebar-primary: 240 5.9% 10%; - --sidebar-primary-foreground: 0 0% 98%; - --sidebar-accent: 215 10% 92%; - --sidebar-accent-foreground: 240 5.9% 10%; - --sidebar-border: 220 13% 88%; - --sidebar-ring: 217.2 91.2% 59.8%; + --background: 1 0 0; + --foreground: 0.129 0.042 264.695; + --card: 1 0 0; + --card-foreground: 0.129 0.042 264.695; + --popover: 1 0 0; + --popover-foreground: 0.129 0.042 264.695; + --primary: 0.208 0.042 265.755; + --primary-foreground: 0.984 0.003 247.858; + --secondary: 0.968 0.007 247.896; + --secondary-foreground: 0.208 0.042 265.755; + --muted: 0.968 0.007 247.896; + --muted-foreground: 0.554 0.046 257.417; + --accent: 0.968 0.007 247.896; + --accent-foreground: 0.208 0.042 265.755; + --destructive: 0.577 0.245 27.325; + --destructive-foreground: 0.984 0.003 247.858; + --border: 0.929 0.013 255.508; + --input: 0.929 0.013 255.508; + --ring: 0.704 0.04 256.788; + + /* Chart */ + --chart-1: 0.646 0.222 41.116; + --chart-2: 0.6 0.118 184.704; + --chart-3: 0.398 0.07 227.392; + --chart-4: 0.828 0.189 84.429; + --chart-5: 0.769 0.188 70.08; + + /* Sidebar */ + --sidebar: 0.984 0.003 247.858; + --sidebar-foreground: 0.129 0.042 264.695; + --sidebar-primary: 0.208 0.042 265.755; + --sidebar-primary-foreground: 0.984 0.003 247.858; + --sidebar-accent: 0.968 0.007 247.896; + --sidebar-accent-foreground: 0.208 0.042 265.755; + --sidebar-border: 0.929 0.013 255.508; + --sidebar-ring: 0.704 0.04 256.788; } + /* Dark theme */ .dark { - --background: 222.2 84% 4.9%; - --foreground: 210 40% 98%; - - --muted: 217.2 32.6% 17.5%; - --muted-foreground: 215 20.2% 65.1%; - - --popover: 222.2 84% 4.9%; - --popover-foreground: 210 40% 98%; - - --card: 222.2 84% 4.9%; - --card-foreground: 210 40% 98%; - - --border: 217.2 32.6% 17.5%; - --input: 217.2 32.6% 17.5%; - - --primary: 210 40% 98%; - --primary-foreground: 222.2 47.4% 11.2%; - - --secondary: 217.2 32.6% 17.5%; - --secondary-foreground: 210 40% 98%; - - --accent: 217.2 32.6% 17.5%; - --accent-foreground: 210 40% 98%; - - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 0 85.7% 97.3%; - - --ring: 217.2 32.6% 17.5%; - - --sidebar-background: 240 5.9% 10%; - - --sidebar-foreground: 240 4.8% 95.9%; - - --sidebar-primary: 224.3 76.3% 48%; - - --sidebar-primary-foreground: 0 0% 100%; - - --sidebar-accent: 240 3.7% 15.9%; - - --sidebar-accent-foreground: 240 4.8% 95.9%; - - --sidebar-border: 240 3.7% 15.9%; - - --sidebar-ring: 217.2 91.2% 59.8%; + --background: 0.129 0.042 264.695; + --foreground: 0.984 0.003 247.858; + --card: 0.208 0.042 265.755; + --card-foreground: 0.984 0.003 247.858; + --popover: 0.208 0.042 265.755; + --popover-foreground: 0.984 0.003 247.858; + --primary: 0.929 0.013 255.508; + --primary-foreground: 0.208 0.042 265.755; + --secondary: 0.279 0.041 260.031; + --secondary-foreground: 0.984 0.003 247.858; + --muted: 0.279 0.041 260.031; + --muted-foreground: 0.704 0.04 256.788; + --accent: 0.279 0.041 260.031; + --accent-foreground: 0.984 0.003 247.858; + --destructive: 0.704 0.191 22.216; + --destructive-foreground: 0.984 0.003 247.858; + --border: 1 0 0 / 10%; + --input: 1 0 0 / 15%; + --ring: 0.551 0.027 264.364; + + /* Chart */ + --chart-1: 0.488 0.243 264.376; + --chart-2: 0.696 0.17 162.48; + --chart-3: 0.769 0.188 70.08; + --chart-4: 0.627 0.265 303.9; + --chart-5: 0.645 0.246 16.439; + + /* Sidebar */ + --sidebar: 0.208 0.042 265.755; + --sidebar-foreground: 0.984 0.003 247.858; + --sidebar-primary: 0.488 0.243 264.376; + --sidebar-primary-foreground: 0.984 0.003 247.858; + --sidebar-accent: 0.279 0.041 260.031; + --sidebar-accent-foreground: 0.984 0.003 247.858; + --sidebar-border: 1 0 0 / 10%; + --sidebar-ring: 0.551 0.027 264.364; } -} -@layer base { * { - @apply border-border; + @apply border-border outline-ring/50; } + body { @apply bg-background text-foreground; } diff --git a/components.json b/components.json index 4a7d1f5..a08feaa 100644 --- a/components.json +++ b/components.json @@ -4,7 +4,7 @@ "rsc": true, "tsx": true, "tailwind": { - "config": "tailwind.config.ts", + "config": "", "css": "app/globals.css", "baseColor": "slate", "cssVariables": true, diff --git a/components/cards/dashboard/Settings/ChangePassword.tsx b/components/cards/dashboard/Settings/ChangePassword.tsx index 5e0de7c..80c5dd1 100644 --- a/components/cards/dashboard/Settings/ChangePassword.tsx +++ b/components/cards/dashboard/Settings/ChangePassword.tsx @@ -5,12 +5,23 @@ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/com import { Input } from "@/components/ui/input" import { Button } from "@/components/ui/button" import { Label } from "@/components/ui/label" -import { Mail, Key, Loader2 } from "lucide-react" +import { Key, Loader2, User } from "lucide-react" +import Link from "next/link" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger +} from "@/components/ui/dialog" export function ChangePassword() { const [newPassword, setNewPassword] = useState(""); const [loading, setLoading] = useState(false); const [message, setMessage] = useState(null); + const [open, setOpen] = useState(false); const handlePasswordChange = async (e: React.FormEvent) => { e.preventDefault(); @@ -29,6 +40,11 @@ export function ChangePassword() { if (response.ok && resData.success) { setMessage("Password Updated"); setLoading(false); + // Close dialog after change + setTimeout(() => { + setOpen(false); + setNewPassword(""); + }, 1500); } else if (resData.error) { setMessage(resData.error); setLoading(false); @@ -46,28 +62,63 @@ export function ChangePassword() { return ( - Change Email Password - Please note, this will NOT change your Authentik password. - {/* TODO: please tell me you added password resets to authentik by now */} + + + My Account + + LibreCloud makes it easy to manage your account -
-
- - setNewPassword(e.target.value)} - className="mt-1.5" - /> -
- - {message &&

{message}

} -
+

Actions

+ + + + + + + Change Your Password + + This only applies to your Authentik account. + Make sure it's secure, and consider using + + LibreCloud Pass + to keep it safe. + + +
+
+ + setNewPassword(e.target.value)} + className="mt-1.5" + /> +

+ Password must be at least 8 characters long. +

+
+ {message && ( +

+ {message} +

+ )} + + + +
+
+
); diff --git a/components/cards/dashboard/git/LinkGitea.tsx b/components/cards/dashboard/git/LinkGitea.tsx index 3ecdd20..fff7c05 100644 --- a/components/cards/dashboard/git/LinkGitea.tsx +++ b/components/cards/dashboard/git/LinkGitea.tsx @@ -98,8 +98,9 @@ export function LinkGitea({ linked }: { linked: boolean }) { return ( - - Link Gitea Account + + + Gitea Link To link your Gitea account to your LibreCloud account, add your p0ntus mail account to your Gitea account, then click the button. @@ -164,7 +165,10 @@ export function LinkGitea({ linked }: { linked: boolean }) { return ( - Git Link + + + Gitea Link + Your Gitea account is currently linked to your LibreCloud account. @@ -178,7 +182,12 @@ export function LinkGitea({ linked }: { linked: boolean }) { )}

- Unlinking your Gitea account will not delete your Gitea account. You can delete your Gitea account here. + Unlinking your Gitea account will not delete your Gitea account. You can delete your Gitea account + here.

{unlinkLoading ? ( + + +
); diff --git a/package.json b/package.json index 7282854..d126579 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "framer-motion": "^12.6.3", "geist": "^1.3.1", "js-cookie": "^3.0.5", - "lucide-react": "^0.474.0", + "lucide-react": "^0.487.0", "motion": "^12.6.3", "next": "^15.3.0", "next-auth": "^5.0.0-beta.25", @@ -45,7 +45,8 @@ "react-hook-form": "^7.55.0", "react-icons": "^5.5.0", "react-typed": "^2.0.12", - "tailwind-merge": "^2.6.0", + "tailwind-merge": "^3.2.0", + "tw-animate-css": "^1.2.5", "validator": "^13.15.0", "zod": "^3.24.2" },