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-*
|
||||
|
||||
/.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"
|
||||
}
|
||||
}
|
36
package.json
36
package.json
|
@ -9,40 +9,44 @@
|
|||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"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": {
|
||||
"@fontsource/fira-mono": "^4.5.10",
|
||||
"@neoconfetti/svelte": "^1.0.0",
|
||||
"@sveltejs/adapter-auto": "^2.0.0",
|
||||
"@sveltejs/kit": "^1.20.4",
|
||||
"@types/cookie": "^0.5.1",
|
||||
"@types/node": "^20.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||
"@typescript-eslint/parser": "^5.45.0",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-svelte": "^2.30.0",
|
||||
"postcss": "^8.4.29",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"prettier": "^2.8.0",
|
||||
"prettier-plugin-svelte": "^2.10.1",
|
||||
"svelte": "^4.0.5",
|
||||
"svelte": "^5.0.0-next.17",
|
||||
"svelte-check": "^3.4.3",
|
||||
"svelte-loading-spinners": "^0.3.4",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"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"
|
||||
"vite": "^4.4.2"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"bits-ui": "^0.11.6",
|
||||
"chart.js": "^4.3.3",
|
||||
"chartjs-plugin-datalabels": "^2.2.0",
|
||||
"svelte-chartjs": "^3.1.2"
|
||||
"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>
|
||||
<html lang="en" class="dark">
|
||||
<html lang="en" class="dark h-full">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover" data-theme="wintry">
|
||||
<div style="display: contents" class="h-screen overflow-hidden contents">%sveltekit.body%</div>
|
||||
<body class="h-full w-full" data-sveltekit-preload-data="hover">
|
||||
%sveltekit.body%
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,78 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@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">
|
||||
import '../app.postcss';
|
||||
|
||||
import { Modal, autoModeWatcher, type ModalComponent, getModalStore, type ModalSettings, initializeStores } from '@skeletonlabs/skeleton';
|
||||
import { apiBaseUrl } from '$lib/components/consts';
|
||||
import { browser } from '$app/environment';
|
||||
import { writable } from 'svelte/store';
|
||||
import { themes } from '$lib/types/themes'
|
||||
import { apiBaseUrl } from '$lib/components_custom/consts';
|
||||
import { LeanChellarisDataStore } from '$lib/stores/ChellarisData';
|
||||
import Header from './Header.svelte';
|
||||
import { AppShell } from '@skeletonlabs/skeleton';
|
||||
import Settings from './Settings.svelte';
|
||||
import AdminSelectedGameStore from '$lib/stores/admin-page/GameStore';
|
||||
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) => {
|
||||
res.json().then((data) => {
|
||||
$LeanChellarisDataStore.ethics = data.ethics;
|
||||
|
@ -33,33 +39,16 @@
|
|||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
const modalComponentRegistry: Record<string, ModalComponent> = {
|
||||
settingsModal: {
|
||||
ref: Settings,
|
||||
props: { background: 'bg-red-500'}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>{@html `<script>${autoModeWatcher.toString()} autoModeWatcher();</script>`}</svelte:head>
|
||||
|
||||
<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 -->
|
||||
<div class="m-4 border-2 border-accent rounded-lg h-[calc(100%-5.75rem-1px)]">
|
||||
<slot />
|
||||
</div>
|
||||
<!-- Router Slot -->
|
||||
<!-- ---- / ---- -->
|
||||
<!-- (pageFooter) -->
|
||||
<!-- (footer) -->
|
||||
</AppShell>
|
||||
|
||||
|
|
|
@ -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">
|
||||
<ul>
|
||||
<li>
|
||||
<a class="hover:text-primary-500" href="/graphs">Graphs</a>
|
||||
<a class="hover:text-primary-500" href="/current">Current Game</a>
|
||||
</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>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -1,55 +1,194 @@
|
|||
<svelte:options runes={true} />
|
||||
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import discord from '$lib/images/discord.svg';
|
||||
import { AppBar, LightSwitch, TabAnchor, TabGroup, getModalStore, type ModalSettings } from '@skeletonlabs/skeleton';
|
||||
import Settings from './Settings.svelte';
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import AuthTokenStore from '$lib/stores/AuthTokenStore';
|
||||
import { Exit, EyeClosed, EyeOpen } from 'radix-icons-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;
|
||||
|
||||
const modalStore = getModalStore();
|
||||
|
||||
const openSettings = () => {
|
||||
const settings: ModalSettings = {
|
||||
type: 'component',
|
||||
component: 'settingsModal'
|
||||
};
|
||||
modalStore.trigger(settings);
|
||||
type User = {
|
||||
token: string,
|
||||
tokenVisible: boolean,
|
||||
discord: string | undefined,
|
||||
picture: string | undefined,
|
||||
admin: boolean
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
<AppBar gridColumns="grid-cols-3" slotDefault="place-self-center" slotTrail="place-content-end">
|
||||
<svelte:fragment slot="lead">
|
||||
<p />
|
||||
</svelte:fragment>
|
||||
<TabGroup
|
||||
padding="px-4 py-2"
|
||||
justify="justify-center"
|
||||
rounded="rounded-tr-xl rounded-tl-xl"
|
||||
border="border-b-2 border-primary-500"
|
||||
active="variant-glass-primary hover:variant-ghost-primary"
|
||||
hover="hover:variant-ghost-primary"
|
||||
<div class="flex gap-2 items-center justify-center py-3 bg-primary-foreground">
|
||||
<!-- spacer -->
|
||||
<Button
|
||||
variant="link"
|
||||
href="https://discord.gg/invite/BYNeHaPNh9"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="h-8 w-8 items-center flex"
|
||||
>
|
||||
<!--<div aria-current={$page.url.pathname.startsWith('/sign-up') ? 'page' : undefined}>
|
||||
<a href="/sign-up">Empire Sign-Up</a>
|
||||
</div>-->
|
||||
<TabAnchor class="mr-1" href="/" selected={$page.url.pathname === '/'}>Home</TabAnchor>
|
||||
<TabAnchor class="mx-1" href="/graphs" selected={$page.url.pathname.startsWith('/graphs')}>Graphs</TabAnchor>
|
||||
<TabAnchor class="mx-1" href="/legacy-graphs" selected={$page.url.pathname === '/legacy-graphs'}>Game 15 Graphs</TabAnchor>
|
||||
<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>
|
||||
</TabGroup>
|
||||
|
||||
<svelte:fragment slot="trail">
|
||||
<Button text="Settings" action={openSettings} />
|
||||
<LightSwitch />
|
||||
<div>
|
||||
<!-- Logo -->
|
||||
<a class="lg:!ml-0 w-[32px] lg:w-auto overflow-hidden" href="https://discord.gg/invite/BYNeHaPNh9" target="_blank" rel="noopener noreferrer">
|
||||
<img width="32px" height="32px" src={discord} alt="Discord" />
|
||||
</a>
|
||||
<Avatar.Root class="h-6 w-6">
|
||||
<Avatar.Image src={discord} alt="DC" />
|
||||
<Avatar.Fallback>US</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
href="/"
|
||||
class="{$page.url.pathname === '/' ? 'text-accent-foreground bg-accent' : ''}"
|
||||
>
|
||||
Home
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
href="/current"
|
||||
class="{$page.url.pathname === '/current' ? 'text-accent-foreground bg-accent' : ''}"
|
||||
>
|
||||
Game [Current Game]
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
href="/archive"
|
||||
class="{$page.url.pathname.startsWith('/archive') ? 'text-accent-foreground bg-accent' : ''}"
|
||||
>
|
||||
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>
|
||||
</svelte:fragment>
|
||||
</AppBar>
|
||||
<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">
|
||||
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 { getModalStore } from "@skeletonlabs/skeleton";
|
||||
import { fade, slide } from "svelte/transition";
|
||||
|
||||
const modalStore = getModalStore();
|
||||
|
||||
let showAuthSaved = false;
|
||||
let showPlaceholder = true;
|
||||
|
||||
|
@ -32,7 +29,7 @@
|
|||
const handleSubmit = () => {
|
||||
console.log("submitted ", gameGroupSettings);
|
||||
document.cookie = "authToken=" + authToken;
|
||||
modalStore.close();
|
||||
// somehow close the modal
|
||||
}
|
||||
|
||||
let gameGroupSettings: [] = [];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { apiBaseUrl } from "$lib/components/consts";
|
||||
import { apiBaseUrl } from "$lib/components_custom/consts";
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
|
||||
export async function load({ cookies }) {
|
||||
|
@ -9,7 +9,8 @@ export async function load({ cookies }) {
|
|||
}
|
||||
})).json();
|
||||
|
||||
if (!auth.admin && !auth.moderator) {
|
||||
/*if (!auth.admin && !auth.moderator) {
|
||||
throw redirect(303, '/401');
|
||||
}
|
||||
}*/
|
||||
console.log("WARNING: Admin Auth Check is disabled! DO NOT USE IN PRODUCTION")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { browser } from '$app/environment';
|
||||
import LoadingSpinnerLocal from '$lib/components/LoadingSpinnerLocal.svelte';
|
||||
import { apiBaseUrl } from '$lib/components/consts';
|
||||
import LoadingSpinnerLocal from '$lib/components_custom/LoadingSpinnerLocal.svelte';
|
||||
import { apiBaseUrl } from '$lib/components_custom/consts';
|
||||
import AuthTokenStore from '$lib/stores/AuthTokenStore';
|
||||
import AdminSelectedEmpireStore from '$lib/stores/admin-page/EmpireStore';
|
||||
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 AdminSelectedGameStore from "$lib/stores/admin-page/GameStore";
|
||||
import type { ChellarisGameInfo } from "$lib/types/chellaris";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import DropDown from '$lib/components/DropDown.svelte';
|
||||
import DropDownElement from '$lib/components/DropDownElement.svelte';
|
||||
import { MACHINE_GROUP_ID, apiBaseUrl } from '$lib/components/consts';
|
||||
import DropDown from '$lib/components_custom/DropDown.svelte';
|
||||
import DropDownElement from '$lib/components_custom/DropDownElement.svelte';
|
||||
import { MACHINE_GROUP_ID, apiBaseUrl } from '$lib/components_custom/consts';
|
||||
import { LeanChellarisDataStore } from '$lib/stores/ChellarisData';
|
||||
import type { ChellarisEmpire, ChellarisGameGroup } from '$lib/types/chellaris';
|
||||
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">
|
||||
import SubNav from './SubNav.svelte';
|
||||
import '../../app.postcss';
|
||||
import '../../../app.postcss';
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/stores";
|
||||
import GraphsTabStore from '$lib/stores/GraphsTab';
|
|
@ -2,9 +2,9 @@ import ChellarisDataStore from '$lib/stores/ChellarisData';
|
|||
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||
import SelectedGameGroupsStore, { type SelectedChellarisGroups } from "$lib/stores/GameGroupFilter";
|
||||
import GraphsTabStore from '$lib/stores/GraphsTab';
|
||||
import type { LayoutLoad } from "./$types";
|
||||
import type { ChellarisInfo } from '../../lib/types/chellaris';
|
||||
import { apiBaseUrl } from '$lib/components/consts';
|
||||
import type { LayoutLoad } from "../../../../.svelte-kit/types/src/routes";
|
||||
import type { ChellarisInfo } from '$lib/types/chellaris';
|
||||
import { apiBaseUrl } from '$lib/components_custom/consts';
|
||||
|
||||
export const load: LayoutLoad = async ({ fetch }) => {
|
||||
let store: string | null;
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import DropDown from '$lib/components/DropDown.svelte';
|
||||
import DropDownElement from '$lib/components/DropDownElement.svelte';
|
||||
import DropDown from '$lib/components_custom/DropDown.svelte';
|
||||
import DropDownElement from '$lib/components_custom/DropDownElement.svelte';
|
||||
import SelectedGameGroupsStore from '$lib/stores/GameGroupFilter';
|
||||
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import DropDown from '$lib/components/DropDown.svelte';
|
||||
import DropDownElement from '$lib/components/DropDownElement.svelte';
|
||||
import DropDown from '$lib/components_custom/DropDown.svelte';
|
||||
import DropDownElement from '$lib/components_custom/DropDownElement.svelte';
|
||||
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
import type { ChellarisGameGroup, ChellarisInfo, ChellarisEmpire, ChellarisGame } from '$lib/types/chellaris';
|
||||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
||||
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];
|
||||
$: selectedGameGroupData = $SelectedGameGroupsStore[$SelectedGameStore];
|
|
@ -3,7 +3,7 @@
|
|||
import EthicsBar from './EthicsBar.svelte';
|
||||
import PopsPie from './PopsPie.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 { fade } from 'svelte/transition';
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { apiBaseUrl } from "$lib/components/consts";
|
||||
import type { PageLoad } from "../$types";
|
||||
import { apiBaseUrl } from "$lib/components_custom/consts";
|
||||
import type { PageLoad } from "../../../../.svelte-kit/types/src/routes";
|
||||
|
||||
export const load: PageLoad = async ({ fetch }) => {
|
||||
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