sec
This commit is contained in:
parent
739dafc2c1
commit
82d7d09818
@ -3,7 +3,10 @@
|
|||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
"printWidth": 100,
|
"printWidth": 100,
|
||||||
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
"plugins": [
|
||||||
|
"prettier-plugin-svelte",
|
||||||
|
"prettier-plugin-tailwindcss"
|
||||||
|
],
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": "*.svelte",
|
"files": "*.svelte",
|
||||||
|
1
.yarnrc.yml
Normal file
1
.yarnrc.yml
Normal file
@ -0,0 +1 @@
|
|||||||
|
nodeLinker: node-modules
|
@ -1,6 +1,6 @@
|
|||||||
# create-svelte
|
# sv
|
||||||
|
|
||||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
|
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
|
||||||
|
|
||||||
## Creating a project
|
## Creating a project
|
||||||
|
|
||||||
|
14
components.json
Normal file
14
components.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://shadcn-svelte.com/schema.json",
|
||||||
|
"style": "default",
|
||||||
|
"tailwind": {
|
||||||
|
"config": "tailwind.config.ts",
|
||||||
|
"css": "src/app.css",
|
||||||
|
"baseColor": "slate"
|
||||||
|
},
|
||||||
|
"aliases": {
|
||||||
|
"components": "$lib/components",
|
||||||
|
"utils": "$lib/utils"
|
||||||
|
},
|
||||||
|
"typescript": true
|
||||||
|
}
|
20
package.json
20
package.json
@ -12,20 +12,34 @@
|
|||||||
"lint": "prettier --check ."
|
"lint": "prettier --check ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@melt-ui/pp": "^0.3.2",
|
|
||||||
"@melt-ui/svelte": "^0.85.0",
|
|
||||||
"@sveltejs/adapter-auto": "^3.0.0",
|
"@sveltejs/adapter-auto": "^3.0.0",
|
||||||
"@sveltejs/kit": "^2.0.0",
|
"@sveltejs/kit": "^2.0.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
"@types/dompurify": "^3",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
|
"bits-ui": "^0.21.16",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"lucide-svelte": "^0.454.0",
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.2",
|
||||||
"prettier-plugin-svelte": "^3.2.6",
|
"prettier-plugin-svelte": "^3.2.6",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||||
"svelte": "^5.0.0",
|
"svelte": "^5.0.0",
|
||||||
"svelte-check": "^4.0.0",
|
"svelte-check": "^4.0.0",
|
||||||
|
"tailwind-merge": "^2.5.4",
|
||||||
|
"tailwind-variants": "^0.2.1",
|
||||||
"tailwindcss": "^3.4.9",
|
"tailwindcss": "^3.4.9",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^5.0.3"
|
"vite": "^5.0.3"
|
||||||
|
},
|
||||||
|
"packageManager": "yarn@4.2.2+sha224.1e50daf19e5e249a025569752c60b88005fddf57d10fcde5fc68b88f",
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify-json/mingcute": "^1.2.1",
|
||||||
|
"dompurify": "^3.1.7",
|
||||||
|
"highlight.js": "^11.10.0",
|
||||||
|
"isomorphic-dompurify": "^2.16.0",
|
||||||
|
"marked": "^14.1.3",
|
||||||
|
"marked-highlight": "^2.2.0",
|
||||||
|
"typescript-svelte-plugin": "^0.3.42",
|
||||||
|
"unplugin-icons": "^0.20.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
102
src/app.css
102
src/app.css
@ -1,16 +1,96 @@
|
|||||||
@import 'tailwindcss/base';
|
@tailwind base;
|
||||||
@import 'tailwindcss/components';
|
@tailwind components;
|
||||||
@import 'tailwindcss/utilities';
|
@tailwind utilities;
|
||||||
|
|
||||||
@import url('https://fonts.googleapis.com/css2?family=LXGW+WenKai+TC&display=swap');
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--background: 0 0% 100%;
|
||||||
|
--foreground: 224 71.4% 4.1%;
|
||||||
|
|
||||||
|
--muted: 220 14.3% 95.9%;
|
||||||
|
--muted-foreground: 220 8.9% 46.1%;
|
||||||
|
|
||||||
|
--popover: 0 0% 100%;
|
||||||
|
--popover-foreground: 224 71.4% 4.1%;
|
||||||
|
|
||||||
|
--card: 0 0% 100%;
|
||||||
|
--card-foreground: 224 71.4% 4.1%;
|
||||||
|
|
||||||
|
--border: 220 13% 91%;
|
||||||
|
--input: 220 13% 91%;
|
||||||
|
|
||||||
|
--primary: 33deg 43% 91%;
|
||||||
|
--primary-foreground: 210 20% 98%;
|
||||||
|
|
||||||
|
--secondary: 220 14.3% 95.9%;
|
||||||
|
--secondary-foreground: 220.9 39.3% 11%;
|
||||||
|
|
||||||
|
--accent: 220 14.3% 95.9%;
|
||||||
|
--accent-foreground: 220.9 39.3% 11%;
|
||||||
|
|
||||||
|
--destructive: 0 72.2% 50.6%;
|
||||||
|
--destructive-foreground: 210 20% 98%;
|
||||||
|
|
||||||
|
--ring: 224 71.4% 4.1%;
|
||||||
|
|
||||||
|
--radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
--background: 249 22% 12%;
|
||||||
|
--foreground: 245 50% 91%;
|
||||||
|
|
||||||
|
--muted: 215 27.9% 16.9%;
|
||||||
|
--muted-foreground: 217.9 10.6% 64.9%;
|
||||||
|
|
||||||
|
--popover: 224 71.4% 4.1%;
|
||||||
|
--popover-foreground: 210 20% 98%;
|
||||||
|
|
||||||
|
--card: 35 88% 72%;
|
||||||
|
--card-foreground: 248 13% 36%;
|
||||||
|
|
||||||
|
--border: 215 27.9% 16.9%;
|
||||||
|
--input: 215 27.9% 16.9%;
|
||||||
|
|
||||||
|
--primary: 248deg 25% 18%;
|
||||||
|
--primary-foreground: 248deg 15% 61%;
|
||||||
|
|
||||||
|
--secondary: 249deg 15% 28%;
|
||||||
|
--secondary-foreground: 210 20% 98%;
|
||||||
|
|
||||||
|
--accent: 215 27.9% 16.9%;
|
||||||
|
--accent-foreground: 210 20% 98%;
|
||||||
|
|
||||||
|
--destructive: 0 62.8% 30.6%;
|
||||||
|
--destructive-foreground: 210 20% 98%;
|
||||||
|
|
||||||
|
--ring: 216 12.2% 83.9%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
* {
|
||||||
|
@apply border-border;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
display:block;
|
@apply bg-background text-foreground;
|
||||||
margin:0px;
|
}
|
||||||
width:100dvw;
|
}
|
||||||
min-height: 100dvh;
|
|
||||||
font-family: "LXGW WenKai TC", cursive;
|
@media (prefers-color-scheme: dark) {
|
||||||
font-weight: 400;
|
body {
|
||||||
font-style: normal;
|
@apply dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "GenRyuMin2TW";
|
||||||
|
src:
|
||||||
|
url("/GenRyuMin2TW-M.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "GenRyuMin2TW";
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
1
src/app.d.ts
vendored
1
src/app.d.ts
vendored
@ -1,5 +1,6 @@
|
|||||||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||||
// for information about these interfaces
|
// for information about these interfaces
|
||||||
|
import 'unplugin-icons/types/svelte'
|
||||||
declare global {
|
declare global {
|
||||||
namespace App {
|
namespace App {
|
||||||
// interface Error {}
|
// interface Error {}
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body data-sveltekit-preload-data="hover">
|
<body data-sveltekit-preload-data="hover">
|
||||||
<div style="display: contents">
|
<div style="display: contents">%sveltekit.body%</div>
|
||||||
%sveltekit.body%
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
36
src/lib/components/ui/dialog/dialog-content.svelte
Normal file
36
src/lib/components/ui/dialog/dialog-content.svelte
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
import X from "lucide-svelte/icons/x";
|
||||||
|
import * as Dialog from "./index.js";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = DialogPrimitive.ContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
|
duration: 200,
|
||||||
|
};
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Dialog.Portal>
|
||||||
|
<Dialog.Overlay />
|
||||||
|
<DialogPrimitive.Content
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
class={cn(
|
||||||
|
"bg-background fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg sm:rounded-lg md:w-full",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<DialogPrimitive.Close
|
||||||
|
class="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none"
|
||||||
|
>
|
||||||
|
<X class="h-4 w-4" />
|
||||||
|
<span class="sr-only">Close</span>
|
||||||
|
</DialogPrimitive.Close>
|
||||||
|
</DialogPrimitive.Content>
|
||||||
|
</Dialog.Portal>
|
16
src/lib/components/ui/dialog/dialog-description.svelte
Normal file
16
src/lib/components/ui/dialog/dialog-description.svelte
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = DialogPrimitive.DescriptionProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DialogPrimitive.Description
|
||||||
|
class={cn("text-muted-foreground text-sm", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DialogPrimitive.Description>
|
16
src/lib/components/ui/dialog/dialog-footer.svelte
Normal file
16
src/lib/components/ui/dialog/dialog-footer.svelte
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
13
src/lib/components/ui/dialog/dialog-header.svelte
Normal file
13
src/lib/components/ui/dialog/dialog-header.svelte
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</div>
|
21
src/lib/components/ui/dialog/dialog-overlay.svelte
Normal file
21
src/lib/components/ui/dialog/dialog-overlay.svelte
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
import { fade } from "svelte/transition";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = DialogPrimitive.OverlayProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let transition: $$Props["transition"] = fade;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
|
duration: 150,
|
||||||
|
};
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DialogPrimitive.Overlay
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
class={cn("bg-background/80 fixed inset-0 z-50 backdrop-blur-sm", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
8
src/lib/components/ui/dialog/dialog-portal.svelte
Normal file
8
src/lib/components/ui/dialog/dialog-portal.svelte
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
type $$Props = DialogPrimitive.PortalProps;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DialogPrimitive.Portal {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</DialogPrimitive.Portal>
|
16
src/lib/components/ui/dialog/dialog-title.svelte
Normal file
16
src/lib/components/ui/dialog/dialog-title.svelte
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = DialogPrimitive.TitleProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DialogPrimitive.Title
|
||||||
|
class={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DialogPrimitive.Title>
|
37
src/lib/components/ui/dialog/index.ts
Normal file
37
src/lib/components/ui/dialog/index.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
import Title from "./dialog-title.svelte";
|
||||||
|
import Portal from "./dialog-portal.svelte";
|
||||||
|
import Footer from "./dialog-footer.svelte";
|
||||||
|
import Header from "./dialog-header.svelte";
|
||||||
|
import Overlay from "./dialog-overlay.svelte";
|
||||||
|
import Content from "./dialog-content.svelte";
|
||||||
|
import Description from "./dialog-description.svelte";
|
||||||
|
|
||||||
|
const Root = DialogPrimitive.Root;
|
||||||
|
const Trigger = DialogPrimitive.Trigger;
|
||||||
|
const Close = DialogPrimitive.Close;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Title,
|
||||||
|
Portal,
|
||||||
|
Footer,
|
||||||
|
Header,
|
||||||
|
Trigger,
|
||||||
|
Overlay,
|
||||||
|
Content,
|
||||||
|
Description,
|
||||||
|
Close,
|
||||||
|
//
|
||||||
|
Root as Dialog,
|
||||||
|
Title as DialogTitle,
|
||||||
|
Portal as DialogPortal,
|
||||||
|
Footer as DialogFooter,
|
||||||
|
Header as DialogHeader,
|
||||||
|
Trigger as DialogTrigger,
|
||||||
|
Overlay as DialogOverlay,
|
||||||
|
Content as DialogContent,
|
||||||
|
Description as DialogDescription,
|
||||||
|
Close as DialogClose,
|
||||||
|
};
|
28
src/lib/components/ui/textarea/index.ts
Normal file
28
src/lib/components/ui/textarea/index.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import Root from "./textarea.svelte";
|
||||||
|
|
||||||
|
type FormTextareaEvent<T extends Event = Event> = T & {
|
||||||
|
currentTarget: EventTarget & HTMLTextAreaElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TextareaEvents = {
|
||||||
|
blur: FormTextareaEvent<FocusEvent>;
|
||||||
|
change: FormTextareaEvent<Event>;
|
||||||
|
click: FormTextareaEvent<MouseEvent>;
|
||||||
|
focus: FormTextareaEvent<FocusEvent>;
|
||||||
|
keydown: FormTextareaEvent<KeyboardEvent>;
|
||||||
|
keypress: FormTextareaEvent<KeyboardEvent>;
|
||||||
|
keyup: FormTextareaEvent<KeyboardEvent>;
|
||||||
|
mouseover: FormTextareaEvent<MouseEvent>;
|
||||||
|
mouseenter: FormTextareaEvent<MouseEvent>;
|
||||||
|
mouseleave: FormTextareaEvent<MouseEvent>;
|
||||||
|
paste: FormTextareaEvent<ClipboardEvent>;
|
||||||
|
input: FormTextareaEvent<InputEvent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Textarea,
|
||||||
|
type TextareaEvents,
|
||||||
|
type FormTextareaEvent,
|
||||||
|
};
|
38
src/lib/components/ui/textarea/textarea.svelte
Normal file
38
src/lib/components/ui/textarea/textarea.svelte
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLTextareaAttributes } from "svelte/elements";
|
||||||
|
import type { TextareaEvents } from "./index.js";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = HTMLTextareaAttributes;
|
||||||
|
type $$Events = TextareaEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: $$Props["value"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
|
||||||
|
// Workaround for https://github.com/sveltejs/svelte/issues/9305
|
||||||
|
// Fixed in Svelte 5, but not backported to 4.x.
|
||||||
|
export let readonly: $$Props["readonly"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
class={cn(
|
||||||
|
"border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[80px] w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
bind:value
|
||||||
|
{readonly}
|
||||||
|
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}
|
||||||
|
></textarea>
|
567
src/lib/hljs/rose-pine.css
Normal file
567
src/lib/hljs/rose-pine.css
Normal file
@ -0,0 +1,567 @@
|
|||||||
|
* {
|
||||||
|
--color-rosepine-base: #191724;
|
||||||
|
--color-rosepine-surface: #1f1d2e;
|
||||||
|
--color-rosepine-overlay: #26233a;
|
||||||
|
--color-rosepine-muted: #6e6a86;
|
||||||
|
--color-rosepine-subtle: #908caa;
|
||||||
|
--color-rosepine-text: #e0def4;
|
||||||
|
--color-rosepine-love: #eb6f92;
|
||||||
|
--color-rosepine-gold: #f6c177;
|
||||||
|
--color-rosepine-rose: #ebbcba;
|
||||||
|
--color-rosepine-pine: #31748f;
|
||||||
|
--color-rosepine-foam: #9ccfd8;
|
||||||
|
--color-rosepine-iris: #c4a7e7;
|
||||||
|
--color-rosepine-highlight-low: #21202e;
|
||||||
|
--color-rosepine-highlight-med: #403d52;
|
||||||
|
--color-rosepine-highlight-high: #524f67;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre code.hljs {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 1em
|
||||||
|
}
|
||||||
|
|
||||||
|
code.hljs {
|
||||||
|
padding: 3px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
background: var(--color-rosepine-overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs,
|
||||||
|
.hljs-subst {
|
||||||
|
color: var(--color-rosepine-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-selector-tag {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-selector-id {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
font-weight: 700
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-selector-attr,
|
||||||
|
.hljs-selector-class {
|
||||||
|
color: var(--color-rosepine-iris)
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-property,
|
||||||
|
.hljs-selector-pseudo {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
background-color: rgba(156, 207, 216, .5)
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
background-color: rgba(235, 111, 146, .5)
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-class,
|
||||||
|
.hljs-type {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-function,
|
||||||
|
.hljs-function>.hljs-title,
|
||||||
|
.hljs-title.hljs-function {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-symbol {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-number {
|
||||||
|
color: var(--color-rosepine-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-regexp {
|
||||||
|
color: var(--color-rosepine-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-title {
|
||||||
|
color: var(--color-rosepine-iris)
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-params {
|
||||||
|
color: var(--color-rosepine-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-bullet {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-code {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-emphasis {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-formula {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-strong {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-quote {
|
||||||
|
color: var(--color-rosepine-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-doctag {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-meta,
|
||||||
|
.hljs-meta .hljs-keyword {
|
||||||
|
color: var(--color-rosepine-pine);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-meta .hljs-string {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attr {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attribute {
|
||||||
|
color: var(--color-rosepine-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-name {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-section {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-tag {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-variable {
|
||||||
|
color: var(--color-rosepine-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-template-tag {
|
||||||
|
color: var(--color-rosepine-pine);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-abnf .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-abnf .hljs-symbol {
|
||||||
|
color: var(--color-rosepine-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-apache .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-apache .hljs-section {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-arduino .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-aspectj .hljs-meta {
|
||||||
|
color: var(--color-rosepine-love);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-aspectj>.hljs-title {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-bnf .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-iris)
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-clojure .hljs-name {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-clojure .hljs-symbol {
|
||||||
|
color: var(--color-rosepine-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-coq .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-cpp .hljs-meta .hljs-string {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-css .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-css .hljs-keyword {
|
||||||
|
color: var(--color-rosepine-love);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-diff .hljs-meta,
|
||||||
|
.language-ebnf .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-glsl .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-groovy .hljs-meta:not(:first-child),
|
||||||
|
.language-haxe .hljs-meta,
|
||||||
|
.language-java .hljs-meta {
|
||||||
|
color: var(--color-rosepine-love);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-ldif .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-lisp .hljs-name,
|
||||||
|
.language-lua .hljs-built_in,
|
||||||
|
.language-moonscript .hljs-built_in,
|
||||||
|
.language-nginx .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-nginx .hljs-section {
|
||||||
|
color: var(--color-rosepine-pine);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-pf .hljs-built_in,
|
||||||
|
.language-processing .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-scss .hljs-keyword,
|
||||||
|
.language-stylus .hljs-keyword {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-swift .hljs-meta {
|
||||||
|
color: var(--color-rosepine-love);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-vim .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-yaml .hljs-meta {
|
||||||
|
color: var(--color-rosepine-love);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
* {
|
||||||
|
--color-rosepine-base: #faf4ed;
|
||||||
|
--color-rosepine-surface: #fffaf3;
|
||||||
|
--color-rosepine-overlay: #f2e9e1;
|
||||||
|
--color-rosepine-muted: #9893a5;
|
||||||
|
--color-rosepine-subtle: #797593;
|
||||||
|
--color-rosepine-text: #575279;
|
||||||
|
--color-rosepine-love: #b4637a;
|
||||||
|
--color-rosepine-gold: #ea9d34;
|
||||||
|
--color-rosepine-rose: #d7827e;
|
||||||
|
--color-rosepine-pine: #286983;
|
||||||
|
--color-rosepine-foam: #56949f;
|
||||||
|
--color-rosepine-iris: #907aa9;
|
||||||
|
--color-rosepine-highlight-low: #f4ede8;
|
||||||
|
--color-rosepine-highlight-med: #dfdad9;
|
||||||
|
--color-rosepine-highlight-high: #cecacd;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre code.hljs {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
code.hljs {
|
||||||
|
padding: 3px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
background: var(--color-rosepine-overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs,
|
||||||
|
.hljs-subst {
|
||||||
|
color: var(--color-rosepine-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-selector-tag {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-selector-id {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
font-weight: 700
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-selector-attr,
|
||||||
|
.hljs-selector-class {
|
||||||
|
color: var(--color-rosepine-iris)
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-property,
|
||||||
|
.hljs-selector-pseudo {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
background-color: rgba(156, 207, 216, 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
background-color: rgba(235, 111, 146, .5)
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-class,
|
||||||
|
.hljs-type {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-function,
|
||||||
|
.hljs-function>.hljs-title,
|
||||||
|
.hljs-title.hljs-function {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-symbol {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-number {
|
||||||
|
color: var(--color-rosepine-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-regexp {
|
||||||
|
color: var(--color-rosepine-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-title {
|
||||||
|
color: var(--color-rosepine-iris)
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-params {
|
||||||
|
color: var(--color-rosepine-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-bullet {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-code {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-emphasis {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-formula {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-strong {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-quote {
|
||||||
|
color: var(--color-rosepine-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-doctag {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-meta,
|
||||||
|
.hljs-meta .hljs-keyword {
|
||||||
|
color: var(--color-rosepine-pine);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-meta .hljs-string {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attr {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attribute {
|
||||||
|
color: var(--color-rosepine-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-name {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-section {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-tag {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-variable {
|
||||||
|
color: var(--color-rosepine-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-template-tag {
|
||||||
|
color: var(--color-rosepine-pine);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-abnf .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-abnf .hljs-symbol {
|
||||||
|
color: var(--color-rosepine-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-apache .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-apache .hljs-section {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-arduino .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-aspectj .hljs-meta {
|
||||||
|
color: var(--color-rosepine-love);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-aspectj>.hljs-title {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-bnf .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-iris)
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-clojure .hljs-name {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-clojure .hljs-symbol {
|
||||||
|
color: var(--color-rosepine-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-coq .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-cpp .hljs-meta .hljs-string {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-css .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-css .hljs-keyword {
|
||||||
|
color: var(--color-rosepine-love);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-diff .hljs-meta,
|
||||||
|
.language-ebnf .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-glsl .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-groovy .hljs-meta:not(:first-child),
|
||||||
|
.language-haxe .hljs-meta,
|
||||||
|
.language-java .hljs-meta {
|
||||||
|
color: var(--color-rosepine-love);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-ldif .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-iris);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-lisp .hljs-name,
|
||||||
|
.language-lua .hljs-built_in,
|
||||||
|
.language-moonscript .hljs-built_in,
|
||||||
|
.language-nginx .hljs-attribute {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-nginx .hljs-section {
|
||||||
|
color: var(--color-rosepine-pine);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-pf .hljs-built_in,
|
||||||
|
.language-processing .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-scss .hljs-keyword,
|
||||||
|
.language-stylus .hljs-keyword {
|
||||||
|
color: var(--color-rosepine-foam);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-swift .hljs-meta {
|
||||||
|
color: var(--color-rosepine-love);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-vim .hljs-built_in {
|
||||||
|
color: var(--color-rosepine-rose);
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-yaml .hljs-meta {
|
||||||
|
color: var(--color-rosepine-love);
|
||||||
|
}
|
||||||
|
}
|
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,17 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import "../app.css"
|
import '../app.css';
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
let template1 = ["grid-cols-4 h-16", "col-span-3 text-4xl grid-cols-4", ""]
|
|
||||||
let template2 = ["grid-cols-1 grid-rows-4 h-1/4", "place-items-center row-span-3 text-6xl text-center", ""]
|
|
||||||
let template = $state(template1)
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="grid w-full {template[0]} sticky top-0">
|
<div class="sticky top-0 z-10 grid h-16 w-full grid-cols-4 bg-background">
|
||||||
<div class="grid {template[1]}">
|
<div class="col-span-3 grid grid-cols-4 text-4xl">
|
||||||
<a class="m-auto" href="/">中工匿名</a>
|
<a class="m-auto" href="/">中工匿名</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-3 grid-rows-1 text-center {template[2]}">
|
<div class="grid grid-cols-3 grid-rows-1 text-center">
|
||||||
<a class="my-auto" href="/tos">服務條款</a>
|
<a class="my-auto" href="/tos">服務條款</a>
|
||||||
<a class="my-auto" href="/links">鏈接</a>
|
<a class="my-auto" href="/links">鏈接</a>
|
||||||
<a class="my-auto" href="/fav">每月精選</a>
|
<a class="my-auto" href="/fav">每月精選</a>
|
||||||
|
@ -1,26 +1,44 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
let body_state = $state(false);
|
import MessageCard from './message_card.svelte';
|
||||||
$inspect(body_state)
|
import MingcuteAddCircleFill from '~icons/mingcute/add-circle-fill';
|
||||||
|
import Overlay, { toggle_overlay, get_overlay } from './overlay.svelte';
|
||||||
|
import DOMPurify from 'isomorphic-dompurify';
|
||||||
|
import Marker from './marker.svelte';
|
||||||
|
|
||||||
|
let value: string;
|
||||||
|
|
||||||
const overlay = () => {
|
const overlay = () => {
|
||||||
body_state = !body_state;
|
if (!get_overlay()) {
|
||||||
if(body_state){
|
|
||||||
document.body.classList.add("overflow-y-hidden");
|
|
||||||
} else {
|
} else {
|
||||||
document.body.classList.remove("overflow-y-hidden");
|
|
||||||
}
|
}
|
||||||
|
toggle_overlay();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<div style="width:100dvw;" class="h-dvh grid">
|
|
||||||
<p class="justify-self-center m-auto">空空如也...</p>
|
<div style="width:100dvw;" class="grid h-dvh px-5 py-3">
|
||||||
|
<!-- <p class="justify-self-center m-auto">空空如也...</p> -->
|
||||||
|
<MessageCard
|
||||||
|
content="
|
||||||
|
# H1
|
||||||
|
## H2
|
||||||
|
### H3
|
||||||
|
[url](https://google.com)
|
||||||
|
![image](http://localhost:5173/favicon.png)
|
||||||
|
Test
|
||||||
|
NormalText
|
||||||
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button id="add" onclick={overlay}>
|
<button id="add" onclick={overlay} class="text-3xl"> <MingcuteAddCircleFill /> </button>
|
||||||
+
|
<Overlay>
|
||||||
</button>
|
<div class="flex w-4/6 flex-col rounded-lg bg-primary px-5 py-3" style="height:60dvh;">
|
||||||
<div id="overlay" class:overlay_enable={body_state} class:hidden={!body_state}>
|
<div class="relative h-6 w-full">
|
||||||
<div>
|
<button class="absolute left-0" onclick={overlay}>取消</button>
|
||||||
<button onclick={overlay}>close</button>
|
<button class="absolute right-0">發送</button>
|
||||||
</div>
|
</div>
|
||||||
|
<Marker text={value} height="h-[calc(100%-1.5rem)]" />
|
||||||
</div>
|
</div>
|
||||||
|
</Overlay>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#add {
|
#add {
|
||||||
@ -28,16 +46,4 @@ const overlay = () => {
|
|||||||
bottom: calc(15dvh);
|
bottom: calc(15dvh);
|
||||||
right: calc(10dvw);
|
right: calc(10dvw);
|
||||||
}
|
}
|
||||||
#overlay{
|
|
||||||
position: fixed;
|
|
||||||
width:100%;
|
|
||||||
height: 100%;
|
|
||||||
top:0;
|
|
||||||
left:0;
|
|
||||||
z-index: 10;
|
|
||||||
cursor:pointer;
|
|
||||||
}
|
|
||||||
.overlay_enable{
|
|
||||||
backdrop-filter: blur(3px);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
92
src/routes/marker.svelte
Normal file
92
src/routes/marker.svelte
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { text, height }: { text: string; height: string } = $props();
|
||||||
|
import { Textarea } from '$lib/components/ui/textarea';
|
||||||
|
import { Marked } from 'marked';
|
||||||
|
import DOMPurify from 'isomorphic-dompurify';
|
||||||
|
import type { KeyboardEventHandler } from 'svelte/elements';
|
||||||
|
import { markedHighlight } from 'marked-highlight';
|
||||||
|
import hljs from 'highlight.js';
|
||||||
|
import '$lib/hljs/rose-pine.css';
|
||||||
|
|
||||||
|
let window_size = $state(0);
|
||||||
|
let value = $state('');
|
||||||
|
const key_scrap: KeyboardEventHandler<HTMLTextAreaElement> = (event: KeyboardEvent) => {
|
||||||
|
let ct: HTMLTextAreaElement = event.currentTarget as HTMLTextAreaElement;
|
||||||
|
if (event.key == 'Tab') {
|
||||||
|
event.preventDefault();
|
||||||
|
let start = ct.selectionStart;
|
||||||
|
let end = ct.selectionEnd;
|
||||||
|
ct.value = ct.value.substring(0, start) + '\t' + ct.value.substring(end);
|
||||||
|
ct.selectionStart = ct.selectionEnd = start + 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// marked
|
||||||
|
const marked = new Marked(
|
||||||
|
markedHighlight({
|
||||||
|
emptyLangClass: 'hljs',
|
||||||
|
langPrefix: 'hljs language-',
|
||||||
|
highlight(code, lang, info) {
|
||||||
|
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
|
||||||
|
return hljs.highlight(code, { language }).value;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window bind:innerWidth={window_size} />
|
||||||
|
<div class="{height} w-full">
|
||||||
|
<div class="h-[4%] w-full"></div>
|
||||||
|
{#if window_size < 360}
|
||||||
|
<div>
|
||||||
|
<Textarea class="h-[96%] w-full resize-none" />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="grid h-[96%] w-full grid-cols-2 gap-5">
|
||||||
|
<textarea
|
||||||
|
tabindex="0"
|
||||||
|
class="resize-none rounded-lg bg-background p-1 text-foreground focus:outline-none focus:ring focus:ring-primary-foreground"
|
||||||
|
bind:value
|
||||||
|
onkeydown={key_scrap}
|
||||||
|
></textarea>
|
||||||
|
<div class="inner_card">
|
||||||
|
{@html marked.parse(value).toString()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.inner_card :global {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow-y: scroll;
|
||||||
|
a {
|
||||||
|
@apply text-cyan-500;
|
||||||
|
}
|
||||||
|
p:has(code) {
|
||||||
|
overflow-x: scroll;
|
||||||
|
padding: 10px 0px;
|
||||||
|
code {
|
||||||
|
/* @apply bg-amber-600; */
|
||||||
|
text-wrap: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
word-break: keep-all;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
/* @apply bg-amber-600; */
|
||||||
|
overflow-x: scroll;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,29 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { content }: { content: string } = $props();
|
||||||
|
import { marked } from 'marked';
|
||||||
|
import * as Dialog from '$lib/components/ui/dialog';
|
||||||
|
//TODO Need sanitizer
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="card_eff flex max-h-80 max-w-64 flex-col overflow-y-hidden bg-amber-400 px-5 font-bold text-slate-900"
|
||||||
|
>
|
||||||
|
<div class="inner_card">
|
||||||
|
{@html marked(content)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.card_eff {
|
||||||
|
filter: drop-shadow(5px 10px #f38f0f);
|
||||||
|
}
|
||||||
|
.inner_card :global {
|
||||||
|
a {
|
||||||
|
@apply text-cyan-500;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
@apply bg-amber-600;
|
||||||
|
}
|
||||||
|
mask-image: linear-gradient(0deg, transparent, white 50%);
|
||||||
|
}
|
||||||
|
</style>
|
32
src/routes/overlay.svelte
Normal file
32
src/routes/overlay.svelte
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<script module lang="ts">
|
||||||
|
let overlay = $state(false);
|
||||||
|
const toggle_overlay = () => {
|
||||||
|
overlay = !overlay;
|
||||||
|
if (overlay) {
|
||||||
|
document.body.classList.add('overflow-y-hidden');
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove('overflow-y-hidden');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const get_overlay = () => {
|
||||||
|
return overlay;
|
||||||
|
};
|
||||||
|
export { toggle_overlay, get_overlay };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
let { children } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class={'fixed left-0 top-0 z-20 h-dvh w-dvw ' +
|
||||||
|
(overlay ? 'overlay_blur grid place-items-center' : 'hidden')}
|
||||||
|
>
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.overlay_blur {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,5 +1,6 @@
|
|||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<p class="w-1/2 break-keep text-2xl">
|
<div class="w-1/2 break-keep text-center text-2xl">
|
||||||
“中工匿名”不記錄個人網路位置, 名字。可選用匿名,或佚名作為發表時署名。如訊息侵害他人權利,違反大眾道德觀,皆不保證留存。
|
<p>“中工匿名”不記錄個人網路位置、名字。</p>
|
||||||
</p>
|
<p>如訊息侵害他人權利,違反大眾道德觀,皆不保證留存。</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
3
src/vite-env.d.ts
vendored
Normal file
3
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/// <reference types="svelte" />
|
||||||
|
/// <reference types="vite/client" />
|
||||||
|
/// <reference types="unplugin-icons/types/svelte" />
|
BIN
static/GenRyuMin2TW-M.woff2
Normal file
BIN
static/GenRyuMin2TW-M.woff2
Normal file
Binary file not shown.
@ -1,15 +1,11 @@
|
|||||||
import adapter from '@sveltejs/adapter-auto';
|
import adapter from '@sveltejs/adapter-auto';
|
||||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||||
import { preprocessMeltUI, sequence } from '@melt-ui/pp'
|
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
// Consult https://svelte.dev/docs/kit/integrations
|
// Consult https://svelte.dev/docs/kit/integrations
|
||||||
// for more information about preprocessors
|
// for more information about preprocessors
|
||||||
preprocess: sequence([
|
preprocess: vitePreprocess(),
|
||||||
vitePreprocess(),
|
|
||||||
preprocessMeltUI()
|
|
||||||
]),
|
|
||||||
|
|
||||||
kit: {
|
kit: {
|
||||||
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
||||||
|
@ -1,12 +1,64 @@
|
|||||||
import typography from '@tailwindcss/typography';
|
import { fontFamily } from "tailwindcss/defaultTheme";
|
||||||
import type { Config } from 'tailwindcss';
|
import type { Config } from "tailwindcss";
|
||||||
|
|
||||||
export default {
|
|
||||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
|
||||||
|
|
||||||
|
const config: Config = {
|
||||||
|
darkMode: ["class"],
|
||||||
|
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||||
|
safelist: ["dark"],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {}
|
container: {
|
||||||
|
center: true,
|
||||||
|
padding: "2rem",
|
||||||
|
screens: {
|
||||||
|
"2xl": "1400px"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
border: "hsl(var(--border) / <alpha-value>)",
|
||||||
|
input: "hsl(var(--input) / <alpha-value>)",
|
||||||
|
ring: "hsl(var(--ring) / <alpha-value>)",
|
||||||
|
background: "hsl(var(--background) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--foreground) / <alpha-value>)",
|
||||||
|
primary: {
|
||||||
|
DEFAULT: "hsl(var(--primary) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--primary-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
DEFAULT: "hsl(var(--secondary) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--secondary-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
destructive: {
|
||||||
|
DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--destructive-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
muted: {
|
||||||
|
DEFAULT: "hsl(var(--muted) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--muted-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
accent: {
|
||||||
|
DEFAULT: "hsl(var(--accent) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--accent-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
popover: {
|
||||||
|
DEFAULT: "hsl(var(--popover) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--popover-foreground) / <alpha-value>)"
|
||||||
|
},
|
||||||
|
card: {
|
||||||
|
DEFAULT: "hsl(var(--card) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--card-foreground) / <alpha-value>)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
lg: "var(--radius)",
|
||||||
|
md: "calc(var(--radius) - 2px)",
|
||||||
|
sm: "calc(var(--radius) - 4px)"
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: [...fontFamily.sans]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
plugins: [typography]
|
export default config;
|
||||||
} as Config;
|
|
||||||
|
@ -9,7 +9,15 @@
|
|||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"moduleResolution": "bundler"
|
"moduleResolution": "bundler",
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "typescript-svelte-plugin",
|
||||||
|
// the following options can be set additionally; they are optional; their default values are listed here
|
||||||
|
"enabled": true, // enables this plugin
|
||||||
|
"assumeIsSvelteProject": false // if true, skip detection and always assume it's a Svelte project
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
import Icons from 'unplugin-icons/vite'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit()]
|
plugins: [sveltekit(), Icons({ compiler: 'svelte' })]
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user