sec
This commit is contained in:
parent
739dafc2c1
commit
82d7d09818
@ -3,7 +3,10 @@
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
||||
"plugins": [
|
||||
"prettier-plugin-svelte",
|
||||
"prettier-plugin-tailwindcss"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"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
|
||||
|
||||
|
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 ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@melt-ui/pp": "^0.3.2",
|
||||
"@melt-ui/svelte": "^0.85.0",
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@types/dompurify": "^3",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"bits-ui": "^0.21.16",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-svelte": "^0.454.0",
|
||||
"prettier": "^3.3.2",
|
||||
"prettier-plugin-svelte": "^3.2.6",
|
||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tailwind-merge": "^2.5.4",
|
||||
"tailwind-variants": "^0.2.1",
|
||||
"tailwindcss": "^3.4.9",
|
||||
"typescript": "^5.0.0",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
106
src/app.css
106
src/app.css
@ -1,16 +1,96 @@
|
||||
@import 'tailwindcss/base';
|
||||
@import 'tailwindcss/components';
|
||||
@import 'tailwindcss/utilities';
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@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%;
|
||||
|
||||
body{
|
||||
display:block;
|
||||
margin:0px;
|
||||
width:100dvw;
|
||||
min-height: 100dvh;
|
||||
font-family: "LXGW WenKai TC", cursive;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
overflow-x: hidden;
|
||||
--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 {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
@apply dark;
|
||||
}
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "GenRyuMin2TW";
|
||||
src:
|
||||
url("/GenRyuMin2TW-M.woff2") format("woff2");
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "GenRyuMin2TW";
|
||||
overflow-x: hidden;
|
||||
}
|
3
src/app.d.ts
vendored
3
src/app.d.ts
vendored
@ -1,5 +1,6 @@
|
||||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
import 'unplugin-icons/types/svelte'
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
@ -10,4 +11,4 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
export { };
|
||||
|
@ -7,8 +7,6 @@
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">
|
||||
%sveltekit.body%
|
||||
</div>
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</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,20 +1,16 @@
|
||||
<script lang="ts">
|
||||
import "../app.css"
|
||||
import '../app.css';
|
||||
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>
|
||||
|
||||
<div class="grid w-full {template[0]} sticky top-0">
|
||||
<div class="grid {template[1]}">
|
||||
<a class="m-auto" href="/">中工匿名</a>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-rows-1 text-center {template[2]}">
|
||||
<a class="my-auto" href="/tos">服務條款</a>
|
||||
<a class="my-auto" href="/links">鏈接</a>
|
||||
<a class="my-auto" href="/fav">每月精選</a>
|
||||
</div>
|
||||
<div class="sticky top-0 z-10 grid h-16 w-full grid-cols-4 bg-background">
|
||||
<div class="col-span-3 grid grid-cols-4 text-4xl">
|
||||
<a class="m-auto" href="/">中工匿名</a>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-rows-1 text-center">
|
||||
<a class="my-auto" href="/tos">服務條款</a>
|
||||
<a class="my-auto" href="/links">鏈接</a>
|
||||
<a class="my-auto" href="/fav">每月精選</a>
|
||||
</div>
|
||||
</div>
|
||||
{@render children()}
|
||||
|
@ -1,43 +1,49 @@
|
||||
<script lang="ts">
|
||||
let body_state = $state(false);
|
||||
$inspect(body_state)
|
||||
const overlay = () => {
|
||||
body_state = !body_state;
|
||||
if(body_state){
|
||||
document.body.classList.add("overflow-y-hidden");
|
||||
}else{
|
||||
document.body.classList.remove("overflow-y-hidden");
|
||||
}
|
||||
};
|
||||
import MessageCard from './message_card.svelte';
|
||||
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 = () => {
|
||||
if (!get_overlay()) {
|
||||
} else {
|
||||
}
|
||||
toggle_overlay();
|
||||
};
|
||||
</script>
|
||||
<div style="width:100dvw;" class="h-dvh grid">
|
||||
<p class="justify-self-center m-auto">空空如也...</p>
|
||||
</div>
|
||||
<button id="add" onclick={overlay}>
|
||||
+
|
||||
</button>
|
||||
<div id="overlay" class:overlay_enable={body_state} class:hidden={!body_state}>
|
||||
<div>
|
||||
<button onclick={overlay}>close</button>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<button id="add" onclick={overlay} class="text-3xl"> <MingcuteAddCircleFill /> </button>
|
||||
<Overlay>
|
||||
<div class="flex w-4/6 flex-col rounded-lg bg-primary px-5 py-3" style="height:60dvh;">
|
||||
<div class="relative h-6 w-full">
|
||||
<button class="absolute left-0" onclick={overlay}>取消</button>
|
||||
<button class="absolute right-0">發送</button>
|
||||
</div>
|
||||
<Marker text={value} height="h-[calc(100%-1.5rem)]" />
|
||||
</div>
|
||||
</Overlay>
|
||||
|
||||
<style>
|
||||
#add{
|
||||
position: fixed;
|
||||
bottom:calc(15dvh);
|
||||
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);
|
||||
}
|
||||
#add {
|
||||
position: fixed;
|
||||
bottom: calc(15dvh);
|
||||
right: calc(10dvw);
|
||||
}
|
||||
</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">
|
||||
<p class="w-1/2 break-keep text-2xl">
|
||||
“中工匿名”不記錄個人網路位置, 名字。可選用匿名,或佚名作為發表時署名。如訊息侵害他人權利,違反大眾道德觀,皆不保證留存。
|
||||
</p>
|
||||
<div class="w-1/2 break-keep text-center text-2xl">
|
||||
<p>“中工匿名”不記錄個人網路位置、名字。</p>
|
||||
<p>如訊息侵害他人權利,違反大眾道德觀,皆不保證留存。</p>
|
||||
</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 { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
import { preprocessMeltUI, sequence } from '@melt-ui/pp'
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://svelte.dev/docs/kit/integrations
|
||||
// for more information about preprocessors
|
||||
preprocess: sequence([
|
||||
vitePreprocess(),
|
||||
preprocessMeltUI()
|
||||
]),
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
// 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 type { Config } from 'tailwindcss';
|
||||
|
||||
export default {
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
import { fontFamily } from "tailwindcss/defaultTheme";
|
||||
import type { Config } from "tailwindcss";
|
||||
|
||||
const config: Config = {
|
||||
darkMode: ["class"],
|
||||
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||
safelist: ["dark"],
|
||||
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]
|
||||
} as Config;
|
||||
export default config;
|
||||
|
@ -9,7 +9,15 @@
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": 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
|
||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
import Icons from 'unplugin-icons/vite'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
plugins: [sveltekit(), Icons({ compiler: 'svelte' })]
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user