feat: password change flow improvement, design improvements, css cleanup, move to shadcn canary
This commit is contained in:
parent
916a4757aa
commit
8af9d140da
269
app/globals.css
269
app/globals.css
@ -1,71 +1,71 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
|
@import "tw-animate-css";
|
||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--color-border: hsl(var(--border));
|
--color-background: oklch(var(--background));
|
||||||
--color-input: hsl(var(--input));
|
--color-foreground: oklch(var(--foreground));
|
||||||
--color-ring: hsl(var(--ring));
|
--color-card: oklch(var(--card));
|
||||||
--color-background: hsl(var(--background));
|
--color-card-foreground: oklch(var(--card-foreground));
|
||||||
--color-foreground: hsl(var(--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));
|
/* Sidebar */
|
||||||
--color-primary-foreground: hsl(var(--primary-foreground));
|
--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));
|
/* Chart */
|
||||||
--color-secondary-foreground: hsl(var(--secondary-foreground));
|
--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));
|
/* Border radius */
|
||||||
--color-destructive-foreground: hsl(var(--destructive-foreground));
|
--radius: 0.625rem;
|
||||||
|
|
||||||
--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);
|
|
||||||
--radius-sm: calc(var(--radius) - 4px);
|
--radius-sm: calc(var(--radius) - 4px);
|
||||||
|
--radius-md: calc(var(--radius) - 2px);
|
||||||
|
--radius-lg: var(--radius);
|
||||||
|
--radius-xl: calc(var(--radius) + 4px);
|
||||||
|
|
||||||
--font-sans:
|
/* Typography */
|
||||||
var(--font-sans), ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji',
|
--font-sans: var(--font-sans), ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji',
|
||||||
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
|
|
||||||
|
/* Animations */
|
||||||
--animate-accordion-down: accordion-down 0.2s ease-out;
|
--animate-accordion-down: accordion-down 0.2s ease-out;
|
||||||
--animate-accordion-up: accordion-up 0.2s ease-out;
|
--animate-accordion-up: accordion-up 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes accordion-down {
|
/* Keyframes */
|
||||||
from {
|
@keyframes accordion-down {
|
||||||
height: 0;
|
from { height: 0; }
|
||||||
}
|
to { height: var(--radix-accordion-content-height); }
|
||||||
to {
|
}
|
||||||
height: var(--radix-accordion-content-height);
|
|
||||||
}
|
@keyframes accordion-up {
|
||||||
}
|
from { height: var(--radix-accordion-content-height); }
|
||||||
@keyframes accordion-up {
|
to { height: 0; }
|
||||||
from {
|
|
||||||
height: var(--radix-accordion-content-height);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@utility container {
|
@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 {
|
@layer base {
|
||||||
*,
|
*,
|
||||||
::after,
|
::after,
|
||||||
@ -95,103 +87,90 @@
|
|||||||
::file-selector-button {
|
::file-selector-button {
|
||||||
border-color: var(--color-gray-200, currentColor);
|
border-color: var(--color-gray-200, currentColor);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@layer base {
|
|
||||||
:root {
|
:root {
|
||||||
--background: 30 20% 98%;
|
--background: 1 0 0;
|
||||||
--foreground: 222.2 84% 4.9%;
|
--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;
|
||||||
|
|
||||||
--muted: 210 40% 96.1%;
|
/* Chart */
|
||||||
--muted-foreground: 215.4 16.3% 46.9%;
|
--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;
|
||||||
|
|
||||||
--popover: 0 0% 100%;
|
/* Sidebar */
|
||||||
--popover-foreground: 222.2 84% 4.9%;
|
--sidebar: 0.984 0.003 247.858;
|
||||||
|
--sidebar-foreground: 0.129 0.042 264.695;
|
||||||
--card: 0 0% 100%;
|
--sidebar-primary: 0.208 0.042 265.755;
|
||||||
--card-foreground: 222.2 84% 4.9%;
|
--sidebar-primary-foreground: 0.984 0.003 247.858;
|
||||||
|
--sidebar-accent: 0.968 0.007 247.896;
|
||||||
--border: 214.3 31.8% 91.4%;
|
--sidebar-accent-foreground: 0.208 0.042 265.755;
|
||||||
--input: 214.3 31.8% 91.4%;
|
--sidebar-border: 0.929 0.013 255.508;
|
||||||
|
--sidebar-ring: 0.704 0.04 256.788;
|
||||||
--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%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dark theme */
|
||||||
.dark {
|
.dark {
|
||||||
--background: 222.2 84% 4.9%;
|
--background: 0.129 0.042 264.695;
|
||||||
--foreground: 210 40% 98%;
|
--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;
|
||||||
|
|
||||||
--muted: 217.2 32.6% 17.5%;
|
/* Chart */
|
||||||
--muted-foreground: 215 20.2% 65.1%;
|
--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;
|
||||||
|
|
||||||
--popover: 222.2 84% 4.9%;
|
/* Sidebar */
|
||||||
--popover-foreground: 210 40% 98%;
|
--sidebar: 0.208 0.042 265.755;
|
||||||
|
--sidebar-foreground: 0.984 0.003 247.858;
|
||||||
--card: 222.2 84% 4.9%;
|
--sidebar-primary: 0.488 0.243 264.376;
|
||||||
--card-foreground: 210 40% 98%;
|
--sidebar-primary-foreground: 0.984 0.003 247.858;
|
||||||
|
--sidebar-accent: 0.279 0.041 260.031;
|
||||||
--border: 217.2 32.6% 17.5%;
|
--sidebar-accent-foreground: 0.984 0.003 247.858;
|
||||||
--input: 217.2 32.6% 17.5%;
|
--sidebar-border: 1 0 0 / 10%;
|
||||||
|
--sidebar-ring: 0.551 0.027 264.364;
|
||||||
--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%;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@layer base {
|
|
||||||
* {
|
* {
|
||||||
@apply border-border;
|
@apply border-border outline-ring/50;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"rsc": true,
|
"rsc": true,
|
||||||
"tsx": true,
|
"tsx": true,
|
||||||
"tailwind": {
|
"tailwind": {
|
||||||
"config": "tailwind.config.ts",
|
"config": "",
|
||||||
"css": "app/globals.css",
|
"css": "app/globals.css",
|
||||||
"baseColor": "slate",
|
"baseColor": "slate",
|
||||||
"cssVariables": true,
|
"cssVariables": true,
|
||||||
|
@ -5,12 +5,23 @@ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/com
|
|||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
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 { 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() {
|
export function ChangePassword() {
|
||||||
const [newPassword, setNewPassword] = useState("");
|
const [newPassword, setNewPassword] = useState("");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [message, setMessage] = useState<string | null>(null);
|
const [message, setMessage] = useState<string | null>(null);
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
const handlePasswordChange = async (e: React.FormEvent<HTMLFormElement>) => {
|
const handlePasswordChange = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -29,6 +40,11 @@ export function ChangePassword() {
|
|||||||
if (response.ok && resData.success) {
|
if (response.ok && resData.success) {
|
||||||
setMessage("Password Updated");
|
setMessage("Password Updated");
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
// Close dialog after change
|
||||||
|
setTimeout(() => {
|
||||||
|
setOpen(false);
|
||||||
|
setNewPassword("");
|
||||||
|
}, 1500);
|
||||||
} else if (resData.error) {
|
} else if (resData.error) {
|
||||||
setMessage(resData.error);
|
setMessage(resData.error);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@ -46,11 +62,36 @@ export function ChangePassword() {
|
|||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="flex items-center"><Mail size={15} className="mr-1" /> Change Email Password</CardTitle>
|
<CardTitle className="flex items-center text-2xl">
|
||||||
<CardDescription>Please note, this will <b>NOT</b> change your Authentik password.</CardDescription>
|
<User className="mr-1" />
|
||||||
{/* TODO: please tell me you added password resets to authentik by now */}
|
My Account
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription>LibreCloud makes it easy to manage your account</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
|
<h2 className="text-lg font-bold">Actions</h2>
|
||||||
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button className="mt-2">
|
||||||
|
<Key />
|
||||||
|
Change Password
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Change Your Password</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
<span className="font-bold mr-1">This only applies to your Authentik account.</span>
|
||||||
|
Make sure it's secure, and consider using
|
||||||
|
<Link
|
||||||
|
href="https://pass.librecloud.cc"
|
||||||
|
target="_blank"
|
||||||
|
className="ml-1 underline hover:text-primary transition-all"
|
||||||
|
>
|
||||||
|
LibreCloud Pass
|
||||||
|
</Link> to keep it safe.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
<form onSubmit={handlePasswordChange} className="space-y-4">
|
<form onSubmit={handlePasswordChange} className="space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="new-password">New Password</Label>
|
<Label htmlFor="new-password">New Password</Label>
|
||||||
@ -61,13 +102,23 @@ export function ChangePassword() {
|
|||||||
onChange={(e) => setNewPassword(e.target.value)}
|
onChange={(e) => setNewPassword(e.target.value)}
|
||||||
className="mt-1.5"
|
className="mt-1.5"
|
||||||
/>
|
/>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Password must be at least 8 characters long.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
{message && (
|
||||||
|
<p className={`text-sm text-center ${message.includes("Updated") ? "text-green-500" : "text-red-500"}`}>
|
||||||
|
{message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<DialogFooter>
|
||||||
<Button type="submit" disabled={loading || newPassword.length < 8}>
|
<Button type="submit" disabled={loading || newPassword.length < 8}>
|
||||||
{/* TODO: this should have the usual error message style */
|
{loading ? <><Loader2 className="animate-spin mr-2" /> Changing...</> : <><Key className="mr-2" /> Change Password</>}
|
||||||
loading ? <><Loader2 className="animate-spin" /> Changing...</> : <><Key /> Change Password</>}
|
|
||||||
</Button>
|
</Button>
|
||||||
{message && <p className="text-sm text-center">{message}</p>}
|
</DialogFooter>
|
||||||
</form>
|
</form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
@ -98,8 +98,9 @@ export function LinkGitea({ linked }: { linked: boolean }) {
|
|||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>
|
<CardTitle className="flex items-center text-2xl">
|
||||||
Link Gitea Account
|
<SiGitea className="mr-2" />
|
||||||
|
Gitea Link
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
To link your Gitea account to your LibreCloud account, add your p0ntus mail account to your Gitea account, then click the button.
|
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 (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Git Link</CardTitle>
|
<CardTitle className="flex items-center text-2xl">
|
||||||
|
<SiGitea className="mr-2" />
|
||||||
|
Gitea Link
|
||||||
|
</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Your Gitea account is currently linked to your LibreCloud account.
|
Your Gitea account is currently linked to your LibreCloud account.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
@ -178,7 +182,12 @@ export function LinkGitea({ linked }: { linked: boolean }) {
|
|||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
<p className="text-sm mb-4">
|
<p className="text-sm mb-4">
|
||||||
Unlinking your Gitea account will not delete your Gitea account. You can delete your Gitea account <Link href="https://try.gitea.com/user/sign_up" target="_blank" className="underline hover:text-muted-foreground">here</Link>.
|
Unlinking your Gitea account will not delete your Gitea account. You can delete your Gitea account
|
||||||
|
<Link
|
||||||
|
href="https://git.pontusmail.org/user/settings/account"
|
||||||
|
target="_blank"
|
||||||
|
className="underline hover:text-muted-foreground transition-all ml-1"
|
||||||
|
>here</Link>.
|
||||||
</p>
|
</p>
|
||||||
{unlinkLoading ? (
|
{unlinkLoading ? (
|
||||||
<Button variant="destructive" disabled>
|
<Button variant="destructive" disabled>
|
||||||
|
@ -3,7 +3,8 @@ import { Button } from "@/components/ui/button"
|
|||||||
import {
|
import {
|
||||||
Mail,
|
Mail,
|
||||||
Headset,
|
Headset,
|
||||||
Heart
|
Heart,
|
||||||
|
Scale
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ export const QuickLinks = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
|
target="_blank"
|
||||||
href="https://mail.librecloud.cc"
|
href="https://mail.librecloud.cc"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
@ -37,6 +39,7 @@ export const QuickLinks = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
|
target="_blank"
|
||||||
href={process.env.NEXT_PUBLIC_DONATE_URL || "https://donate.stripe.com/6oE8yxaPk6yXbpS145"}
|
href={process.env.NEXT_PUBLIC_DONATE_URL || "https://donate.stripe.com/6oE8yxaPk6yXbpS145"}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
@ -47,6 +50,18 @@ export const QuickLinks = () => {
|
|||||||
Donate
|
Donate
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link
|
||||||
|
target="_blank"
|
||||||
|
href="/legal"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
className="w-full mb-2 cursor-pointer"
|
||||||
|
>
|
||||||
|
<Scale />
|
||||||
|
Legal
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
"framer-motion": "^12.6.3",
|
"framer-motion": "^12.6.3",
|
||||||
"geist": "^1.3.1",
|
"geist": "^1.3.1",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"lucide-react": "^0.474.0",
|
"lucide-react": "^0.487.0",
|
||||||
"motion": "^12.6.3",
|
"motion": "^12.6.3",
|
||||||
"next": "^15.3.0",
|
"next": "^15.3.0",
|
||||||
"next-auth": "^5.0.0-beta.25",
|
"next-auth": "^5.0.0-beta.25",
|
||||||
@ -45,7 +45,8 @@
|
|||||||
"react-hook-form": "^7.55.0",
|
"react-hook-form": "^7.55.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-typed": "^2.0.12",
|
"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",
|
"validator": "^13.15.0",
|
||||||
"zod": "^3.24.2"
|
"zod": "^3.24.2"
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user