diff --git a/package.json b/package.json index 1ffdb43..aadf5c9 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@fortawesome/free-regular-svg-icons": "^6.7.2", "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/react-fontawesome": "^0.2.2", + "@radix-ui/react-dropdown-menu": "^2.1.14", "@radix-ui/react-hover-card": "^1.1.13", "@radix-ui/react-label": "^2.1.6", "@radix-ui/react-slot": "^1.2.2", diff --git a/src/app/home/page.tsx b/src/app/home/page.tsx index b28c508..4ef0cd4 100644 --- a/src/app/home/page.tsx +++ b/src/app/home/page.tsx @@ -1,10 +1,14 @@ import { Logout } from '@/components/user/sso-logout-button'; +import { ThemePicker } from '@/components/user/theme-picker'; export default function Home() { return ( -
-

Home

- +
+
{}
+
+

Home

+ +
); } diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 987846c..714e996 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -7,6 +7,7 @@ import Image from 'next/image'; import '@/app/globals.css'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { ThemePicker } from '@/components/user/theme-picker'; import { HoverCard, HoverCardTrigger, @@ -23,20 +24,25 @@ export default async function LoginPage() { return (
- - - Login - - - +
+ +
+
+ + + Login + + + -
+
- {process.env.AUTH_AUTHENTIK_ISSUER && ( - - )} -
-
+ {process.env.AUTH_AUTHENTIK_ISSUER && ( + + )} + + +
diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..7a8804e --- /dev/null +++ b/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,257 @@ +'use client'; + +import * as React from 'react'; +import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'; +import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react'; + +import { cn } from '@/lib/utils'; + +function DropdownMenu({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuContent({ + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function DropdownMenuGroup({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuItem({ + className, + inset, + variant = 'default', + ...props +}: React.ComponentProps & { + inset?: boolean; + variant?: 'default' | 'destructive'; +}) { + return ( + + ); +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuShortcut({ + className, + ...props +}: React.ComponentProps<'span'>) { + return ( + + ); +} + +function DropdownMenuSub({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +}; diff --git a/src/components/user/theme-picker.tsx b/src/components/user/theme-picker.tsx new file mode 100644 index 0000000..5341c3c --- /dev/null +++ b/src/components/user/theme-picker.tsx @@ -0,0 +1,40 @@ +'use client'; + +import * as React from 'react'; +import { Moon, Sun } from 'lucide-react'; +import { useTheme } from 'next-themes'; + +import { Button } from '@/components/ui/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; + +export function ThemePicker() { + const { setTheme } = useTheme(); + + return ( + + + + + + setTheme('light')}> + Light + + setTheme('dark')}> + Dark + + setTheme('system')}> + System + + + + ); +} diff --git a/yarn.lock b/yarn.lock index 1618bfc..1d6757f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -966,6 +966,28 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-collection@npm:1.1.6": + version: 1.1.6 + resolution: "@radix-ui/react-collection@npm:1.1.6" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.2" + "@radix-ui/react-slot": "npm:1.2.2" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/eb3faf1cdc55d0dca7bc0567254a5f4c0ee271a836a1d89a68f36950f12bbd10260b039722c46af7449a8282d833d5afcd6b7745da27be72662ffb0d4108211c + languageName: node + linkType: hard + "@radix-ui/react-compose-refs@npm:1.1.2": version: 1.1.2 resolution: "@radix-ui/react-compose-refs@npm:1.1.2" @@ -992,6 +1014,19 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-direction@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-direction@npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7a89d9291f846a3105e45f4df98d6b7a08f8d7b30acdcd253005dc9db107ee83cbbebc9e47a9af1e400bcd47697f1511ceab23a399b0da854488fc7220482ac9 + languageName: node + linkType: hard + "@radix-ui/react-dismissable-layer@npm:1.1.9": version: 1.1.9 resolution: "@radix-ui/react-dismissable-layer@npm:1.1.9" @@ -1015,6 +1050,65 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-dropdown-menu@npm:^2.1.14": + version: 2.1.14 + resolution: "@radix-ui/react-dropdown-menu@npm:2.1.14" + dependencies: + "@radix-ui/primitive": "npm:1.1.2" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-menu": "npm:2.1.14" + "@radix-ui/react-primitive": "npm:2.1.2" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/c590fff74c2ac1022abc3b6e87fed922d34db7513488119a212eb23a1ae8951d2be45f0124dde7b092f038e452f890d0d279b9da24311aebdb652e650dfce074 + languageName: node + linkType: hard + +"@radix-ui/react-focus-guards@npm:1.1.2": + version: 1.1.2 + resolution: "@radix-ui/react-focus-guards@npm:1.1.2" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/8d6fa55752b9b6e55d1eebb643178e38a824e8ba418eb29031b2979077a12c4e3922892de9f984dd326f77071a14960cd81e99a960beea07598b8c80da618dc5 + languageName: node + linkType: hard + +"@radix-ui/react-focus-scope@npm:1.1.6": + version: 1.1.6 + resolution: "@radix-ui/react-focus-scope@npm:1.1.6" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.2" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/c4a3d12e2c45908113e3a2b9bd59666c2bcc40bde611133a5d67c8d248ddd7bfdfee66c7150dceb1acc6b894ebd44da1b08fab116bbf00fb7bb047be1ec0ec8d + languageName: node + linkType: hard + "@radix-ui/react-hover-card@npm:^1.1.13": version: 1.1.13 resolution: "@radix-ui/react-hover-card@npm:1.1.13" @@ -1042,6 +1136,21 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-id@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-id@npm:1.1.1" + dependencies: + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7d12e76818763d592c331277ef62b197e2e64945307e650bd058f0090e5ae48bbd07691b23b7e9e977901ef4eadcb3e2d5eaeb17a13859083384be83fc1292c7 + languageName: node + linkType: hard + "@radix-ui/react-label@npm:^2.1.6": version: 2.1.6 resolution: "@radix-ui/react-label@npm:2.1.6" @@ -1061,6 +1170,42 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-menu@npm:2.1.14": + version: 2.1.14 + resolution: "@radix-ui/react-menu@npm:2.1.14" + dependencies: + "@radix-ui/primitive": "npm:1.1.2" + "@radix-ui/react-collection": "npm:1.1.6" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-direction": "npm:1.1.1" + "@radix-ui/react-dismissable-layer": "npm:1.1.9" + "@radix-ui/react-focus-guards": "npm:1.1.2" + "@radix-ui/react-focus-scope": "npm:1.1.6" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-popper": "npm:1.2.6" + "@radix-ui/react-portal": "npm:1.1.8" + "@radix-ui/react-presence": "npm:1.1.4" + "@radix-ui/react-primitive": "npm:2.1.2" + "@radix-ui/react-roving-focus": "npm:1.1.9" + "@radix-ui/react-slot": "npm:1.2.2" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + aria-hidden: "npm:^1.2.4" + react-remove-scroll: "npm:^2.6.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/88d5fd986b8d56ce587109507d272f726fd6f45c42886559c1240e868890fc91e3f15e889b69a5db23851c6b576f606cb80640ada6b728261073ee6914fcb422 + languageName: node + linkType: hard + "@radix-ui/react-popper@npm:1.2.6": version: 1.2.6 resolution: "@radix-ui/react-popper@npm:1.2.6" @@ -1148,6 +1293,33 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-roving-focus@npm:1.1.9": + version: 1.1.9 + resolution: "@radix-ui/react-roving-focus@npm:1.1.9" + dependencies: + "@radix-ui/primitive": "npm:1.1.2" + "@radix-ui/react-collection": "npm:1.1.6" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-direction": "npm:1.1.1" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-primitive": "npm:2.1.2" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/7794036199245d3d153f2c3f79fc0f36ba1eec81ba9dca28927c4693f3cca1ddbd3e54d60372cd506c82b826371519d9dc5280ffbe8a3cb0220e141e37718d46 + languageName: node + linkType: hard + "@radix-ui/react-slot@npm:1.2.2, @radix-ui/react-slot@npm:^1.2.2": version: 1.2.2 resolution: "@radix-ui/react-slot@npm:1.2.2" @@ -1849,6 +2021,15 @@ __metadata: languageName: node linkType: hard +"aria-hidden@npm:^1.2.4": + version: 1.2.4 + resolution: "aria-hidden@npm:1.2.4" + dependencies: + tslib: "npm:^2.0.0" + checksum: 10c0/8abcab2e1432efc4db415e97cb3959649ddf52c8fc815d7384f43f3d3abf56f1c12852575d00df9a8927f421d7e0712652dd5f8db244ea57634344e29ecfc74a + languageName: node + linkType: hard + "aria-query@npm:^5.3.2": version: 5.3.2 resolution: "aria-query@npm:5.3.2" @@ -2377,6 +2558,13 @@ __metadata: languageName: node linkType: hard +"detect-node-es@npm:^1.1.0": + version: 1.1.0 + resolution: "detect-node-es@npm:1.1.0" + checksum: 10c0/e562f00de23f10c27d7119e1af0e7388407eb4b06596a25f6d79a360094a109ff285de317f02b090faae093d314cf6e73ac3214f8a5bb3a0def5bece94557fbe + languageName: node + linkType: hard + "doctrine@npm:^2.1.0": version: 2.1.0 resolution: "doctrine@npm:2.1.0" @@ -3314,6 +3502,13 @@ __metadata: languageName: node linkType: hard +"get-nonce@npm:^1.0.0": + version: 1.0.1 + resolution: "get-nonce@npm:1.0.1" + checksum: 10c0/2d7df55279060bf0568549e1ffc9b84bc32a32b7541675ca092dce56317cdd1a59a98dcc4072c9f6a980779440139a3221d7486f52c488e69dc0fd27b1efb162 + languageName: node + linkType: hard + "get-proto@npm:^1.0.0, get-proto@npm:^1.0.1": version: 1.0.1 resolution: "get-proto@npm:1.0.1" @@ -4209,6 +4404,7 @@ __metadata: "@fortawesome/free-regular-svg-icons": "npm:^6.7.2" "@fortawesome/free-solid-svg-icons": "npm:^6.7.2" "@fortawesome/react-fontawesome": "npm:^0.2.2" + "@radix-ui/react-dropdown-menu": "npm:^2.1.14" "@radix-ui/react-hover-card": "npm:^1.1.13" "@radix-ui/react-label": "npm:^2.1.6" "@radix-ui/react-slot": "npm:^1.2.2" @@ -4976,6 +5172,57 @@ __metadata: languageName: node linkType: hard +"react-remove-scroll-bar@npm:^2.3.7": + version: 2.3.8 + resolution: "react-remove-scroll-bar@npm:2.3.8" + dependencies: + react-style-singleton: "npm:^2.2.2" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/9a0675c66cbb52c325bdbfaed80987a829c4504cefd8ff2dd3b6b3afc9a1500b8ec57b212e92c1fb654396d07bbe18830a8146fe77677d2a29ce40b5e1f78654 + languageName: node + linkType: hard + +"react-remove-scroll@npm:^2.6.3": + version: 2.6.3 + resolution: "react-remove-scroll@npm:2.6.3" + dependencies: + react-remove-scroll-bar: "npm:^2.3.7" + react-style-singleton: "npm:^2.2.3" + tslib: "npm:^2.1.0" + use-callback-ref: "npm:^1.3.3" + use-sidecar: "npm:^1.1.3" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/068e9704ff26816fffc4c8903e2c6c8df7291ee08615d7c1ab0cf8751f7080e2c5a5d78ef5d908b11b9cfc189f176d312e44cb02ea291ca0466d8283b479b438 + languageName: node + linkType: hard + +"react-style-singleton@npm:^2.2.2, react-style-singleton@npm:^2.2.3": + version: 2.2.3 + resolution: "react-style-singleton@npm:2.2.3" + dependencies: + get-nonce: "npm:^1.0.0" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/841938ff16d16a6b76895f4cb2e1fea957e5fe3b30febbf03a54892dae1c9153f2383e231dea0b3ba41192ad2f2849448fa859caccd288943bce32639e971bee + languageName: node + linkType: hard + "react@npm:^19.0.0": version: 19.1.0 resolution: "react@npm:19.1.0" @@ -5735,7 +5982,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.4.0, tslib@npm:^2.8.0": +"tslib@npm:^2.0.0, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 @@ -5956,6 +6203,37 @@ __metadata: languageName: node linkType: hard +"use-callback-ref@npm:^1.3.3": + version: 1.3.3 + resolution: "use-callback-ref@npm:1.3.3" + dependencies: + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/f887488c6e6075cdad4962979da1714b217bcb1ee009a9e57ce9a844bcfc4c3a99e93983dfc2e5af9e0913824d24e730090ff255e902c516dcb58d2d3837e01c + languageName: node + linkType: hard + +"use-sidecar@npm:^1.1.3": + version: 1.1.3 + resolution: "use-sidecar@npm:1.1.3" + dependencies: + detect-node-es: "npm:^1.1.0" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/161599bf921cfaa41c85d2b01c871975ee99260f3e874c2d41c05890d41170297bdcf314bc5185e7a700de2034ac5b888e3efc8e9f35724f4918f53538d717c9 + languageName: node + linkType: hard + "vary@npm:^1, vary@npm:^1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2"