Compare commits
24 commits
Author | SHA1 | Date | |
---|---|---|---|
a458f1d600 | |||
c571f084d7 | |||
01e301eb60 | |||
4d6f3c23c3 | |||
cf477b1f25 | |||
792b11248a | |||
79bdf1bc6c | |||
bbe681d6d9 | |||
0ac6065a83 | |||
59a0cb4bc9 | |||
e2bbc2f1eb | |||
c0c38e7aa7 | |||
17e52b12d0 | |||
69574ae124 | |||
fb4425a20c | |||
596b9d7f79 | |||
3fd683b6ee | |||
8da05a33cb | |||
4eef07de01 | |||
fdbb265ae6 | |||
f0c66fb4a2 | |||
47aadc9ef5 | |||
59c2fd8f2d | |||
33c3eb5581 |
107 changed files with 2590 additions and 555 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -12,3 +12,4 @@ vite.config.js.timestamp-*
|
||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
|
|
||||||
/.vscode
|
/.vscode
|
||||||
|
/.idea
|
13
components.json
Normal file
13
components.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://shadcn-svelte.com/schema.json",
|
||||||
|
"style": "new-york",
|
||||||
|
"tailwind": {
|
||||||
|
"config": "tailwind.config.js",
|
||||||
|
"css": "src/app.postcss",
|
||||||
|
"baseColor": "slate"
|
||||||
|
},
|
||||||
|
"aliases": {
|
||||||
|
"components": "$lib/components",
|
||||||
|
"utils": "$lib/utils"
|
||||||
|
}
|
||||||
|
}
|
42
package.json
42
package.json
|
@ -9,40 +9,44 @@
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
||||||
"format": "prettier --plugin-search-dir . --write ."
|
"format": "prettier --plugin-search-dir . --write .",
|
||||||
|
"ui": "npx shadcn-svelte@latest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@fontsource/fira-mono": "^4.5.10",
|
||||||
|
"@neoconfetti/svelte": "^1.0.0",
|
||||||
"@sveltejs/adapter-auto": "^2.0.0",
|
"@sveltejs/adapter-auto": "^2.0.0",
|
||||||
"@sveltejs/kit": "^1.20.4",
|
"@sveltejs/kit": "^1.20.4",
|
||||||
|
"@types/cookie": "^0.5.1",
|
||||||
|
"@types/node": "^20.6.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||||
"@typescript-eslint/parser": "^5.45.0",
|
"@typescript-eslint/parser": "^5.45.0",
|
||||||
|
"autoprefixer": "^10.4.15",
|
||||||
"eslint": "^8.28.0",
|
"eslint": "^8.28.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-svelte": "^2.30.0",
|
"eslint-plugin-svelte": "^2.30.0",
|
||||||
|
"postcss": "^8.4.29",
|
||||||
|
"postcss-load-config": "^4.0.1",
|
||||||
"prettier": "^2.8.0",
|
"prettier": "^2.8.0",
|
||||||
"prettier-plugin-svelte": "^2.10.1",
|
"prettier-plugin-svelte": "^2.10.1",
|
||||||
"svelte": "^4.0.5",
|
"svelte": "^5.0.0-next.17",
|
||||||
"svelte-check": "^3.4.3",
|
"svelte-check": "^3.4.3",
|
||||||
|
"svelte-loading-spinners": "^0.3.4",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^4.4.2",
|
"vite": "^4.4.2"
|
||||||
"postcss": "8.4.29",
|
|
||||||
"autoprefixer": "10.4.15",
|
|
||||||
"tailwindcss": "3.3.3",
|
|
||||||
"@skeletonlabs/skeleton": "2.0.0",
|
|
||||||
"@skeletonlabs/tw-plugin": "0.1.0",
|
|
||||||
"vite-plugin-tailwind-purgecss": "0.1.3",
|
|
||||||
"@types/node": "20.6.0",
|
|
||||||
"@fontsource/fira-mono": "^4.5.10",
|
|
||||||
"@neoconfetti/svelte": "^1.0.0",
|
|
||||||
"@types/cookie": "^0.5.1",
|
|
||||||
"postcss-load-config": "^4.0.1",
|
|
||||||
"svelte-loading-spinners": "^0.3.4"
|
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chart.js": "^4.3.3",
|
"bits-ui": "^0.11.6",
|
||||||
"chartjs-plugin-datalabels": "^2.2.0",
|
"chart.js": "^4.3.3",
|
||||||
"svelte-chartjs": "^3.1.2"
|
"chartjs-plugin-datalabels": "^2.2.0",
|
||||||
}
|
"clsx": "^2.0.0",
|
||||||
|
"flowbite": "^2.2.0",
|
||||||
|
"radix-icons-svelte": "^1.2.1",
|
||||||
|
"svelte-chartjs": "^3.1.2",
|
||||||
|
"tailwind-merge": "^2.1.0",
|
||||||
|
"tailwind-variants": "^0.1.18",
|
||||||
|
"tailwindcss": "^3.3.6"
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" class="dark">
|
<html lang="en" class="dark h-full">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body data-sveltekit-preload-data="hover" data-theme="wintry">
|
<body class="h-full w-full" data-sveltekit-preload-data="hover">
|
||||||
<div style="display: contents" class="h-screen overflow-hidden contents">%sveltekit.body%</div>
|
%sveltekit.body%
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,6 +1,78 @@
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
@tailwind variants;
|
|
||||||
|
|
||||||
html, body { @apply h-full overflow-hidden; }
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--background: 0 0% 100%;
|
||||||
|
--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 40% 96.1%;
|
||||||
|
--accent-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--destructive: 0 72.2% 50.6%;
|
||||||
|
--destructive-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--ring: 222.2 84% 4.9%;
|
||||||
|
|
||||||
|
--radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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: 210 40% 98%;
|
||||||
|
|
||||||
|
--ring: hsl(212.7,26.8%,83.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
* {
|
||||||
|
@apply border-border;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
@apply bg-background text-foreground;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
export let text: string;
|
|
||||||
export let action: any = () => {};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<button class="btn px-4 py-2 mx-2 rounded-token variant-ringed-primary hover:variant-filled-primary active:variant-filled-primary" on:click={action}>{text}</button>
|
|
|
@ -1,2 +0,0 @@
|
||||||
export const apiBaseUrl = 'https://wip.chellaris.net/api';
|
|
||||||
export const MACHINE_GROUP_ID = 12;
|
|
19
src/lib/components/ui/avatar/avatar-fallback.svelte
Normal file
19
src/lib/components/ui/avatar/avatar-fallback.svelte
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = AvatarPrimitive.FallbackProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AvatarPrimitive.Fallback
|
||||||
|
class={cn(
|
||||||
|
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</AvatarPrimitive.Fallback>
|
18
src/lib/components/ui/avatar/avatar-image.svelte
Normal file
18
src/lib/components/ui/avatar/avatar-image.svelte
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = AvatarPrimitive.ImageProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let src: $$Props["src"] = undefined;
|
||||||
|
export let alt: $$Props["alt"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AvatarPrimitive.Image
|
||||||
|
{src}
|
||||||
|
{alt}
|
||||||
|
class={cn("aspect-square h-full w-full", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
21
src/lib/components/ui/avatar/avatar.svelte
Normal file
21
src/lib/components/ui/avatar/avatar.svelte
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = AvatarPrimitive.Props;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let delayMs: $$Props["delayMs"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AvatarPrimitive.Root
|
||||||
|
{delayMs}
|
||||||
|
class={cn(
|
||||||
|
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</AvatarPrimitive.Root>
|
13
src/lib/components/ui/avatar/index.ts
Normal file
13
src/lib/components/ui/avatar/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import Root from "./avatar.svelte";
|
||||||
|
import Image from "./avatar-image.svelte";
|
||||||
|
import Fallback from "./avatar-fallback.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Image,
|
||||||
|
Fallback,
|
||||||
|
//
|
||||||
|
Root as Avatar,
|
||||||
|
Image as AvatarImage,
|
||||||
|
Fallback as AvatarFallback
|
||||||
|
};
|
25
src/lib/components/ui/button/button.svelte
Normal file
25
src/lib/components/ui/button/button.svelte
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Button as ButtonPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { buttonVariants, type Props, type Events } from ".";
|
||||||
|
|
||||||
|
type $$Props = Props;
|
||||||
|
type $$Events = Events;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let variant: $$Props["variant"] = "default";
|
||||||
|
export let size: $$Props["size"] = "default";
|
||||||
|
export let builders: $$Props["builders"] = [];
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ButtonPrimitive.Root
|
||||||
|
{builders}
|
||||||
|
class={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
type="button"
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</ButtonPrimitive.Root>
|
52
src/lib/components/ui/button/index.ts
Normal file
52
src/lib/components/ui/button/index.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import type { Button as ButtonPrimitive } from "bits-ui";
|
||||||
|
import { tv, type VariantProps } from "tailwind-variants";
|
||||||
|
import Root from "./button.svelte";
|
||||||
|
|
||||||
|
const buttonVariants = tv({
|
||||||
|
base: "inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default:
|
||||||
|
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||||
|
destructive:
|
||||||
|
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||||
|
outline:
|
||||||
|
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||||
|
secondary:
|
||||||
|
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||||
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||||
|
link: "text-primary underline-offset-4 hover:underline"
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: "h-9 px-4 py-2",
|
||||||
|
sm: "h-8 rounded-md px-3 text-xs",
|
||||||
|
lg: "h-10 rounded-md px-8",
|
||||||
|
icon: "h-9 w-9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
type Variant = VariantProps<typeof buttonVariants>["variant"];
|
||||||
|
type Size = VariantProps<typeof buttonVariants>["size"];
|
||||||
|
|
||||||
|
type Props = ButtonPrimitive.Props & {
|
||||||
|
variant?: Variant;
|
||||||
|
size?: Size;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Events = ButtonPrimitive.Events;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
type Props,
|
||||||
|
type Events,
|
||||||
|
//
|
||||||
|
Root as Button,
|
||||||
|
type Props as ButtonProps,
|
||||||
|
type Events as ButtonEvents,
|
||||||
|
buttonVariants
|
||||||
|
};
|
36
src/lib/components/ui/checkbox/checkbox.svelte
Normal file
36
src/lib/components/ui/checkbox/checkbox.svelte
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Checkbox as CheckboxPrimitive } from "bits-ui";
|
||||||
|
import { Check, Minus } from "radix-icons-svelte";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = CheckboxPrimitive.Props;
|
||||||
|
type $$Events = CheckboxPrimitive.Events;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let checked: $$Props["checked"] = false;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CheckboxPrimitive.Root
|
||||||
|
class={cn(
|
||||||
|
"box-content peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
bind:checked
|
||||||
|
on:click
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<CheckboxPrimitive.Indicator
|
||||||
|
class={cn("flex items-center justify-center text-current h-4 w-4")}
|
||||||
|
let:isChecked
|
||||||
|
let:isIndeterminate
|
||||||
|
>
|
||||||
|
{#if isIndeterminate}
|
||||||
|
<Minus class="h-3.5 w-3.5" />
|
||||||
|
{:else}
|
||||||
|
<Check
|
||||||
|
class={cn("h-3.5 w-3.5", !isChecked && "text-transparent")}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</CheckboxPrimitive.Indicator>
|
||||||
|
</CheckboxPrimitive.Root>
|
6
src/lib/components/ui/checkbox/index.ts
Normal file
6
src/lib/components/ui/checkbox/index.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import Root from "./checkbox.svelte";
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Checkbox
|
||||||
|
};
|
14
src/lib/components/ui/collapsible/collapsible-content.svelte
Normal file
14
src/lib/components/ui/collapsible/collapsible-content.svelte
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Collapsible as CollapsiblePrimitive } from "bits-ui";
|
||||||
|
import { slide } from "svelte/transition";
|
||||||
|
type $$Props = CollapsiblePrimitive.ContentProps;
|
||||||
|
|
||||||
|
export let transition: $$Props["transition"] = slide;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
|
duration: 150
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CollapsiblePrimitive.Content {transition} {transitionConfig} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</CollapsiblePrimitive.Content>
|
15
src/lib/components/ui/collapsible/index.ts
Normal file
15
src/lib/components/ui/collapsible/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { Collapsible as CollapsiblePrimitive } from "bits-ui";
|
||||||
|
import Content from "./collapsible-content.svelte";
|
||||||
|
|
||||||
|
const Root = CollapsiblePrimitive.Root;
|
||||||
|
const Trigger = CollapsiblePrimitive.Trigger;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Content,
|
||||||
|
Trigger,
|
||||||
|
//
|
||||||
|
Root as Collapsible,
|
||||||
|
Content as CollapsibleContent,
|
||||||
|
Trigger as CollapsibleTrigger
|
||||||
|
};
|
|
@ -0,0 +1,35 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { Check } from "radix-icons-svelte";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
|
||||||
|
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let checked: $$Props["checked"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.CheckboxItem
|
||||||
|
bind:checked
|
||||||
|
class={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerdown
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
>
|
||||||
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<DropdownMenuPrimitive.CheckboxIndicator>
|
||||||
|
<Check class="h-4 w-4" />
|
||||||
|
</DropdownMenuPrimitive.CheckboxIndicator>
|
||||||
|
</span>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.CheckboxItem>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.ContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let sideOffset: $$Props["sideOffset"] = 4;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.Content
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
{sideOffset}
|
||||||
|
class={cn(
|
||||||
|
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:keydown
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.Content>
|
|
@ -0,0 +1,31 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.ItemProps & {
|
||||||
|
inset?: boolean;
|
||||||
|
};
|
||||||
|
type $$Events = DropdownMenuPrimitive.ItemEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let inset: $$Props["inset"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.Item
|
||||||
|
class={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
inset && "pl-8",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerdown
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.Item>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.LabelProps & {
|
||||||
|
inset?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let inset: $$Props["inset"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.Label
|
||||||
|
class={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.Label>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.RadioGroupProps;
|
||||||
|
|
||||||
|
export let value: $$Props["value"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.RadioGroup {...$$restProps} bind:value>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.RadioGroup>
|
|
@ -0,0 +1,35 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { DotFilled } from "radix-icons-svelte";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.RadioItemProps;
|
||||||
|
type $$Events = DropdownMenuPrimitive.RadioItemEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: DropdownMenuPrimitive.RadioItemProps["value"];
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.RadioItem
|
||||||
|
class={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{value}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerdown
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
>
|
||||||
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<DropdownMenuPrimitive.RadioIndicator>
|
||||||
|
<DotFilled class="h-4 w-4 fill-current" />
|
||||||
|
</DropdownMenuPrimitive.RadioIndicator>
|
||||||
|
</span>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.RadioItem>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.SeparatorProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.Separator
|
||||||
|
class={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</span>
|
|
@ -0,0 +1,29 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.SubContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
|
x: -10,
|
||||||
|
y: 0
|
||||||
|
};
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.SubContent
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
class={cn(
|
||||||
|
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-lg focus:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:keydown
|
||||||
|
on:focusout
|
||||||
|
on:pointermove
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.SubContent>
|
|
@ -0,0 +1,32 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { ChevronRight } from "radix-icons-svelte";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.SubTriggerProps & {
|
||||||
|
inset?: boolean;
|
||||||
|
};
|
||||||
|
type $$Events = DropdownMenuPrimitive.SubTriggerEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let inset: $$Props["inset"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.SubTrigger
|
||||||
|
class={cn(
|
||||||
|
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[state=open]:bg-accent",
|
||||||
|
inset && "pl-8",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<ChevronRight class="ml-auto h-4 w-4" />
|
||||||
|
</DropdownMenuPrimitive.SubTrigger>
|
48
src/lib/components/ui/dropdown-menu/index.ts
Normal file
48
src/lib/components/ui/dropdown-menu/index.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import Item from "./dropdown-menu-item.svelte";
|
||||||
|
import Label from "./dropdown-menu-label.svelte";
|
||||||
|
import Content from "./dropdown-menu-content.svelte";
|
||||||
|
import Shortcut from "./dropdown-menu-shortcut.svelte";
|
||||||
|
import RadioItem from "./dropdown-menu-radio-item.svelte";
|
||||||
|
import Separator from "./dropdown-menu-separator.svelte";
|
||||||
|
import RadioGroup from "./dropdown-menu-radio-group.svelte";
|
||||||
|
import SubContent from "./dropdown-menu-sub-content.svelte";
|
||||||
|
import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
|
||||||
|
import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
|
||||||
|
|
||||||
|
const Sub = DropdownMenuPrimitive.Sub;
|
||||||
|
const Root = DropdownMenuPrimitive.Root;
|
||||||
|
const Trigger = DropdownMenuPrimitive.Trigger;
|
||||||
|
const Group = DropdownMenuPrimitive.Group;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Sub,
|
||||||
|
Root,
|
||||||
|
Item,
|
||||||
|
Label,
|
||||||
|
Group,
|
||||||
|
Trigger,
|
||||||
|
Content,
|
||||||
|
Shortcut,
|
||||||
|
Separator,
|
||||||
|
RadioItem,
|
||||||
|
SubContent,
|
||||||
|
SubTrigger,
|
||||||
|
RadioGroup,
|
||||||
|
CheckboxItem,
|
||||||
|
//
|
||||||
|
Root as DropdownMenu,
|
||||||
|
Sub as DropdownMenuSub,
|
||||||
|
Item as DropdownMenuItem,
|
||||||
|
Label as DropdownMenuLabel,
|
||||||
|
Group as DropdownMenuGroup,
|
||||||
|
Content as DropdownMenuContent,
|
||||||
|
Trigger as DropdownMenuTrigger,
|
||||||
|
Shortcut as DropdownMenuShortcut,
|
||||||
|
RadioItem as DropdownMenuRadioItem,
|
||||||
|
Separator as DropdownMenuSeparator,
|
||||||
|
RadioGroup as DropdownMenuRadioGroup,
|
||||||
|
SubContent as DropdownMenuSubContent,
|
||||||
|
SubTrigger as DropdownMenuSubTrigger,
|
||||||
|
CheckboxItem as DropdownMenuCheckboxItem
|
||||||
|
};
|
25
src/lib/components/ui/input/index.ts
Normal file
25
src/lib/components/ui/input/index.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import Root from "./input.svelte";
|
||||||
|
|
||||||
|
type FormInputEvent<T extends Event = Event> = T & {
|
||||||
|
currentTarget: EventTarget & HTMLInputElement;
|
||||||
|
};
|
||||||
|
export type InputEvents = {
|
||||||
|
blur: FormInputEvent<FocusEvent>;
|
||||||
|
change: FormInputEvent<Event>;
|
||||||
|
click: FormInputEvent<MouseEvent>;
|
||||||
|
focus: FormInputEvent<FocusEvent>;
|
||||||
|
keydown: FormInputEvent<KeyboardEvent>;
|
||||||
|
keypress: FormInputEvent<KeyboardEvent>;
|
||||||
|
keyup: FormInputEvent<KeyboardEvent>;
|
||||||
|
mouseover: FormInputEvent<MouseEvent>;
|
||||||
|
mouseenter: FormInputEvent<MouseEvent>;
|
||||||
|
mouseleave: FormInputEvent<MouseEvent>;
|
||||||
|
paste: FormInputEvent<ClipboardEvent>;
|
||||||
|
input: FormInputEvent<InputEvent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Input
|
||||||
|
};
|
33
src/lib/components/ui/input/input.svelte
Normal file
33
src/lib/components/ui/input/input.svelte
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLInputAttributes } from "svelte/elements";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { InputEvents } from ".";
|
||||||
|
|
||||||
|
type $$Props = HTMLInputAttributes;
|
||||||
|
type $$Events = InputEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: $$Props["value"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<input
|
||||||
|
class={cn(
|
||||||
|
"flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-foreground file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
bind:value
|
||||||
|
on:blur
|
||||||
|
on:change
|
||||||
|
on:click
|
||||||
|
on:focus
|
||||||
|
on:keydown
|
||||||
|
on:keypress
|
||||||
|
on:keyup
|
||||||
|
on:mouseover
|
||||||
|
on:mouseenter
|
||||||
|
on:mouseleave
|
||||||
|
on:paste
|
||||||
|
on:input
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
7
src/lib/components/ui/label/index.ts
Normal file
7
src/lib/components/ui/label/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Root from "./label.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Label
|
||||||
|
};
|
19
src/lib/components/ui/label/label.svelte
Normal file
19
src/lib/components/ui/label/label.svelte
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Label as LabelPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = LabelPrimitive.Props;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<LabelPrimitive.Root
|
||||||
|
class={cn(
|
||||||
|
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</LabelPrimitive.Root>
|
52
src/lib/components/ui/menubar/index.ts
Normal file
52
src/lib/components/ui/menubar/index.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
import Root from "./menubar.svelte";
|
||||||
|
import CheckboxItem from "./menubar-checkbox-item.svelte";
|
||||||
|
import Content from "./menubar-content.svelte";
|
||||||
|
import Item from "./menubar-item.svelte";
|
||||||
|
import Label from "./menubar-label.svelte";
|
||||||
|
import RadioItem from "./menubar-radio-item.svelte";
|
||||||
|
import Separator from "./menubar-separator.svelte";
|
||||||
|
import Shortcut from "./menubar-shortcut.svelte";
|
||||||
|
import SubContent from "./menubar-sub-content.svelte";
|
||||||
|
import SubTrigger from "./menubar-sub-trigger.svelte";
|
||||||
|
import Trigger from "./menubar-trigger.svelte";
|
||||||
|
|
||||||
|
const Menu = MenubarPrimitive.Menu;
|
||||||
|
const Group = MenubarPrimitive.Group;
|
||||||
|
const Sub = MenubarPrimitive.Sub;
|
||||||
|
const RadioGroup = MenubarPrimitive.RadioGroup;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
CheckboxItem,
|
||||||
|
Content,
|
||||||
|
Item,
|
||||||
|
Label,
|
||||||
|
RadioItem,
|
||||||
|
Separator,
|
||||||
|
Shortcut,
|
||||||
|
SubContent,
|
||||||
|
SubTrigger,
|
||||||
|
Trigger,
|
||||||
|
Menu,
|
||||||
|
Group,
|
||||||
|
Sub,
|
||||||
|
RadioGroup,
|
||||||
|
//
|
||||||
|
Root as Menubar,
|
||||||
|
CheckboxItem as MenubarCheckboxItem,
|
||||||
|
Content as MenubarContent,
|
||||||
|
Item as MenubarItem,
|
||||||
|
Label as MenubarLabel,
|
||||||
|
RadioItem as MenubarRadioItem,
|
||||||
|
Separator as MenubarSeparator,
|
||||||
|
Shortcut as MenubarShortcut,
|
||||||
|
SubContent as MenubarSubContent,
|
||||||
|
SubTrigger as MenubarSubTrigger,
|
||||||
|
Trigger as MenubarTrigger,
|
||||||
|
Menu as MenubarMenu,
|
||||||
|
Group as MenubarGroup,
|
||||||
|
Sub as MenubarSub,
|
||||||
|
RadioGroup as MenubarRadioGroup
|
||||||
|
};
|
33
src/lib/components/ui/menubar/menubar-checkbox-item.svelte
Normal file
33
src/lib/components/ui/menubar/menubar-checkbox-item.svelte
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { Check } from "radix-icons-svelte";
|
||||||
|
|
||||||
|
type $$Props = MenubarPrimitive.CheckboxItemProps;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
export let checked: $$Props["checked"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.CheckboxItem
|
||||||
|
bind:checked
|
||||||
|
class={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
on:pointerdown
|
||||||
|
>
|
||||||
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<MenubarPrimitive.CheckboxIndicator>
|
||||||
|
<Check class="h-4 w-4" />
|
||||||
|
</MenubarPrimitive.CheckboxIndicator>
|
||||||
|
</span>
|
||||||
|
<slot />
|
||||||
|
</MenubarPrimitive.CheckboxItem>
|
28
src/lib/components/ui/menubar/menubar-content.svelte
Normal file
28
src/lib/components/ui/menubar/menubar-content.svelte
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = MenubarPrimitive.ContentProps;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let align: $$Props["align"] = "start";
|
||||||
|
export let alignOffset: $$Props["alignOffset"] = -4;
|
||||||
|
export let sideOffset: $$Props["sideOffset"] = 8;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.Content
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
{sideOffset}
|
||||||
|
{align}
|
||||||
|
{alignOffset}
|
||||||
|
class={cn(
|
||||||
|
"z-50 min-w-[12rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</MenubarPrimitive.Content>
|
31
src/lib/components/ui/menubar/menubar-item.svelte
Normal file
31
src/lib/components/ui/menubar/menubar-item.svelte
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = MenubarPrimitive.ItemProps & {
|
||||||
|
inset?: boolean;
|
||||||
|
};
|
||||||
|
type $$Events = MenubarPrimitive.ItemEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let inset: $$Props["inset"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.Item
|
||||||
|
class={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
inset && "pl-8",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
on:pointerdown
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</MenubarPrimitive.Item>
|
18
src/lib/components/ui/menubar/menubar-label.svelte
Normal file
18
src/lib/components/ui/menubar/menubar-label.svelte
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = MenubarPrimitive.LabelProps & {
|
||||||
|
inset?: boolean;
|
||||||
|
};
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let inset: $$Props["inset"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.Label
|
||||||
|
class={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</MenubarPrimitive.Label>
|
34
src/lib/components/ui/menubar/menubar-radio-item.svelte
Normal file
34
src/lib/components/ui/menubar/menubar-radio-item.svelte
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { DotFilled } from "radix-icons-svelte";
|
||||||
|
|
||||||
|
type $$Props = MenubarPrimitive.RadioItemProps;
|
||||||
|
type $$Events = MenubarPrimitive.RadioItemEvents;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: $$Props["value"];
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.RadioItem
|
||||||
|
{value}
|
||||||
|
class={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
on:pointerdown
|
||||||
|
>
|
||||||
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<MenubarPrimitive.RadioIndicator>
|
||||||
|
<DotFilled class="h-4 w-4 fill-current" />
|
||||||
|
</MenubarPrimitive.RadioIndicator>
|
||||||
|
</span>
|
||||||
|
<slot />
|
||||||
|
</MenubarPrimitive.RadioItem>
|
13
src/lib/components/ui/menubar/menubar-separator.svelte
Normal file
13
src/lib/components/ui/menubar/menubar-separator.svelte
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = MenubarPrimitive.SeparatorProps;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.Separator
|
||||||
|
class={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
18
src/lib/components/ui/menubar/menubar-shortcut.svelte
Normal file
18
src/lib/components/ui/menubar/menubar-shortcut.svelte
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class={cn(
|
||||||
|
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</span>
|
25
src/lib/components/ui/menubar/menubar-sub-content.svelte
Normal file
25
src/lib/components/ui/menubar/menubar-sub-content.svelte
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = MenubarPrimitive.SubContentProps;
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
|
x: -10,
|
||||||
|
y: 0
|
||||||
|
};
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.SubContent
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
class={cn(
|
||||||
|
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-lg focus:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</MenubarPrimitive.SubContent>
|
32
src/lib/components/ui/menubar/menubar-sub-trigger.svelte
Normal file
32
src/lib/components/ui/menubar/menubar-sub-trigger.svelte
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { ChevronRight } from "radix-icons-svelte";
|
||||||
|
|
||||||
|
type $$Props = MenubarPrimitive.SubTriggerProps & {
|
||||||
|
inset?: boolean;
|
||||||
|
};
|
||||||
|
type $$Events = MenubarPrimitive.SubTriggerEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let inset: $$Props["inset"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.SubTrigger
|
||||||
|
class={cn(
|
||||||
|
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
||||||
|
inset && "pl-8",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<ChevronRight class="ml-auto h-4 w-4" />
|
||||||
|
</MenubarPrimitive.SubTrigger>
|
23
src/lib/components/ui/menubar/menubar-trigger.svelte
Normal file
23
src/lib/components/ui/menubar/menubar-trigger.svelte
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = MenubarPrimitive.TriggerProps;
|
||||||
|
type $$Events = MenubarPrimitive.TriggerEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.Trigger
|
||||||
|
class={cn(
|
||||||
|
"flex cursor-default select-none items-center rounded-sm px-3 py-1 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:pointerenter
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</MenubarPrimitive.Trigger>
|
18
src/lib/components/ui/menubar/menubar.svelte
Normal file
18
src/lib/components/ui/menubar/menubar.svelte
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = MenubarPrimitive.Props;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.Root
|
||||||
|
class={cn(
|
||||||
|
"flex h-9 items-center space-x-1 rounded-md border bg-background p-1 shadow-sm",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</MenubarPrimitive.Root>
|
14
src/lib/components/ui/popover/index.ts
Normal file
14
src/lib/components/ui/popover/index.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
import Content from "./popover-content.svelte";
|
||||||
|
const Root = PopoverPrimitive.Root;
|
||||||
|
const Trigger = PopoverPrimitive.Trigger;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Content,
|
||||||
|
Trigger,
|
||||||
|
//
|
||||||
|
Root as Popover,
|
||||||
|
Content as PopoverContent,
|
||||||
|
Trigger as PopoverTrigger
|
||||||
|
};
|
27
src/lib/components/ui/popover/popover-content.svelte
Normal file
27
src/lib/components/ui/popover/popover-content.svelte
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = PopoverPrimitive.ContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
||||||
|
export let align: $$Props["align"] = "center";
|
||||||
|
export let sideOffset: $$Props["sideOffset"] = 4;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PopoverPrimitive.Content
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
{align}
|
||||||
|
{sideOffset}
|
||||||
|
{...$$restProps}
|
||||||
|
class={cn(
|
||||||
|
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</PopoverPrimitive.Content>
|
34
src/lib/components/ui/select/index.ts
Normal file
34
src/lib/components/ui/select/index.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
import Label from "./select-label.svelte";
|
||||||
|
import Item from "./select-item.svelte";
|
||||||
|
import Content from "./select-content.svelte";
|
||||||
|
import Trigger from "./select-trigger.svelte";
|
||||||
|
import Separator from "./select-separator.svelte";
|
||||||
|
|
||||||
|
const Root = SelectPrimitive.Root;
|
||||||
|
const Group = SelectPrimitive.Group;
|
||||||
|
const Input = SelectPrimitive.Input;
|
||||||
|
const Value = SelectPrimitive.Value;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Item,
|
||||||
|
Group,
|
||||||
|
Input,
|
||||||
|
Label,
|
||||||
|
Value,
|
||||||
|
Content,
|
||||||
|
Trigger,
|
||||||
|
Separator,
|
||||||
|
//
|
||||||
|
Root as Select,
|
||||||
|
Item as SelectItem,
|
||||||
|
Group as SelectGroup,
|
||||||
|
Input as SelectInput,
|
||||||
|
Label as SelectLabel,
|
||||||
|
Value as SelectValue,
|
||||||
|
Content as SelectContent,
|
||||||
|
Trigger as SelectTrigger,
|
||||||
|
Separator as SelectSeparator
|
||||||
|
};
|
36
src/lib/components/ui/select/select-content.svelte
Normal file
36
src/lib/components/ui/select/select-content.svelte
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
import { scale } from "svelte/transition";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.ContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let sideOffset: $$Props["sideOffset"] = 4;
|
||||||
|
export let inTransition: $$Props["inTransition"] = flyAndScale;
|
||||||
|
export let inTransitionConfig: $$Props["inTransitionConfig"] = undefined;
|
||||||
|
export let outTransition: $$Props["outTransition"] = scale;
|
||||||
|
export let outTransitionConfig: $$Props["outTransitionConfig"] = {
|
||||||
|
start: 0.95,
|
||||||
|
opacity: 0,
|
||||||
|
duration: 50
|
||||||
|
};
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SelectPrimitive.Content
|
||||||
|
{inTransition}
|
||||||
|
{inTransitionConfig}
|
||||||
|
{outTransition}
|
||||||
|
{outTransitionConfig}
|
||||||
|
{sideOffset}
|
||||||
|
class={cn(
|
||||||
|
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md focus:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<div class="w-full p-1">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</SelectPrimitive.Content>
|
35
src/lib/components/ui/select/select-item.svelte
Normal file
35
src/lib/components/ui/select/select-item.svelte
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
import { Check } from "radix-icons-svelte";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.ItemProps;
|
||||||
|
type $$Events = Required<SelectPrimitive.ItemEvents>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: $$Props["value"];
|
||||||
|
export let label: $$Props["label"] = undefined;
|
||||||
|
export let disabled: $$Props["disabled"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SelectPrimitive.Item
|
||||||
|
{value}
|
||||||
|
{disabled}
|
||||||
|
{label}
|
||||||
|
class={cn(
|
||||||
|
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:pointermove
|
||||||
|
on:focusin
|
||||||
|
>
|
||||||
|
<span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<SelectPrimitive.ItemIndicator>
|
||||||
|
<Check class="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
<slot />
|
||||||
|
</SelectPrimitive.Item>
|
16
src/lib/components/ui/select/select-label.svelte
Normal file
16
src/lib/components/ui/select/select-label.svelte
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.LabelProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SelectPrimitive.Label
|
||||||
|
class={cn("px-2 py-1.5 text-sm font-semibold", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</SelectPrimitive.Label>
|
14
src/lib/components/ui/select/select-separator.svelte
Normal file
14
src/lib/components/ui/select/select-separator.svelte
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.SeparatorProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SelectPrimitive.Separator
|
||||||
|
class={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
24
src/lib/components/ui/select/select-trigger.svelte
Normal file
24
src/lib/components/ui/select/select-trigger.svelte
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
import { CaretSort } from "radix-icons-svelte";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.TriggerProps;
|
||||||
|
type $$Events = SelectPrimitive.TriggerEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SelectPrimitive.Trigger
|
||||||
|
class={cn(
|
||||||
|
"flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<div>
|
||||||
|
<CaretSort class="h-4 w-4 opacity-50" />
|
||||||
|
</div>
|
||||||
|
</SelectPrimitive.Trigger>
|
7
src/lib/components/ui/separator/index.ts
Normal file
7
src/lib/components/ui/separator/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Root from "./separator.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Separator
|
||||||
|
};
|
22
src/lib/components/ui/separator/separator.svelte
Normal file
22
src/lib/components/ui/separator/separator.svelte
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Separator as SeparatorPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = SeparatorPrimitive.Props;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let orientation: $$Props["orientation"] = "horizontal";
|
||||||
|
export let decorative: $$Props["decorative"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SeparatorPrimitive.Root
|
||||||
|
class={cn(
|
||||||
|
"shrink-0 bg-border",
|
||||||
|
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{orientation}
|
||||||
|
{decorative}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
7
src/lib/components/ui/skeleton/index.ts
Normal file
7
src/lib/components/ui/skeleton/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Root from "./skeleton.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Skeleton
|
||||||
|
};
|
14
src/lib/components/ui/skeleton/skeleton.svelte
Normal file
14
src/lib/components/ui/skeleton/skeleton.svelte
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class={cn("animate-pulse rounded-md bg-primary/10", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
12
src/lib/components_custom/Button.svelte
Normal file
12
src/lib/components_custom/Button.svelte
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import UserSettingsStore from '$lib/stores/UserSettingsStore';
|
||||||
|
import { themes } from '$lib/types/themes';
|
||||||
|
|
||||||
|
let {children, onclick} = $props()
|
||||||
|
|
||||||
|
let themeId = $derived($UserSettingsStore.themeId)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button {onclick} class="border-2 border-{themes[themeId].primaryAction} hover:border-{themes[themeId].secondaryAction}">{@render children()}</button>
|
2
src/lib/components_custom/consts.ts
Normal file
2
src/lib/components_custom/consts.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export const apiBaseUrl = 'https://www.chellaris.net/api';
|
||||||
|
export const MACHINE_GROUP_ID = 12;
|
6
src/lib/stores/UserSettingsStore.ts
Normal file
6
src/lib/stores/UserSettingsStore.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { writable, type Writable } from "svelte/store";
|
||||||
|
import { UserSettings } from '$lib/types/userSettings';
|
||||||
|
|
||||||
|
const UserSettingsStore: Writable<UserSettings> = writable(new UserSettings());
|
||||||
|
|
||||||
|
export default UserSettingsStore;
|
27
src/lib/types/themes.ts
Normal file
27
src/lib/types/themes.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
export type Theme = {
|
||||||
|
backgroundColor: string,
|
||||||
|
textColor: string,
|
||||||
|
primaryAction: string,
|
||||||
|
secondaryAction: string,
|
||||||
|
}
|
||||||
|
const lightTheme = {
|
||||||
|
backgroundColor: "slate-50",
|
||||||
|
textColor: "slate-950",
|
||||||
|
primaryAction: "sky-300",
|
||||||
|
secondaryAction: "sky-600",
|
||||||
|
}
|
||||||
|
|
||||||
|
const darkTheme = {
|
||||||
|
backgroundColor: "slate-950",
|
||||||
|
textColor: "slate-50",
|
||||||
|
primaryAction: "sky-300",
|
||||||
|
secondaryAction: "sky-600",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const themes = [
|
||||||
|
lightTheme,
|
||||||
|
darkTheme
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
8
src/lib/types/userSettings.ts
Normal file
8
src/lib/types/userSettings.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export class UserSettings {
|
||||||
|
themeId: number
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.themeId = 1 // DEBUG
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
62
src/lib/utils.ts
Normal file
62
src/lib/utils.ts
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import { type ClassValue, clsx } from "clsx";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
import { cubicOut } from "svelte/easing";
|
||||||
|
import type { TransitionConfig } from "svelte/transition";
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs));
|
||||||
|
}
|
||||||
|
|
||||||
|
type FlyAndScaleParams = {
|
||||||
|
y?: number;
|
||||||
|
x?: number;
|
||||||
|
start?: number;
|
||||||
|
duration?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const flyAndScale = (
|
||||||
|
node: Element,
|
||||||
|
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
|
||||||
|
): TransitionConfig => {
|
||||||
|
const style = getComputedStyle(node);
|
||||||
|
const transform = style.transform === "none" ? "" : style.transform;
|
||||||
|
|
||||||
|
const scaleConversion = (
|
||||||
|
valueA: number,
|
||||||
|
scaleA: [number, number],
|
||||||
|
scaleB: [number, number]
|
||||||
|
) => {
|
||||||
|
const [minA, maxA] = scaleA;
|
||||||
|
const [minB, maxB] = scaleB;
|
||||||
|
|
||||||
|
const percentage = (valueA - minA) / (maxA - minA);
|
||||||
|
const valueB = percentage * (maxB - minB) + minB;
|
||||||
|
|
||||||
|
return valueB;
|
||||||
|
};
|
||||||
|
|
||||||
|
const styleToString = (
|
||||||
|
style: Record<string, number | string | undefined>
|
||||||
|
): string => {
|
||||||
|
return Object.keys(style).reduce((str, key) => {
|
||||||
|
if (style[key] === undefined) return str;
|
||||||
|
return str + `${key}:${style[key]};`;
|
||||||
|
}, "");
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
duration: params.duration ?? 200,
|
||||||
|
delay: 0,
|
||||||
|
css: (t) => {
|
||||||
|
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
|
||||||
|
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
|
||||||
|
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
|
||||||
|
|
||||||
|
return styleToString({
|
||||||
|
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
|
||||||
|
opacity: t
|
||||||
|
});
|
||||||
|
},
|
||||||
|
easing: cubicOut
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,18 +1,24 @@
|
||||||
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '../app.postcss';
|
import '../app.postcss';
|
||||||
|
import { browser } from '$app/environment';
|
||||||
import { Modal, autoModeWatcher, type ModalComponent, getModalStore, type ModalSettings, initializeStores } from '@skeletonlabs/skeleton';
|
import { writable } from 'svelte/store';
|
||||||
import { apiBaseUrl } from '$lib/components/consts';
|
import { themes } from '$lib/types/themes'
|
||||||
|
import { apiBaseUrl } from '$lib/components_custom/consts';
|
||||||
import { LeanChellarisDataStore } from '$lib/stores/ChellarisData';
|
import { LeanChellarisDataStore } from '$lib/stores/ChellarisData';
|
||||||
import Header from './Header.svelte';
|
import Header from './Header.svelte';
|
||||||
import { AppShell } from '@skeletonlabs/skeleton';
|
|
||||||
import Settings from './Settings.svelte';
|
import Settings from './Settings.svelte';
|
||||||
import AdminSelectedGameStore from '$lib/stores/admin-page/GameStore';
|
import AdminSelectedGameStore from '$lib/stores/admin-page/GameStore';
|
||||||
import type { ChellarisGameInfo } from '$lib/types/chellaris';
|
import type { ChellarisGameInfo } from '$lib/types/chellaris';
|
||||||
|
import UserSettingsStore from '$lib/stores/UserSettingsStore';
|
||||||
|
import AuthTokenStore from '$lib/stores/AuthTokenStore';
|
||||||
|
|
||||||
initializeStores();
|
if (browser) {
|
||||||
|
$AuthTokenStore = document.cookie.split("=")[document.cookie.split("=").length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
$: {
|
/* $: {
|
||||||
fetch(apiBaseUrl + '/v3/ethics').then((res) => {
|
fetch(apiBaseUrl + '/v3/ethics').then((res) => {
|
||||||
res.json().then((data) => {
|
res.json().then((data) => {
|
||||||
$LeanChellarisDataStore.ethics = data.ethics;
|
$LeanChellarisDataStore.ethics = data.ethics;
|
||||||
|
@ -33,33 +39,16 @@
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const modalComponentRegistry: Record<string, ModalComponent> = {
|
|
||||||
settingsModal: {
|
|
||||||
ref: Settings,
|
|
||||||
props: { background: 'bg-red-500'}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>{@html `<script>${autoModeWatcher.toString()} autoModeWatcher();</script>`}</svelte:head>
|
<Header />
|
||||||
|
<div class="m-4 border-2 border-accent rounded-lg h-[calc(100%-5.75rem-1px)]">
|
||||||
<Modal components={modalComponentRegistry}/>
|
|
||||||
|
|
||||||
<AppShell regionPage="relative">
|
|
||||||
<svelte:fragment slot="header">
|
|
||||||
<Header/>
|
|
||||||
</svelte:fragment>
|
|
||||||
<!-- (sidebarLeft) -->
|
|
||||||
<!-- (sidebarRight) -->
|
|
||||||
<!-- <svelte:fragment slot="pageHeader">Page Header</svelte:fragment> -->
|
|
||||||
<!-- Router Slot -->
|
|
||||||
<slot />
|
<slot />
|
||||||
<!-- ---- / ---- -->
|
</div>
|
||||||
<!-- (pageFooter) -->
|
<!-- Router Slot -->
|
||||||
<!-- (footer) -->
|
<!-- ---- / ---- -->
|
||||||
</AppShell>
|
<!-- (pageFooter) -->
|
||||||
|
<!-- (footer) -->
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
<!-- YOU CAN DELETE EVERYTHING IN THIS PAGE -->
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
<div class="container h-full mx-auto flex justify-center items-center">
|
<script lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Home</title>
|
||||||
|
<meta name="description" content="Landing Page for the Chellaris Multiplayer Group" />
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="container py-2 h-full mx-auto flex flex-col justify-center items-center">
|
||||||
|
<h1>Chellaris</h1>
|
||||||
<div class="space-y-5">
|
<div class="space-y-5">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a class="hover:text-primary-500" href="/graphs">Graphs</a>
|
<a class="hover:text-primary-500" href="/current">Current Game</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="hover:text-primary-500" href="/legacy-graphs">Game 15 Graphs</a>
|
<a class="hover:text-primary-500" href="/archive/1">Previous Game</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,55 +1,194 @@
|
||||||
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import discord from '$lib/images/discord.svg';
|
import discord from '$lib/images/discord.svg';
|
||||||
import { AppBar, LightSwitch, TabAnchor, TabGroup, getModalStore, type ModalSettings } from '@skeletonlabs/skeleton';
|
import AuthTokenStore from '$lib/stores/AuthTokenStore';
|
||||||
import Settings from './Settings.svelte';
|
import { Exit, EyeClosed, EyeOpen } from 'radix-icons-svelte';
|
||||||
import Button from '$lib/components/Button.svelte';
|
import { Button } from '$lib/components/ui/button';
|
||||||
|
import { Separator } from '$lib/components/ui/separator';
|
||||||
|
import { Input } from '$lib/components/ui/input';
|
||||||
|
import * as Popover from '$lib/components/ui/popover';
|
||||||
|
import * as Avatar from '$lib/components/ui/avatar';
|
||||||
|
|
||||||
let showSettings = false;
|
type User = {
|
||||||
|
token: string,
|
||||||
const modalStore = getModalStore();
|
tokenVisible: boolean,
|
||||||
|
discord: string | undefined,
|
||||||
const openSettings = () => {
|
picture: string | undefined,
|
||||||
const settings: ModalSettings = {
|
admin: boolean
|
||||||
type: 'component',
|
|
||||||
component: 'settingsModal'
|
|
||||||
};
|
|
||||||
modalStore.trigger(settings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let user: User | undefined = $state(undefined);
|
||||||
|
|
||||||
|
function handleLogout() {
|
||||||
|
$AuthTokenStore = ""
|
||||||
|
document.cookie = "authToken=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/"
|
||||||
|
user = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleLogin() {
|
||||||
|
// pretend we are handling the login via a fetch
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||||
|
let ret = {
|
||||||
|
token: $AuthTokenStore,
|
||||||
|
discord: "neshura",
|
||||||
|
picture: "/avatar.png",
|
||||||
|
admin: true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
const d = new Date();
|
||||||
|
let authExpiryDays = 14
|
||||||
|
d.setTime(d.getTime() + (authExpiryDays*24*60*60*1000));
|
||||||
|
document.cookie = "authToken=" + ret.token + "; expires=" + d.toUTCString() + "; path=/";
|
||||||
|
|
||||||
|
user = {
|
||||||
|
token: ret.token,
|
||||||
|
tokenVisible: false,
|
||||||
|
discord: ret.discord ?? undefined,
|
||||||
|
picture: ret.picture ?? undefined,
|
||||||
|
admin: ret.admin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// handle login failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($AuthTokenStore != "") {
|
||||||
|
handleLogin()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AppBar gridColumns="grid-cols-3" slotDefault="place-self-center" slotTrail="place-content-end">
|
<div class="flex gap-2 items-center justify-center py-3 bg-primary-foreground">
|
||||||
<svelte:fragment slot="lead">
|
<!-- spacer -->
|
||||||
<p />
|
<Button
|
||||||
</svelte:fragment>
|
variant="link"
|
||||||
<TabGroup
|
href="https://discord.gg/invite/BYNeHaPNh9"
|
||||||
padding="px-4 py-2"
|
target="_blank"
|
||||||
justify="justify-center"
|
rel="noopener noreferrer"
|
||||||
rounded="rounded-tr-xl rounded-tl-xl"
|
class="h-8 w-8 items-center flex"
|
||||||
border="border-b-2 border-primary-500"
|
>
|
||||||
active="variant-glass-primary hover:variant-ghost-primary"
|
<Avatar.Root class="h-6 w-6">
|
||||||
hover="hover:variant-ghost-primary"
|
<Avatar.Image src={discord} alt="DC" />
|
||||||
>
|
<Avatar.Fallback>US</Avatar.Fallback>
|
||||||
<!--<div aria-current={$page.url.pathname.startsWith('/sign-up') ? 'page' : undefined}>
|
</Avatar.Root>
|
||||||
<a href="/sign-up">Empire Sign-Up</a>
|
</Button>
|
||||||
</div>-->
|
<Button
|
||||||
<TabAnchor class="mr-1" href="/" selected={$page.url.pathname === '/'}>Home</TabAnchor>
|
variant="ghost"
|
||||||
<TabAnchor class="mx-1" href="/graphs" selected={$page.url.pathname.startsWith('/graphs')}>Graphs</TabAnchor>
|
href="/"
|
||||||
<TabAnchor class="mx-1" href="/legacy-graphs" selected={$page.url.pathname === '/legacy-graphs'}>Game 15 Graphs</TabAnchor>
|
class="{$page.url.pathname === '/' ? 'text-accent-foreground bg-accent' : ''}"
|
||||||
<TabAnchor class="mx-1" href="/admin" selected={$page.url.pathname === '/admin'}>Admin Menu</TabAnchor>
|
>
|
||||||
<TabAnchor class="ml-1" href="/about" selected={$page.url.pathname === '/about'}>About</TabAnchor>
|
Home
|
||||||
</TabGroup>
|
</Button>
|
||||||
|
<Button
|
||||||
<svelte:fragment slot="trail">
|
variant="ghost"
|
||||||
<Button text="Settings" action={openSettings} />
|
href="/current"
|
||||||
<LightSwitch />
|
class="{$page.url.pathname === '/current' ? 'text-accent-foreground bg-accent' : ''}"
|
||||||
<div>
|
>
|
||||||
<!-- Logo -->
|
Game [Current Game]
|
||||||
<a class="lg:!ml-0 w-[32px] lg:w-auto overflow-hidden" href="https://discord.gg/invite/BYNeHaPNh9" target="_blank" rel="noopener noreferrer">
|
</Button>
|
||||||
<img width="32px" height="32px" src={discord} alt="Discord" />
|
<Button
|
||||||
</a>
|
variant="ghost"
|
||||||
</div>
|
href="/archive"
|
||||||
</svelte:fragment>
|
class="{$page.url.pathname.startsWith('/archive') ? 'text-accent-foreground bg-accent' : ''}"
|
||||||
</AppBar>
|
>
|
||||||
<div />
|
Archives
|
||||||
|
</Button>
|
||||||
|
{#if user !== undefined && user.admin}
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
href="/admin"
|
||||||
|
class="{$page.url.pathname === '/admin' ? 'text-accent-foreground bg-accent' : ''}"
|
||||||
|
>
|
||||||
|
Admin
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
href="/admin/new"
|
||||||
|
class="{$page.url.pathname === '/admin/new' ? 'text-accent-foreground bg-accent' : ''}"
|
||||||
|
>
|
||||||
|
Admin (New)
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
{#if user !== undefined}
|
||||||
|
<Popover.Root>
|
||||||
|
<Popover.Trigger>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
class="relative h-8 w-8 rounded-full align-middle"
|
||||||
|
>
|
||||||
|
<Avatar.Root class="h-8 w-8">
|
||||||
|
<Avatar.Image src={user.picture} alt="@user" />
|
||||||
|
<Avatar.Fallback>US</Avatar.Fallback>
|
||||||
|
</Avatar.Root>
|
||||||
|
</Button>
|
||||||
|
</Popover.Trigger>
|
||||||
|
<Popover.Content class="w-56 p-0">
|
||||||
|
<div class="w-full p-1">
|
||||||
|
<div class="px-2 py-1.5 font-normal">
|
||||||
|
<div class="flex flex-row items-center gap-1">
|
||||||
|
{#if user.tokenVisible}
|
||||||
|
<p class="text-sm font-medium leading-none w-12">{user.token}</p> <!--Make the UserToken hidden by default-->
|
||||||
|
{:else}
|
||||||
|
<p class="text-sm font-medium leading-none w-12">******</p>
|
||||||
|
{/if}
|
||||||
|
<Button variant="ghost" size="sm" class="p-0 h-2 justify-start" on:click={() => {if (user !== undefined) user.tokenVisible = !user.tokenVisible}}>
|
||||||
|
{#if user.tokenVisible}
|
||||||
|
<EyeOpen />
|
||||||
|
{:else}
|
||||||
|
<EyeClosed />
|
||||||
|
{/if}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{#if user.discord}
|
||||||
|
<p class="mt-1 text-xs leading-none text-muted-foreground">@{user.discord}</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Separator orientation="horizontal" />
|
||||||
|
<div class="w-full p-1">
|
||||||
|
<Button variant="ghost" class="justify-start h-8 px-2 py-1.5 text-sm w-full" href="/profile">
|
||||||
|
Profile
|
||||||
|
</Button>
|
||||||
|
<Button variant="ghost" class="justify-start h-8 px-2 py-1.5 text-sm w-full" href="/settings">
|
||||||
|
Settings
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Separator orientation="horizontal" />
|
||||||
|
<div class="w-full p-1">
|
||||||
|
<Button variant="ghost" class="flex flex-row items-center justify-start h-8 space-x-1 px-2 py-1.5 text-sm w-full" on:click={handleLogout}>
|
||||||
|
<p>Log out </p>
|
||||||
|
<Exit />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Root>
|
||||||
|
{:else}
|
||||||
|
<Popover.Root>
|
||||||
|
<Popover.Trigger>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
class="relative"
|
||||||
|
>
|
||||||
|
Log In
|
||||||
|
</Button>
|
||||||
|
</Popover.Trigger>
|
||||||
|
<Popover.Content class="w-40 p-1 ">
|
||||||
|
<form class="flex flex-col items-center gap-1" on:submit={handleLogin}>
|
||||||
|
<Input type="text" placeholder="User Token" bind:value={$AuthTokenStore} />
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<Button variant="link" class="flex flex-row items-center h-8 space-x-1 px-2 py-1.5 text-sm w-full text-muted-foreground" href="/sign-up" >
|
||||||
|
Sign Up
|
||||||
|
</Button>
|
||||||
|
<Button variant="secondary" class="justify-start h-8 px-2 py-1.5 text-sm w-full" type="submit">
|
||||||
|
Log In
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Root>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<Separator orientation="horizontal"></Separator>
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { browser } from "$app/environment";
|
import { browser } from "$app/environment";
|
||||||
import Button from "$lib/components/Button.svelte";
|
import Button from "$lib/components_custom/Button.svelte";
|
||||||
import AuthTokenStore from "$lib/stores/AuthTokenStore";
|
import AuthTokenStore from "$lib/stores/AuthTokenStore";
|
||||||
import { getModalStore } from "@skeletonlabs/skeleton";
|
|
||||||
import { fade, slide } from "svelte/transition";
|
import { fade, slide } from "svelte/transition";
|
||||||
|
|
||||||
const modalStore = getModalStore();
|
|
||||||
|
|
||||||
let showAuthSaved = false;
|
let showAuthSaved = false;
|
||||||
let showPlaceholder = true;
|
let showPlaceholder = true;
|
||||||
|
|
||||||
|
@ -32,7 +29,7 @@
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
console.log("submitted ", gameGroupSettings);
|
console.log("submitted ", gameGroupSettings);
|
||||||
document.cookie = "authToken=" + authToken;
|
document.cookie = "authToken=" + authToken;
|
||||||
modalStore.close();
|
// somehow close the modal
|
||||||
}
|
}
|
||||||
|
|
||||||
let gameGroupSettings: [] = [];
|
let gameGroupSettings: [] = [];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiBaseUrl } from "$lib/components/consts";
|
import { apiBaseUrl } from "$lib/components_custom/consts";
|
||||||
import { redirect } from "@sveltejs/kit";
|
import { redirect } from "@sveltejs/kit";
|
||||||
|
|
||||||
export async function load({ cookies }) {
|
export async function load({ cookies }) {
|
||||||
|
@ -9,7 +9,8 @@ export async function load({ cookies }) {
|
||||||
}
|
}
|
||||||
})).json();
|
})).json();
|
||||||
|
|
||||||
if (!auth.admin && !auth.moderator) {
|
/*if (!auth.admin && !auth.moderator) {
|
||||||
throw redirect(303, '/401');
|
throw redirect(303, '/401');
|
||||||
}
|
}*/
|
||||||
|
console.log("WARNING: Admin Auth Check is disabled! DO NOT USE IN PRODUCTION")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
import LoadingSpinnerLocal from '$lib/components/LoadingSpinnerLocal.svelte';
|
import LoadingSpinnerLocal from '$lib/components_custom/LoadingSpinnerLocal.svelte';
|
||||||
import { apiBaseUrl } from '$lib/components/consts';
|
import { apiBaseUrl } from '$lib/components_custom/consts';
|
||||||
import AuthTokenStore from '$lib/stores/AuthTokenStore';
|
import AuthTokenStore from '$lib/stores/AuthTokenStore';
|
||||||
import AdminSelectedEmpireStore from '$lib/stores/admin-page/EmpireStore';
|
import AdminSelectedEmpireStore from '$lib/stores/admin-page/EmpireStore';
|
||||||
import AdminSelectedGameStore from '$lib/stores/admin-page/GameStore';
|
import AdminSelectedGameStore from '$lib/stores/admin-page/GameStore';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { apiBaseUrl } from "$lib/components/consts";
|
import { apiBaseUrl } from "$lib/components_custom/consts";
|
||||||
import AdminSelectedEmpireStore from "$lib/stores/admin-page/EmpireStore";
|
import AdminSelectedEmpireStore from "$lib/stores/admin-page/EmpireStore";
|
||||||
import AdminSelectedGameStore from "$lib/stores/admin-page/GameStore";
|
import AdminSelectedGameStore from "$lib/stores/admin-page/GameStore";
|
||||||
import type { ChellarisGameInfo } from "$lib/types/chellaris";
|
import type { ChellarisGameInfo } from "$lib/types/chellaris";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import DropDown from '$lib/components/DropDown.svelte';
|
import DropDown from '$lib/components_custom/DropDown.svelte';
|
||||||
import DropDownElement from '$lib/components/DropDownElement.svelte';
|
import DropDownElement from '$lib/components_custom/DropDownElement.svelte';
|
||||||
import { MACHINE_GROUP_ID, apiBaseUrl } from '$lib/components/consts';
|
import { MACHINE_GROUP_ID, apiBaseUrl } from '$lib/components_custom/consts';
|
||||||
import { LeanChellarisDataStore } from '$lib/stores/ChellarisData';
|
import { LeanChellarisDataStore } from '$lib/stores/ChellarisData';
|
||||||
import type { ChellarisEmpire, ChellarisGameGroup } from '$lib/types/chellaris';
|
import type { ChellarisEmpire, ChellarisGameGroup } from '$lib/types/chellaris';
|
||||||
import type { EmpireEthic } from '$lib/types/stellaris';
|
import type { EmpireEthic } from '$lib/types/stellaris';
|
||||||
|
|
16
src/routes/admin/new/+page.server.ts
Normal file
16
src/routes/admin/new/+page.server.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { apiBaseUrl } from "$lib/components_custom/consts";
|
||||||
|
import { redirect } from "@sveltejs/kit";
|
||||||
|
|
||||||
|
export async function load({ cookies }) {
|
||||||
|
const auth = await (await fetch(apiBaseUrl + "/v3/auth", {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': cookies.get("authToken") || ""
|
||||||
|
}
|
||||||
|
})).json();
|
||||||
|
|
||||||
|
/*if (!auth.admin && !auth.moderator) {
|
||||||
|
throw redirect(303, '/401');
|
||||||
|
}*/
|
||||||
|
console.log("WARNING: Admin Auth Check is disabled! DO NOT USE IN PRODUCTION")
|
||||||
|
}
|
372
src/routes/admin/new/+page.svelte
Normal file
372
src/routes/admin/new/+page.svelte
Normal file
|
@ -0,0 +1,372 @@
|
||||||
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Separator } from '$lib/components/ui/separator';
|
||||||
|
import * as Collapsible from "$lib/components/ui/collapsible";
|
||||||
|
import { Button } from '$lib/components/ui/button';
|
||||||
|
import { CaretDown, CaretRight } from 'radix-icons-svelte';
|
||||||
|
import { Checkbox } from '$lib/components/ui/checkbox';
|
||||||
|
import { Label } from '$lib/components/ui/label';
|
||||||
|
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||||
|
import { range } from 'svelte-loading-spinners/utils';
|
||||||
|
import * as Select from '$lib/components/ui/select';
|
||||||
|
import AdminSelectedGameStore from '$lib/stores/admin-page/GameStore';
|
||||||
|
import AdminSelectedGroupStore from '$lib/stores/admin-page/GroupStore';
|
||||||
|
import AdminSelectedEmpireStore from '$lib/stores/admin-page/EmpireStore';
|
||||||
|
import {
|
||||||
|
type ChellarisEmpire,
|
||||||
|
type ChellarisGameGroup,
|
||||||
|
type ChellarisGameInfo,
|
||||||
|
createBlankEmpire
|
||||||
|
} from '$lib/types/chellaris';
|
||||||
|
import { apiBaseUrl } from '$lib/components_custom/consts';
|
||||||
|
|
||||||
|
// Dummy Data, Replace with API fetch
|
||||||
|
function defaultEmpires() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
name: "Test Empire 1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "Test Empire 2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultGroups() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
checked: false,
|
||||||
|
name: "Test Group 1",
|
||||||
|
empires: defaultEmpires()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
checked: false,
|
||||||
|
name: "Test Group 2",
|
||||||
|
empires: defaultEmpires()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
type Empire = {
|
||||||
|
id: number,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Group = {
|
||||||
|
id: number,
|
||||||
|
checked: boolean,
|
||||||
|
name: string,
|
||||||
|
empires: Array<Empire>
|
||||||
|
}
|
||||||
|
|
||||||
|
type Game = {
|
||||||
|
id: number,
|
||||||
|
checked: boolean,
|
||||||
|
name: string,
|
||||||
|
groups: Array<Group>
|
||||||
|
}
|
||||||
|
|
||||||
|
let games: Array<Game> = $state([
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
checked: false,
|
||||||
|
name: "Test 1",
|
||||||
|
groups: defaultGroups()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
checked: false,
|
||||||
|
name: "Test 2",
|
||||||
|
groups: defaultGroups()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
checked: false,
|
||||||
|
name: "Test 3",
|
||||||
|
groups: defaultGroups()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
checked: false,
|
||||||
|
name: "Test 4",
|
||||||
|
groups: defaultGroups()
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
let filteredGames = $derived(games.filter(game => game.checked))
|
||||||
|
let filteredGroups = $derived(filteredGames.flatMap(game => game.groups.filter(group => group.checked)))
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
console.log(games)
|
||||||
|
})
|
||||||
|
|
||||||
|
const modes = [
|
||||||
|
{ value: "Game", label: "Games" },
|
||||||
|
{ value: "Group", label: "Groups" },
|
||||||
|
{ value: "Empire", label: "Empires" },
|
||||||
|
{ value: "Ethic", label: "Ethics" },
|
||||||
|
{ value: "Portrait", label: "Portraits" },
|
||||||
|
{ value: "User", label: "Users" }
|
||||||
|
];
|
||||||
|
|
||||||
|
let modeSelect = $state(modes[0]);
|
||||||
|
|
||||||
|
// Helper Function
|
||||||
|
|
||||||
|
function newGame() {
|
||||||
|
let newGame = {
|
||||||
|
id: games.length,
|
||||||
|
checked: false,
|
||||||
|
name: `Test ${games.length + 1}`,
|
||||||
|
groups: defaultGroups()
|
||||||
|
}
|
||||||
|
return newGame
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="h-full grid grid-cols-5">
|
||||||
|
<div class="pt-4 px-2 flex flex-col items-center border-r-2 border-accent gap-2">
|
||||||
|
<div class="flex flex-row gap-2">
|
||||||
|
<h2 class="self-center">
|
||||||
|
Editing
|
||||||
|
</h2>
|
||||||
|
<Select.Root bind:selected={modeSelect}>
|
||||||
|
<Select.Trigger class="w-28">
|
||||||
|
<Select.Value />
|
||||||
|
</Select.Trigger>
|
||||||
|
<Select.Content>
|
||||||
|
<Select.Group>
|
||||||
|
{#each modes as mode}
|
||||||
|
<Select.Item value={mode.value} label={mode.label}>
|
||||||
|
{mode.label}
|
||||||
|
</Select.Item>
|
||||||
|
{/each}
|
||||||
|
</Select.Group>
|
||||||
|
</Select.Content>
|
||||||
|
<Select.Input name="modeSelect" />
|
||||||
|
</Select.Root>
|
||||||
|
</div>
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
<h2>{modeSelect.value} Filters</h2>
|
||||||
|
{#if modeSelect.value == modes[0].value}
|
||||||
|
|
||||||
|
{:else if modeSelect.value == modes[1].value}
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
<Collapsible.Root class="w-[90%] space-y-2">
|
||||||
|
<Collapsible.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
||||||
|
{#if builder["data-state"] == "open"}
|
||||||
|
<CaretDown />
|
||||||
|
{:else}
|
||||||
|
<CaretRight />
|
||||||
|
{/if}
|
||||||
|
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
||||||
|
Games
|
||||||
|
</h4>
|
||||||
|
</Button>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content class="space-y-2">
|
||||||
|
{#each games as game}
|
||||||
|
<div class="pl-4 flex items-center space-x-2">
|
||||||
|
<Checkbox id="{game.id.toString()}" checked={game.checked} on:click={() => game.checked = !game.checked} />
|
||||||
|
<Label
|
||||||
|
for="{game.id.toString()}"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
{game.name}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
{:else if modeSelect.value == modes[2].value}
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
<Collapsible.Root class="w-[90%] space-y-2">
|
||||||
|
<Collapsible.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
||||||
|
{#if builder["data-state"] == "open"}
|
||||||
|
<CaretDown />
|
||||||
|
{:else}
|
||||||
|
<CaretRight />
|
||||||
|
{/if}
|
||||||
|
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
||||||
|
Games
|
||||||
|
</h4>
|
||||||
|
</Button>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content class="space-y-2">
|
||||||
|
{#each games as game}
|
||||||
|
<div class="pl-4 flex items-center space-x-2">
|
||||||
|
<Checkbox id="{game.id.toString()}" checked={game.checked} on:click={() => game.checked = !game.checked} />
|
||||||
|
<Label
|
||||||
|
for="{game.id.toString()}"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
{game.name}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Collapsible.Root class="w-[90%] space-y-2">
|
||||||
|
<Collapsible.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
||||||
|
{#if builder["data-state"] == "open"}
|
||||||
|
<CaretDown />
|
||||||
|
{:else}
|
||||||
|
<CaretRight />
|
||||||
|
{/if}
|
||||||
|
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
||||||
|
Groups
|
||||||
|
</h4>
|
||||||
|
</Button>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content class="space-y-2">
|
||||||
|
{#if games.filter(value => value.checked == true).length == 0}
|
||||||
|
<div class="pl-4 flex flex-col items-center space-x-2 text-muted-foreground">
|
||||||
|
<Label class="text-center" >No Games Selected</Label>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#each games as game}
|
||||||
|
{#if game.checked}
|
||||||
|
{#each game.groups as group}
|
||||||
|
<div class="pl-4 flex items-center space-x-2">
|
||||||
|
<Checkbox id="{game.id}-{group.id}" checked={group.checked} on:click={() => {games[game.id].groups[group.id].checked = !group.checked}} />
|
||||||
|
<Label
|
||||||
|
for="{game.id}-{group.id}"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
{game.name} {group.name}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
{:else if modeSelect.value == modes[3].value}
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
<Collapsible.Root class="w-[90%] space-y-2">
|
||||||
|
<Collapsible.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
||||||
|
{#if builder["data-state"] == "open"}
|
||||||
|
<CaretDown />
|
||||||
|
{:else}
|
||||||
|
<CaretRight />
|
||||||
|
{/if}
|
||||||
|
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
||||||
|
Games
|
||||||
|
</h4>
|
||||||
|
</Button>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content class="space-y-2">
|
||||||
|
{#each games as game}
|
||||||
|
<div class="pl-4 flex items-center space-x-2">
|
||||||
|
<Checkbox id="{game.id.toString()}" checked={game.checked} on:click={() => game.checked = !game.checked} />
|
||||||
|
<Label
|
||||||
|
for="{game.id.toString()}"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
{game.name}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
{:else if modeSelect.value == modes[4].value}
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
<Collapsible.Root class="w-[90%] space-y-2">
|
||||||
|
<Collapsible.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
||||||
|
{#if builder["data-state"] == "open"}
|
||||||
|
<CaretDown />
|
||||||
|
{:else}
|
||||||
|
<CaretRight />
|
||||||
|
{/if}
|
||||||
|
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
||||||
|
Games
|
||||||
|
</h4>
|
||||||
|
</Button>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content class="space-y-2">
|
||||||
|
{#each games as game}
|
||||||
|
<div class="pl-4 flex items-center space-x-2">
|
||||||
|
<Checkbox id="{game.id.toString()}" checked={game.checked} on:click={() => game.checked = !game.checked} />
|
||||||
|
<Label
|
||||||
|
for="{game.id.toString()}"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
{game.name}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="pt-6 px-3 flex flex-col col-span-2 items-center border-r-2 border-accent text-center text-muted-foreground gap-2 overflow-y-scroll">
|
||||||
|
{#if modeSelect.value == modes[0].value}
|
||||||
|
{#each games as game}
|
||||||
|
<!--<Skeleton class="h-12 w-[90%]" />-->
|
||||||
|
<div class="px-6 h-12 w-[90%] flex flex-row items-center border-2 rounded-md bg-primary/10">
|
||||||
|
<p class="text-primary">{game.name}</p>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
No Content
|
||||||
|
{/each}
|
||||||
|
<Button
|
||||||
|
class="px-6 h-12 w-[90%] flex flex-row items-center border-2 rounded-md bg-primary/10 text-primary hover:bg-primary/5"
|
||||||
|
on:click={() => {games.push(newGame())}}
|
||||||
|
>
|
||||||
|
Add Game
|
||||||
|
</Button>
|
||||||
|
{:else if modeSelect.value == modes[1].value}
|
||||||
|
{#each filteredGames as game}
|
||||||
|
{#each game.groups as group}
|
||||||
|
<Skeleton class="h-12 w-[90%]" />
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
No Content
|
||||||
|
{/each}
|
||||||
|
<Button>Add Group</Button>
|
||||||
|
{:else if modeSelect.value == modes[2].value}
|
||||||
|
{console.log(filteredGroups)}
|
||||||
|
{#each filteredGroups as group}
|
||||||
|
{#each group.empires as empire}
|
||||||
|
<Skeleton class="h-12 w-[90%]" />
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
No Content
|
||||||
|
{/each}
|
||||||
|
<Button>Add Empire</Button>
|
||||||
|
{:else if modeSelect.value == modes[3].value}
|
||||||
|
{#each filteredGames as game}
|
||||||
|
<Skeleton class="h-12 w-[90%]" />
|
||||||
|
{:else}
|
||||||
|
No Content
|
||||||
|
{/each}
|
||||||
|
<Button>Add Ethic</Button>
|
||||||
|
{:else if modeSelect.value == modes[4].value}
|
||||||
|
{#each filteredGames as game}
|
||||||
|
<Skeleton class="h-12 w-[90%]" />
|
||||||
|
{:else}
|
||||||
|
No Content
|
||||||
|
{/each}
|
||||||
|
<Button>Add Portrait</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="pt-6 px-3 flex flex-col col-span-2 text-center text-muted-foreground">
|
||||||
|
No Content
|
||||||
|
</div>
|
||||||
|
</div>
|
6
src/routes/archive/+page.svelte
Normal file
6
src/routes/archive/+page.svelte
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<script lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
PREVIOUS GAMES PAGE
|
||||||
|
</div>
|
8
src/routes/archive/[gameId]/+page.svelte
Normal file
8
src/routes/archive/[gameId]/+page.svelte
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { PageData } from './$types'
|
||||||
|
export let data: PageData;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
PREVIOUS GAME {data.gameId} PAGE
|
||||||
|
</div>
|
8
src/routes/archive/[gameId]/+page.ts
Normal file
8
src/routes/archive/[gameId]/+page.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
/** @type {import('./$types').PageLoad} */
|
||||||
|
export function load({ params }) {
|
||||||
|
return {
|
||||||
|
gameId: params.gameId
|
||||||
|
}
|
||||||
|
}
|
3
src/routes/current/+page.svelte
Normal file
3
src/routes/current/+page.svelte
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<div>
|
||||||
|
CURRENT GAME PAGE
|
||||||
|
</div>
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import SubNav from './SubNav.svelte';
|
import SubNav from './SubNav.svelte';
|
||||||
import '../../app.postcss';
|
import '../../../app.postcss';
|
||||||
import { goto } from "$app/navigation";
|
import { goto } from "$app/navigation";
|
||||||
import { page } from "$app/stores";
|
import { page } from "$app/stores";
|
||||||
import GraphsTabStore from '$lib/stores/GraphsTab';
|
import GraphsTabStore from '$lib/stores/GraphsTab';
|
|
@ -2,9 +2,9 @@ import ChellarisDataStore from '$lib/stores/ChellarisData';
|
||||||
import SelectedGameStore from '$lib/stores/GameFilter';
|
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||||
import SelectedGameGroupsStore, { type SelectedChellarisGroups } from "$lib/stores/GameGroupFilter";
|
import SelectedGameGroupsStore, { type SelectedChellarisGroups } from "$lib/stores/GameGroupFilter";
|
||||||
import GraphsTabStore from '$lib/stores/GraphsTab';
|
import GraphsTabStore from '$lib/stores/GraphsTab';
|
||||||
import type { LayoutLoad } from "./$types";
|
import type { LayoutLoad } from "../../../../.svelte-kit/types/src/routes";
|
||||||
import type { ChellarisInfo } from '../../lib/types/chellaris';
|
import type { ChellarisInfo } from '$lib/types/chellaris';
|
||||||
import { apiBaseUrl } from '$lib/components/consts';
|
import { apiBaseUrl } from '$lib/components_custom/consts';
|
||||||
|
|
||||||
export const load: LayoutLoad = async ({ fetch }) => {
|
export const load: LayoutLoad = async ({ fetch }) => {
|
||||||
let store: string | null;
|
let store: string | null;
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import DropDown from '$lib/components/DropDown.svelte';
|
import DropDown from '$lib/components_custom/DropDown.svelte';
|
||||||
import DropDownElement from '$lib/components/DropDownElement.svelte';
|
import DropDownElement from '$lib/components_custom/DropDownElement.svelte';
|
||||||
import SelectedGameGroupsStore from '$lib/stores/GameGroupFilter';
|
import SelectedGameGroupsStore from '$lib/stores/GameGroupFilter';
|
||||||
import SelectedGameStore from '$lib/stores/GameFilter';
|
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import DropDown from '$lib/components/DropDown.svelte';
|
import DropDown from '$lib/components_custom/DropDown.svelte';
|
||||||
import DropDownElement from '$lib/components/DropDownElement.svelte';
|
import DropDownElement from '$lib/components_custom/DropDownElement.svelte';
|
||||||
import SelectedGameStore from '$lib/stores/GameFilter';
|
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import type { ChellarisGameGroup, ChellarisInfo, ChellarisEmpire, ChellarisGame } from '$lib/types/chellaris';
|
import type { ChellarisGameGroup, ChellarisInfo, ChellarisEmpire, ChellarisGame } from '$lib/types/chellaris';
|
||||||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
||||||
import GraphsTabStore from '$lib/stores/GraphsTab';
|
import GraphsTabStore from '$lib/stores/GraphsTab';
|
||||||
import LoadingSpinner from '$lib/components/LoadingSpinner.svelte';
|
import LoadingSpinner from '$lib/components_custom/LoadingSpinner.svelte';
|
||||||
|
|
||||||
$: selectedGame = $ChellarisDataStore.games[$SelectedGameStore];
|
$: selectedGame = $ChellarisDataStore.games[$SelectedGameStore];
|
||||||
$: selectedGameGroupData = $SelectedGameGroupsStore[$SelectedGameStore];
|
$: selectedGameGroupData = $SelectedGameGroupsStore[$SelectedGameStore];
|
|
@ -3,7 +3,7 @@
|
||||||
import EthicsBar from './EthicsBar.svelte';
|
import EthicsBar from './EthicsBar.svelte';
|
||||||
import PopsPie from './PopsPie.svelte';
|
import PopsPie from './PopsPie.svelte';
|
||||||
import EmpireStats from './EmpireStats.svelte';
|
import EmpireStats from './EmpireStats.svelte';
|
||||||
import LoadingSpinner from '$lib/components/LoadingSpinner.svelte';
|
import LoadingSpinner from '$lib/components_custom/LoadingSpinner.svelte';
|
||||||
import { navigating } from '$app/stores';
|
import { navigating } from '$app/stores';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { apiBaseUrl } from "$lib/components/consts";
|
import { apiBaseUrl } from "$lib/components_custom/consts";
|
||||||
import type { PageLoad } from "../$types";
|
import type { PageLoad } from "../../../../.svelte-kit/types/src/routes";
|
||||||
|
|
||||||
export const load: PageLoad = async ({ fetch }) => {
|
export const load: PageLoad = async ({ fetch }) => {
|
||||||
const popsRet: { speciesArray: Array<number> } = await (await fetch(apiBaseUrl + '/v1/species')).json();
|
const popsRet: { speciesArray: Array<number> } = await (await fetch(apiBaseUrl + '/v1/species')).json();
|
10
src/routes/legacy/sign-up/+page.svelte
Normal file
10
src/routes/legacy/sign-up/+page.svelte
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<svelte:head>
|
||||||
|
<title>Empire Sign-Up</title>
|
||||||
|
<meta name="description" content="Empire Sign-Up" />
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="text-column">
|
||||||
|
<h1>Empire Sign-Up: Not yet implemented</h1>
|
||||||
|
|
||||||
|
<p>For now only Sign-Up statistics and the backend have been migrated.</p>
|
||||||
|
</div>
|
0
src/routes/profile/+page.svelte
Normal file
0
src/routes/profile/+page.svelte
Normal file
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue