diff --git a/.gitignore b/.gitignore index 79518f7..b95f779 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,8 @@ Thumbs.db # Vite vite.config.js.timestamp-* vite.config.ts.timestamp-* + +# lock files +bun.lockb +yarn.lock +.yarn/ diff --git a/package.json b/package.json index 86979df..791748a 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "@sveltejs/vite-plugin-svelte": "^4.0.0", "@types/dompurify": "^3", "autoprefixer": "^10.4.20", - "bits-ui": "^0.21.16", + "bits-ui": "^0.22.0", "clsx": "^2.1.1", "lucide-svelte": "^0.454.0", "prettier": "^3.3.2", diff --git a/src/app.css b/src/app.css index ca35437..c037f66 100644 --- a/src/app.css +++ b/src/app.css @@ -3,139 +3,141 @@ @tailwind utilities; @layer base { - :root { - --background: 0 0% 100%; - --foreground: 224 71.4% 4.1%; + :root { + --background: 0 0% 100%; + --foreground: 224 71.4% 4.1%; - --muted: 220 14.3% 95.9%; - --muted-foreground: 220 8.9% 46.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%; + --popover: 0 0% 100%; + --popover-foreground: 224 71.4% 4.1%; - --card: 0 0% 100%; - --card-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%; + --border: 220 13% 91%; + --input: 220 13% 91%; - --primary: 33deg 43% 91%; - --primary-foreground: 210 20% 98%; + --primary: 33deg 43% 91%; + --primary-foreground: 210 20% 98%; - --secondary: 220 14.3% 95.9%; - --secondary-foreground: 220.9 39.3% 11%; + --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%; + --accent: 220 14.3% 95.9%; + --accent-foreground: 220.9 39.3% 11%; - --destructive: 0 72.2% 50.6%; - --destructive-foreground: 210 20% 98%; + --destructive: 0 72.2% 50.6%; + --destructive-foreground: 210 20% 98%; - --ring: 224 71.4% 4.1%; + --ring: 224 71.4% 4.1%; - --radius: 0.5rem; + --radius: 0.5rem; - } + } - .dark { - --background: 249 22% 12%; - --foreground: 245 50% 91%; + .dark { + --background: 249 22% 12%; + --foreground: 245 50% 91%; - --muted: 215 27.9% 16.9%; - --muted-foreground: 217.9 10.6% 64.9%; + --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%; + --popover: 224 71.4% 4.1%; + --popover-foreground: 210 20% 98%; - --card: 35 88% 72%; - --card-foreground: 248 13% 36%; + --card: 35 88% 72%; + --card-foreground: 248 13% 36%; - --border: 248 13% 36%; - --input: 215 27.9% 16.9%; + --border: 248 13% 36%; + --input: 215 27.9% 16.9%; - --primary: 248deg 25% 18%; - --primary-foreground: 248deg 15% 61%; + --primary: 248deg 25% 18%; + --primary-foreground: 248deg 15% 61%; - --secondary: 249deg 15% 28%; - --secondary-foreground: 210 20% 98%; + --secondary: 249deg 15% 28%; + --secondary-foreground: 210 20% 98%; - --accent: 215 27.9% 16.9%; - --accent-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%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 20% 98%; - --ring: 216 12.2% 83.9%; - } + --ring: 216 12.2% 83.9%; + } } @layer base { - * { - @apply border-border; - } + * { + @apply border-border; + } - body { - @apply bg-background text-foreground; - } + body { + @apply bg-background text-foreground; + } } @media (prefers-color-scheme: dark) { - body { - @apply dark; - } + body { + @apply dark; + } } @font-face { - font-family: "PingFang"; - src: - local('PingFang Bold'), src("/PingFang Bold.woff2") type("woff2"); - font-weight: bold; + font-family: "PingFang"; + src: + local('PingFang Bold'), src("/PingFang Bold.woff2") type("woff2"); + font-weight: bold; } @font-face { - font-family: "PingFang"; - src: - local('PingFang Medium'), src("/PingFang Medium.woff2") type("woff2"); - font-weight: normal; + font-family: "PingFang"; + src: + local('PingFang Medium'), src("/PingFang Medium.woff2") type("woff2"); + font-weight: normal; } @font-face { - font-family: "PingFang"; - src: - local('PingFang Heavy'), src("/PingFang Heavy.woff2") type("woff2"); - font-weight: bolder; + font-family: "PingFang"; + src: + local('PingFang Heavy'), src("/PingFang Heavy.woff2") type("woff2"); + font-weight: bolder; } @font-face { - font-family: "PingFang"; - src: - local('PingFang Light'), src("/PingFang Light.woff2") type("woff2"); - font-weight: lighter; + font-family: "PingFang"; + src: + local('PingFang Light'), src("/PingFang Light.woff2") type("woff2"); + font-weight: lighter; } @font-face { - font-family: "PingFang"; - src: - local('PingFang Regular'), src("/PingFang Regular.woff2") type("woff2"); - font-weight: normal; + font-family: "PingFang"; + src: + local('PingFang Regular'), src("/PingFang Regular.woff2") type("woff2"); + font-weight: normal; } body { - font-family: "PingFang"; - font-weight: 400; - overflow-x: hidden; + font-family: "PingFang"; + font-weight: 400; + overflow-x: hidden; + width: 100dvw; + min-height: 100dvh; } ::-webkit-scrollbar { - width: 8px; + width: 8px; } ::-webkit-scrollbar-track { - background-color: hsl(var(--muted)) + background-color: hsl(var(--muted)) } ::-webkit-scrollbar-thumb { - background-color: hsl(248deg, 13%, 36%); - border-radius: 10px; + background-color: hsl(248deg, 13%, 36%); + border-radius: 10px; } diff --git a/src/lib/api.ts b/src/lib/api.ts index 4cb0320..c44ee60 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,63 +1,81 @@ -import { Fetch, Post, PostResponse } from '$lib/protobuf/niming'; -import axios from 'axios'; +import { FetchResponse, Post, PostResponse } from '$lib/protobuf/niming'; +import axios, { type AxiosRequestConfig, type AxiosResponse } from 'axios'; -export const ResultEnum = { - Ok: 1, - Err: 2 -} as const; -export type ResultEnum = typeof ResultEnum[keyof typeof ResultEnum]; -export interface Result { - kind: ResultEnum; - message: string - enclose?: T; +export class Result { + status: number + enclose?: T + message?: string + constructor(status: number, enclose?: T, message?: string) { + this.status = status; + this.enclose = enclose; + this.message = message; + } + ok(): boolean { return this.status == 1 } + set_status(status: number) { + this.status = status + } +} + + +function axios_request(method: string, url: string, params?: Map | Object, data?: Uint8Array): Promise> { + let cfg: AxiosRequestConfig = { + method, + url, + params, + data, + responseType: "arraybuffer", + headers: { 'Content-Type': 'application/x-protobuf' }, + } + + return axios(cfg) } export class API { - page: number - constructor() { - this.page = 0 - } - async send_post(content: string, refer: bigint | undefined, files: File[] | undefined) { - let readed: Uint8Array[] = []; - files?.forEach((e) => { - e.arrayBuffer().then((arrbuf) => { - readed.push(new Uint8Array(arrbuf)); - }); - }); - let ctx = Post.create({ content: content, files: readed }); - if (refer !== undefined) { - ctx.ref = refer; - } - let result: Result = { kind: ResultEnum.Err, message: "" }; - await axios - .post('/article/', Post.toBinary(ctx), { - headers: { 'Content-Type': 'application/x-protobuf' }, - responseType: "arraybuffer" - }) - .then((e) => { - result.kind = ResultEnum.Ok; - result.enclose = PostResponse.fromBinary(e.data); - }) - .catch((err) => { - if (err.response) { - result.message = err.response.data.error; - } - }); - return result; - } - async fetch() { - let result: Result = { kind: ResultEnum.Err, message: "" }; - axios.get("/article/list", { responseType: "arraybuffer" }).then((e) => { - result.kind = ResultEnum.Ok; - result.enclose = Fetch.fromBinary(e.data); - }).catch((e) => { + page: number + constructor() { + this.page = 0 + } + async send_post(content: string, refer: bigint | undefined, files: File[] | undefined) { + let files_buf: Uint8Array[] = []; + files?.forEach((e) => { + e.arrayBuffer().then((arrbuf) => { + files_buf.push(new Uint8Array(arrbuf)); + }); + }); - }); - this.page++; - return result; - } + let ctx = Post.create({ content: content, files: files_buf }); + if (refer !== undefined) { + ctx.ref = refer; + } + + let result = new Result(0) + + await axios_request('post', '/article', undefined, Post.toBinary(ctx)) + .then(e => { + result.enclose = PostResponse.fromBinary(new Uint8Array(e.data)) + result.set_status(1); + }).catch(e => { + result.message = e.response?.data + }); + return result; + } + async fetch(): Promise> { + let result = new Result(0) + + await axios_request('get', '/article/list', { page: this.page }) + .then(e => { + result.enclose = FetchResponse.fromBinary(new Uint8Array(e.data)) + result.set_status(1); + this.page += 1; + }) + .catch(e => { + result.message = e.response?.data + }) + + return result; + } } let api_inst = new API(); export default api_inst; diff --git a/src/lib/components/ui/button/button.svelte b/src/lib/components/ui/button/button.svelte new file mode 100644 index 0000000..86827f3 --- /dev/null +++ b/src/lib/components/ui/button/button.svelte @@ -0,0 +1,25 @@ + + + + + diff --git a/src/lib/components/ui/button/index.ts b/src/lib/components/ui/button/index.ts new file mode 100644 index 0000000..af1e188 --- /dev/null +++ b/src/lib/components/ui/button/index.ts @@ -0,0 +1,49 @@ +import { type VariantProps, tv } from "tailwind-variants"; +import type { Button as ButtonPrimitive } from "bits-ui"; +import Root from "./button.svelte"; + +const buttonVariants = tv({ + base: "ring-offset-background focus-visible:ring-ring inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border-input bg-background hover:bg-accent hover:text-accent-foreground border", + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, +}); + +type Variant = VariantProps["variant"]; +type Size = VariantProps["size"]; + +type Props = ButtonPrimitive.Props & { + variant?: Variant; + size?: Size; +}; + +type Events = ButtonPrimitive.Events; + +export { + Root, + type Props, + type Events, + // + Root as Button, + type Props as ButtonProps, + type Events as ButtonEvents, + buttonVariants, +}; diff --git a/src/lib/components/ui/scroll-area/index.ts b/src/lib/components/ui/scroll-area/index.ts new file mode 100644 index 0000000..e86a25b --- /dev/null +++ b/src/lib/components/ui/scroll-area/index.ts @@ -0,0 +1,10 @@ +import Scrollbar from "./scroll-area-scrollbar.svelte"; +import Root from "./scroll-area.svelte"; + +export { + Root, + Scrollbar, + //, + Root as ScrollArea, + Scrollbar as ScrollAreaScrollbar, +}; diff --git a/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte b/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte new file mode 100644 index 0000000..71b3328 --- /dev/null +++ b/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte @@ -0,0 +1,27 @@ + + + + + + diff --git a/src/lib/components/ui/scroll-area/scroll-area.svelte b/src/lib/components/ui/scroll-area/scroll-area.svelte new file mode 100644 index 0000000..e8e368c --- /dev/null +++ b/src/lib/components/ui/scroll-area/scroll-area.svelte @@ -0,0 +1,32 @@ + + + + + + + + + {#if orientation === "vertical" || orientation === "both"} + + {/if} + {#if orientation === "horizontal" || orientation === "both"} + + {/if} + + diff --git a/src/lib/components/ui/tooltip/index.ts b/src/lib/components/ui/tooltip/index.ts new file mode 100644 index 0000000..7d0444d --- /dev/null +++ b/src/lib/components/ui/tooltip/index.ts @@ -0,0 +1,15 @@ +import { Tooltip as TooltipPrimitive } from "bits-ui"; +import Content from "./tooltip-content.svelte"; + +const Root = TooltipPrimitive.Root; +const Trigger = TooltipPrimitive.Trigger; + +export { + Root, + Trigger, + Content, + // + Root as Tooltip, + Content as TooltipContent, + Trigger as TooltipTrigger, +}; diff --git a/src/lib/components/ui/tooltip/tooltip-content.svelte b/src/lib/components/ui/tooltip/tooltip-content.svelte new file mode 100644 index 0000000..af9d1ff --- /dev/null +++ b/src/lib/components/ui/tooltip/tooltip-content.svelte @@ -0,0 +1,28 @@ + + + + + diff --git a/src/lib/index.ts b/src/lib/index.ts index 5022ad5..856f2b6 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,2 +1 @@ // place files you want to import through the `$lib` alias in this folder. -export * from './textmark' diff --git a/src/lib/protobuf/definitions/niming.proto b/src/lib/protobuf/definitions/niming.proto index 893fde4..1c2e3e0 100644 --- a/src/lib/protobuf/definitions/niming.proto +++ b/src/lib/protobuf/definitions/niming.proto @@ -8,21 +8,30 @@ message Post { repeated bytes files = 3; } -// The response of the posting, defining what should return. -message PostResponse { - string hash = 1; - uint64 id = 2; +enum Status { + Failed = 0; + Success = 1; } -message Fetch { +// The response of the posting, defining what should return. +message PostResponse { + Status status = 1; + string hash = 2; + uint64 id = 3; + optional string failed_message = 4; +} + +message FetchResponse { message Message { uint64 id = 1; string content = 2; // reply to a post, like a mail chat. - optional uint64 ref = 3; + // optional uint64 ref = 3; // request files through /article/file/ with MIME type. // See it as a BLOB url; - repeated uint64 files_id = 4; + repeated string files_hash = 3; + optional string igid = 4; + repeated string comments_hash = 5; } // Several post info repeated Message posts = 1; diff --git a/src/lib/protobuf/niming.ts b/src/lib/protobuf/niming.ts index 87f0591..95d1c5f 100644 --- a/src/lib/protobuf/niming.ts +++ b/src/lib/protobuf/niming.ts @@ -38,29 +38,37 @@ export interface Post { */ export interface PostResponse { /** - * @generated from protobuf field: string hash = 1; + * @generated from protobuf field: Status status = 1; + */ + status: Status; + /** + * @generated from protobuf field: string hash = 2; */ hash: string; /** - * @generated from protobuf field: uint64 id = 2; + * @generated from protobuf field: uint64 id = 3; */ id: bigint; + /** + * @generated from protobuf field: optional string failed_message = 4; + */ + failedMessage?: string; } /** - * @generated from protobuf message Fetch + * @generated from protobuf message FetchResponse */ -export interface Fetch { +export interface FetchResponse { /** * Several post info * - * @generated from protobuf field: repeated Fetch.Message posts = 1; + * @generated from protobuf field: repeated FetchResponse.Message posts = 1; */ - posts: Fetch_Message[]; + posts: FetchResponse_Message[]; } /** - * @generated from protobuf message Fetch.Message + * @generated from protobuf message FetchResponse.Message */ -export interface Fetch_Message { +export interface FetchResponse_Message { /** * @generated from protobuf field: uint64 id = 1; */ @@ -71,17 +79,34 @@ export interface Fetch_Message { content: string; /** * reply to a post, like a mail chat. - * - * @generated from protobuf field: optional uint64 ref = 3; - */ - ref?: bigint; - /** + * optional uint64 ref = 3; * request files through /article/file/ with MIME type. * See it as a BLOB url; * - * @generated from protobuf field: repeated uint64 files_id = 4; + * @generated from protobuf field: repeated string files_hash = 3; */ - filesId: bigint[]; + filesHash: string[]; + /** + * @generated from protobuf field: optional string igid = 4; + */ + igid?: string; + /** + * @generated from protobuf field: repeated string comments_hash = 5; + */ + commentsHash: string[]; +} +/** + * @generated from protobuf enum Status + */ +export enum Status { + /** + * @generated from protobuf enum value: Failed = 0; + */ + Failed = 0, + /** + * @generated from protobuf enum value: Success = 1; + */ + Success = 1 } // @generated message type with reflection information, may provide speed optimized methods class Post$Type extends MessageType { @@ -149,12 +174,15 @@ export const Post = new Post$Type(); class PostResponse$Type extends MessageType { constructor() { super("PostResponse", [ - { no: 1, name: "hash", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, - { no: 2, name: "id", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ } + { no: 1, name: "status", kind: "enum", T: () => ["Status", Status] }, + { no: 2, name: "hash", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "id", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ }, + { no: 4, name: "failed_message", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } ]); } create(value?: PartialMessage): PostResponse { const message = globalThis.Object.create((this.messagePrototype!)); + message.status = 0; message.hash = ""; message.id = 0n; if (value !== undefined) @@ -166,12 +194,18 @@ class PostResponse$Type extends MessageType { while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { - case /* string hash */ 1: + case /* Status status */ 1: + message.status = reader.int32(); + break; + case /* string hash */ 2: message.hash = reader.string(); break; - case /* uint64 id */ 2: + case /* uint64 id */ 3: message.id = reader.uint64().toBigInt(); break; + case /* optional string failed_message */ 4: + message.failedMessage = reader.string(); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -184,12 +218,18 @@ class PostResponse$Type extends MessageType { return message; } internalBinaryWrite(message: PostResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { - /* string hash = 1; */ + /* Status status = 1; */ + if (message.status !== 0) + writer.tag(1, WireType.Varint).int32(message.status); + /* string hash = 2; */ if (message.hash !== "") - writer.tag(1, WireType.LengthDelimited).string(message.hash); - /* uint64 id = 2; */ + writer.tag(2, WireType.LengthDelimited).string(message.hash); + /* uint64 id = 3; */ if (message.id !== 0n) - writer.tag(2, WireType.Varint).uint64(message.id); + writer.tag(3, WireType.Varint).uint64(message.id); + /* optional string failed_message = 4; */ + if (message.failedMessage !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.failedMessage); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); @@ -201,26 +241,26 @@ class PostResponse$Type extends MessageType { */ export const PostResponse = new PostResponse$Type(); // @generated message type with reflection information, may provide speed optimized methods -class Fetch$Type extends MessageType { +class FetchResponse$Type extends MessageType { constructor() { - super("Fetch", [ - { no: 1, name: "posts", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => Fetch_Message } + super("FetchResponse", [ + { no: 1, name: "posts", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => FetchResponse_Message } ]); } - create(value?: PartialMessage): Fetch { + create(value?: PartialMessage): FetchResponse { const message = globalThis.Object.create((this.messagePrototype!)); message.posts = []; if (value !== undefined) - reflectionMergePartial(this, message, value); + reflectionMergePartial(this, message, value); return message; } - internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Fetch): Fetch { + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FetchResponse): FetchResponse { let message = target ?? this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { - case /* repeated Fetch.Message posts */ 1: - message.posts.push(Fetch_Message.internalBinaryRead(reader, reader.uint32(), options)); + case /* repeated FetchResponse.Message posts */ 1: + message.posts.push(FetchResponse_Message.internalBinaryRead(reader, reader.uint32(), options)); break; default: let u = options.readUnknownField; @@ -233,10 +273,10 @@ class Fetch$Type extends MessageType { } return message; } - internalBinaryWrite(message: Fetch, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { - /* repeated Fetch.Message posts = 1; */ + internalBinaryWrite(message: FetchResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* repeated FetchResponse.Message posts = 1; */ for (let i = 0; i < message.posts.length; i++) - Fetch_Message.internalBinaryWrite(message.posts[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + FetchResponse_Message.internalBinaryWrite(message.posts[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join(); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); @@ -244,29 +284,31 @@ class Fetch$Type extends MessageType { } } /** - * @generated MessageType for protobuf message Fetch + * @generated MessageType for protobuf message FetchResponse */ -export const Fetch = new Fetch$Type(); +export const FetchResponse = new FetchResponse$Type(); // @generated message type with reflection information, may provide speed optimized methods -class Fetch_Message$Type extends MessageType { +class FetchResponse_Message$Type extends MessageType { constructor() { - super("Fetch.Message", [ + super("FetchResponse.Message", [ { no: 1, name: "id", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ }, { no: 2, name: "content", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, - { no: 3, name: "ref", kind: "scalar", opt: true, T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ }, - { no: 4, name: "files_id", kind: "scalar", repeat: 1 /*RepeatType.PACKED*/, T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ } + { no: 3, name: "files_hash", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "igid", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "comments_hash", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ } ]); } - create(value?: PartialMessage): Fetch_Message { + create(value?: PartialMessage): FetchResponse_Message { const message = globalThis.Object.create((this.messagePrototype!)); message.id = 0n; message.content = ""; - message.filesId = []; + message.filesHash = []; + message.commentsHash = []; if (value !== undefined) - reflectionMergePartial(this, message, value); + reflectionMergePartial(this, message, value); return message; } - internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Fetch_Message): Fetch_Message { + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FetchResponse_Message): FetchResponse_Message { let message = target ?? this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); @@ -277,15 +319,14 @@ class Fetch_Message$Type extends MessageType { case /* string content */ 2: message.content = reader.string(); break; - case /* optional uint64 ref */ 3: - message.ref = reader.uint64().toBigInt(); + case /* repeated string files_hash */ 3: + message.filesHash.push(reader.string()); break; - case /* repeated uint64 files_id */ 4: - if (wireType === WireType.LengthDelimited) - for (let e = reader.int32() + reader.pos; reader.pos < e;) - message.filesId.push(reader.uint64().toBigInt()); - else - message.filesId.push(reader.uint64().toBigInt()); + case /* optional string igid */ 4: + message.igid = reader.string(); + break; + case /* repeated string comments_hash */ 5: + message.commentsHash.push(reader.string()); break; default: let u = options.readUnknownField; @@ -298,23 +339,22 @@ class Fetch_Message$Type extends MessageType { } return message; } - internalBinaryWrite(message: Fetch_Message, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + internalBinaryWrite(message: FetchResponse_Message, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { /* uint64 id = 1; */ if (message.id !== 0n) writer.tag(1, WireType.Varint).uint64(message.id); /* string content = 2; */ if (message.content !== "") writer.tag(2, WireType.LengthDelimited).string(message.content); - /* optional uint64 ref = 3; */ - if (message.ref !== undefined) - writer.tag(3, WireType.Varint).uint64(message.ref); - /* repeated uint64 files_id = 4; */ - if (message.filesId.length) { - writer.tag(4, WireType.LengthDelimited).fork(); - for (let i = 0; i < message.filesId.length; i++) - writer.uint64(message.filesId[i]); - writer.join(); - } + /* repeated string files_hash = 3; */ + for (let i = 0; i < message.filesHash.length; i++) + writer.tag(3, WireType.LengthDelimited).string(message.filesHash[i]); + /* optional string igid = 4; */ + if (message.igid !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.igid); + /* repeated string comments_hash = 5; */ + for (let i = 0; i < message.commentsHash.length; i++) + writer.tag(5, WireType.LengthDelimited).string(message.commentsHash[i]); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); @@ -322,6 +362,6 @@ class Fetch_Message$Type extends MessageType { } } /** - * @generated MessageType for protobuf message Fetch.Message + * @generated MessageType for protobuf message FetchResponse.Message */ -export const Fetch_Message = new Fetch_Message$Type(); +export const FetchResponse_Message = new FetchResponse_Message$Type(); diff --git a/src/lib/textmark.ts b/src/lib/textmark.ts deleted file mode 100644 index 8974bbc..0000000 --- a/src/lib/textmark.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Marked } from "marked"; -import { markedHighlight } from "marked-highlight"; -import hljs from "highlight.js"; -import DOMPurify from "isomorphic-dompurify"; - - -export default class TextMark { - marked: Marked - constructor() { - this.marked = new Marked( - markedHighlight({ - emptyLangClass: 'hljs', - langPrefix: 'hljs language-', - highlight(code, lang, _) { - const language = hljs.getLanguage(lang) ? lang : 'plaintext'; - return hljs.highlight(code, { language }).value; - } - }) - ); - this.marked = this.marked.use({ - async: true, - gfm: true, - pedantic: false, - hooks: { - postprocess(e) { - return DOMPurify.sanitize(e) - } - } - }) - } - async parse(pure_mark: boolean, content: string): Promise { - if (!pure_mark) { - let processed = ""; - content.split("\n").forEach((e) => { - processed += e + " \n" - }) - content = processed; - - } - return this.marked.parse(content); - } -} - diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 1b20a8f..e940e31 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -3,7 +3,7 @@ let { children } = $props(); -
+
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 5494105..9e45d83 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,20 +1,25 @@ -
- - +
+ {#each posts as p} + + {/each} +
Loading...
- - -
-
- - -
- -
-
- - + + + + + + + +
+ 離開 + 新增文章 + +
+ +
+
+
diff --git a/src/routes/links/+page.svelte b/src/routes/links/+page.svelte new file mode 100644 index 0000000..6a8518b --- /dev/null +++ b/src/routes/links/+page.svelte @@ -0,0 +1,3 @@ +
+

IG: IG 帳號

+
diff --git a/src/routes/marker.svelte b/src/routes/marker.svelte index 4efdef1..794ce2b 100644 --- a/src/routes/marker.svelte +++ b/src/routes/marker.svelte @@ -5,13 +5,6 @@ let files: Array = []; const get_content = () => { - let length = dyn_files == undefined ? 0 : dyn_files.length; - for (let i = 0; i < length; i++) { - let item = dyn_files?.item(i); - if (item != null) { - files.push(item); - } - } return content; }; const clear_content = () => { @@ -24,9 +17,13 @@
@@ -48,16 +65,37 @@ />
- - + + + + + + +

Add a picture

+
+
+ + {#if dyn_image_links.size > 0} +
+ {#each dyn_image_links as entries} +
+ selected files + +
+ {/each} +
+ {/if}
diff --git a/src/routes/overlay.svelte b/src/routes/overlay.svelte deleted file mode 100644 index d9e97e6..0000000 --- a/src/routes/overlay.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - diff --git a/src/routes/tos/+page.svelte b/src/routes/tos/+page.svelte index c734ed3..2f849cb 100644 --- a/src/routes/tos/+page.svelte +++ b/src/routes/tos/+page.svelte @@ -1,6 +1,4 @@ -
-
-

“中工匿名”不記錄個人網路位置、名字。

-

如訊息侵害他人權利,違反大眾道德觀,皆不保證留存。

-
+
+

“中工匿名”不記錄個人姓名。

+

如訊息侵害他人權利,違反大眾道德觀,皆不保證留存。

diff --git a/vite.config.ts b/vite.config.ts index 2bed3b5..e1c2b45 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,13 +3,13 @@ import { defineConfig } from 'vite'; import Icons from 'unplugin-icons/vite' export default defineConfig({ - plugins: [sveltekit(), Icons({ compiler: 'svelte' })], - server: { - proxy: { - '/article': { - target: "http://10.16.20.17:5000", - changeOrigin: true, - } - } - } + plugins: [sveltekit(), Icons({ compiler: 'svelte' })], + server: { + proxy: { + '/article': { + target: "http://10.16.20.17:5000", + changeOrigin: true, + } + } + } });