feat: add login button animation, add donation env var+button, ui tweaks, session checking in account links card

This commit is contained in:
Aidan 2025-04-09 01:11:28 -04:00
parent 4c1a20407e
commit 152f96f0af
9 changed files with 111 additions and 47 deletions

View File

@ -2,9 +2,10 @@ import Link from "next/link"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from "@/components/ui/card" import { Card, CardContent, CardHeader, CardTitle, CardFooter } from "@/components/ui/card"
import { auth, signIn } from "@/auth" import { auth, signIn } from "@/auth"
import { redirect } from "next/navigation"; import { redirect } from "next/navigation"
import { SiAuthentik } from "react-icons/si" import { SiAuthentik } from "react-icons/si"
import { UserPlus } from "lucide-react" import { UserPlus } from "lucide-react"
import * as motion from "motion/react-client"
export default async function Login() { export default async function Login() {
const session = await auth() const session = await auth()
@ -27,22 +28,43 @@ export default async function Login() {
await signIn("authentik", { redirectTo: "/account/dashboard" }) await signIn("authentik", { redirectTo: "/account/dashboard" })
}} }}
> >
<Button type="submit" className="w-full"> <motion.div
<SiAuthentik /> initial={{ scale: 0.95 }}
Sign in with Authentik animate={{ scale: 1 }}
</Button> whileTap={{ scale: 0.95 }}
transition={{ duration: 0.2 }}
>
<Button type="submit" className="w-full cursor-pointer">
<SiAuthentik />
Sign in with Authentik
</Button>
</motion.div>
{process.env.SIGNUP_ENABLED === "true" ? ( {process.env.SIGNUP_ENABLED === "true" ? (
<Link href="/account/signup"> <Link href="/account/signup">
<Button variant="outline" className="w-full"> <motion.div
<UserPlus /> initial={{ scale: 0.95 }}
Create an Account animate={{ scale: 1 }}
</Button> whileTap={{ scale: 0.95 }}
transition={{ duration: 0.2 }}
>
<Button variant="outline" className="w-full cursor-pointer">
<UserPlus />
Create an Account
</Button>
</motion.div>
</Link> </Link>
) : ( ) : (
<Button variant="outline" className="w-full cursor-not-allowed" disabled> <motion.div
<UserPlus /> initial={{ scale: 0.95 }}
Registration is Closed animate={{ scale: 1 }}
</Button> whileTap={{ scale: 0.95 }}
transition={{ duration: 0.2 }}
>
<Button variant="outline" className="w-full cursor-not-allowed" disabled>
<UserPlus />
Registration is Closed
</Button>
</motion.div>
)} )}
</form> </form>
</CardContent> </CardContent>

View File

@ -2,12 +2,15 @@
import { ThemeProvider } from "next-themes" import { ThemeProvider } from "next-themes"
import type { ReactNode } from "react" import type { ReactNode } from "react"
import { SessionProvider } from "next-auth/react"
export function Providers({ children }: { children: ReactNode }) { export function Providers({ children }: { children: ReactNode }) {
return ( return (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem> <SessionProvider>
{children} <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
</ThemeProvider> {children}
</ThemeProvider>
</SessionProvider>
) )
} }

View File

@ -178,7 +178,7 @@ 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="text-blue-500">here</Link>. 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>.
</p> </p>
{unlinkLoading ? ( {unlinkLoading ? (
<Button variant="destructive" disabled> <Button variant="destructive" disabled>

View File

@ -1,13 +1,25 @@
import { useState, useEffect } from "react"; "use client"
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge"; import { useState, useEffect } from "react"
import { Loader2 } from "lucide-react"; import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Loader2 } from "lucide-react"
import { useSession } from "next-auth/react"
export const LinkedAccounts = () => { export const LinkedAccounts = () => {
const [gitStatus, setGitStatus] = useState(false) const [gitStatus, setGitStatus] = useState(false)
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [isAdmin, setIsAdmin] = useState(false) const [isAdmin, setIsAdmin] = useState(false)
const [error, setError] = useState<string | null>(null) const [error, setError] = useState<string | null>(null)
const [authStatus, setAuthStatus] = useState(false)
const { data: session } = useSession()
useEffect(() => {
if (session?.user?.email) {
setAuthStatus(true)
}
}, [session])
useEffect(() => { useEffect(() => {
const fetchGitStatus = async () => { const fetchGitStatus = async () => {
@ -40,17 +52,32 @@ export const LinkedAccounts = () => {
} }
}; };
fetchGitStatus().then(r => r) fetchGitStatus()
}, []); }, []);
return ( return (
<Card className="col-span-full md:col-span-1"> <Card className="col-span-full md:col-span-1">
<CardHeader> <CardHeader>
<CardTitle>Linked Accounts</CardTitle> <CardTitle>Linked Accounts</CardTitle>
<CardDescription>LibreCloud-connected services</CardDescription> <CardDescription>LibreCloud-connected services you've linked to your account.</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<ul className="space-y-2"> <ul className="space-y-2">
{authStatus ? (
<li className="flex items-center">
<span className="w-2 h-2 rounded-full bg-green-500 mr-2"></span>
<span>LibreCloud Auth</span>
</li>
) : (
<li className="flex items-center">
<span className="w-2 h-2 rounded-full bg-red-500 mr-2"></span>
<span>LibreCloud Auth</span>
</li>
)}
<li className="flex items-center">
<span className="w-2 h-2 rounded-full bg-green-500 mr-2"></span>
<span>LibreCloud Mail</span>
</li>
<li className="flex items-center"> <li className="flex items-center">
{isLoading ? ( {isLoading ? (
<Loader2 className="w-4 h-4 mr-2 animate-spin" /> <Loader2 className="w-4 h-4 mr-2 animate-spin" />
@ -74,10 +101,6 @@ export const LinkedAccounts = () => {
<span>LibreCloud Git</span> <span>LibreCloud Git</span>
)} )}
</li> </li>
<li className="flex items-center">
<span className="w-2 h-2 rounded-full bg-green-500 mr-2"></span>
<span>p0ntus mail</span>
</li>
</ul> </ul>
<div className="mt-4"> <div className="mt-4">
{error && <p className="text-red-500">{error}</p>} {error && <p className="text-red-500">{error}</p>}

View File

@ -2,7 +2,8 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { import {
Mail, Mail,
Headset Headset,
Heart
} from "lucide-react" } from "lucide-react"
import Link from "next/link" import Link from "next/link"
@ -17,7 +18,8 @@ export const QuickLinks = () => {
href="/account/dashboard/support" href="/account/dashboard/support"
> >
<Button <Button
className="w-full mb-2" variant="secondary"
className="w-full mb-2 cursor-pointer"
> >
<Headset /> <Headset />
Support Support
@ -27,12 +29,24 @@ export const QuickLinks = () => {
href="https://mail.librecloud.cc" href="https://mail.librecloud.cc"
> >
<Button <Button
className="w-full mb-2" variant="secondary"
className="w-full mb-2 cursor-pointer"
> >
<Mail /> <Mail />
Webmail Webmail
</Button> </Button>
</Link> </Link>
<Link
href={process.env.NEXT_PUBLIC_DONATE_URL || "https://donate.stripe.com/6oE8yxaPk6yXbpS145"}
>
<Button
variant="secondary"
className="w-full mb-2 cursor-pointer"
>
<Heart />
Donate
</Button>
</Link>
</CardContent> </CardContent>
</Card> </Card>
); );

View File

@ -36,7 +36,7 @@ export const WelcomeCard = () => {
<p className="text-sm mt-4">Thats all, have a great day!</p> <p className="text-sm mt-4">Thats all, have a great day!</p>
</CardContent> </CardContent>
<CardFooter> <CardFooter>
<Button className="w-full" onClick={handleMarkAsRead}> <Button className="w-full cursor-pointer" onClick={handleMarkAsRead}>
<Check /> Mark as Read <Check /> Mark as Read
</Button> </Button>
</CardFooter> </CardFooter>

View File

@ -1,7 +1,7 @@
import Link from "next/link" import Link from "next/link"
import { Mail, Key, ExternalLink } from "lucide-react" import { Mail, Key, ExternalLink } from "lucide-react"
import { SiGitea, SiAuthentik } from "react-icons/si"; import { SiGitea, SiAuthentik } from "react-icons/si";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Card, CardFooter, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
export const ServicesTab = () => ( export const ServicesTab = () => (
@ -13,16 +13,16 @@ export const ServicesTab = () => (
<Mail className="mr-2 h-4 w-4" /> <Mail className="mr-2 h-4 w-4" />
Webmail Webmail
</CardTitle> </CardTitle>
<CardDescription className="pt-4">Send, read, and manage your email account from a web browser!</CardDescription> <CardDescription className="pt-4">Send, read, and manage your email account from a web browser! Powered by Roundcube and LibreCloud Mail.</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardFooter>
<Button> <Button>
<ExternalLink className="h-4 w-4" /> <ExternalLink className="h-4 w-4" />
<Link href="https://mail.librecloud.cc/"> <Link href="https://mail.librecloud.cc/">
Open App Open App
</Link> </Link>
</Button> </Button>
</CardContent> </CardFooter>
</Card> </Card>
<Card> <Card>
@ -31,16 +31,16 @@ export const ServicesTab = () => (
<SiGitea className="mr-2 h-4 w-4" /> <SiGitea className="mr-2 h-4 w-4" />
Git Git
</CardTitle> </CardTitle>
<CardDescription className="pt-4">Host your repositories and run Actions on a fair usage policy.</CardDescription> <CardDescription className="pt-4">Host unlimited repositories and run Actions on our Git server, powered by Gitea.</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardFooter>
<Button> <Button>
<ExternalLink className="h-4 w-4" /> <ExternalLink className="h-4 w-4" />
<Link href="https://git.pontusmail.org/"> <Link href="https://git.pontusmail.org/">
Open App Open App
</Link> </Link>
</Button> </Button>
</CardContent> </CardFooter>
</Card> </Card>
<Card> <Card>
@ -49,16 +49,16 @@ export const ServicesTab = () => (
<Key className="mr-2 h-4 w-4" /> <Key className="mr-2 h-4 w-4" />
Pass Pass
</CardTitle> </CardTitle>
<CardDescription className="pt-4">Securely store your passwords, notes, and 2FA codes with Vaultwarden.</CardDescription> <CardDescription className="pt-4">Securely store your passwords, notes, and 2FA codes with Vaultwarden. Data is encrypted at rest.</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardFooter>
<Button> <Button>
<ExternalLink className="h-4 w-4" /> <ExternalLink className="h-4 w-4" />
<Link href="https://vaultwarden.p0ntus.com/"> <Link href="https://pass.librecloud.cc/">
Open App Open App
</Link> </Link>
</Button> </Button>
</CardContent> </CardFooter>
</Card> </Card>
<Card> <Card>
@ -69,14 +69,14 @@ export const ServicesTab = () => (
</CardTitle> </CardTitle>
<CardDescription className="pt-4">Manage your single-sign-on account for all LibreCloud services.</CardDescription> <CardDescription className="pt-4">Manage your single-sign-on account for all LibreCloud services.</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardFooter>
<Button> <Button>
<ExternalLink className="h-4 w-4" /> <ExternalLink className="h-4 w-4" />
<Link href="https://auth.librecloud.cc/"> <Link href="https://auth.librecloud.cc/">
Open App Open App
</Link> </Link>
</Button> </Button>
</CardContent> </CardFooter>
</Card> </Card>
</div> </div>
) )

View File

@ -9,9 +9,10 @@ While this will change in the future, we still suggest that provide all the list
These are the environment variables which handle how `librecloud/web` functions. These are the environment variables which handle how `librecloud/web` functions.
With these variables, you can disable entire parts of the dashboard, such as registration. With these variables, you can disable entire parts of the dashboard, such as registration.
| Environment Variable | Description | Expected Value | | Environment Variable | Description | Expected Value |
|----------------------|-----------------------------------------------------------|----------------------------------------| |------------------------|-----------------------------------------------------------|----------------------------------------|
| SIGNUP_ENABLED | Controls if the signup page and APIs are enabled/disabled | `true` (Enabled) or `false` (Disabled) | | SIGNUP_ENABLED | Controls if the signup page and APIs are enabled/disabled | `true` (Enabled) or `false` (Disabled) |
| NEXT_PUBLIC_DONATE_URL | Changes the universal donation link for buttons/links | String - `https://...` |
## Authentik ## Authentik

View File

@ -29,6 +29,7 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cmdk": "1.0.0", "cmdk": "1.0.0",
"cookies-next": "^5.1.0", "cookies-next": "^5.1.0",
"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.474.0",