fubi 0.4.7 → 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/.prettierignore +9 -0
  2. package/.prettierrc +23 -0
  3. package/.vscode/extensions.json +3 -0
  4. package/config.toml +3 -0
  5. package/demo/index.html +64 -0
  6. package/index.html +19 -0
  7. package/package.json +44 -39
  8. package/publish.js +77 -0
  9. package/src/components/App.svelte +17 -0
  10. package/src/components/Debug.svelte +39 -0
  11. package/src/components/Layout.svelte +47 -0
  12. package/src/components/comment/CommentCard.svelte +49 -0
  13. package/src/components/comment/CommentFocusElement.svelte +14 -0
  14. package/src/components/comment/CommentMenu.svelte +18 -0
  15. package/src/components/comment/CommentPriority.svelte +31 -0
  16. package/src/components/comment/CommentReplyButton.svelte +35 -0
  17. package/src/components/comment/CommentUser.svelte +22 -0
  18. package/src/components/icons/AlertIcon.svelte +7 -0
  19. package/src/components/icons/CancelIcon.svelte +8 -0
  20. package/src/components/icons/CheckCircle.svelte +7 -0
  21. package/src/components/icons/CheckIcon.svelte +7 -0
  22. package/src/components/icons/CheckSmallIcon.svelte +7 -0
  23. package/src/components/icons/ChevronLeftIcon.svelte +7 -0
  24. package/src/components/icons/ChevronRightIcon.svelte +7 -0
  25. package/src/components/icons/ChevronsUpIcon.svelte +8 -0
  26. package/src/components/icons/DotsIcon.svelte +9 -0
  27. package/src/components/icons/PlusIcon.svelte +8 -0
  28. package/src/components/index.ts +0 -0
  29. package/src/components/toolbar/ButtonToolbar.svelte +29 -0
  30. package/src/components/toolbar/Menu.svelte +42 -0
  31. package/src/components/toolbar/Toolbar.svelte +55 -0
  32. package/src/components/ui/Button.svelte +33 -0
  33. package/src/components/ui/ButtonIcon.svelte +31 -0
  34. package/src/components/ui/ButtonSmall.svelte +12 -0
  35. package/src/components/ui/ButtonTabbar.svelte +35 -0
  36. package/src/components/ui/Chip.svelte +28 -0
  37. package/src/components/ui/Icon.svelte +38 -0
  38. package/src/components/ui/Input.svelte +9 -0
  39. package/src/components/ui/List.svelte +18 -0
  40. package/src/components/ui/ListItem.svelte +87 -0
  41. package/src/components/ui/ListLoader.svelte +20 -0
  42. package/src/components/ui/Loader.svelte +39 -0
  43. package/src/components/ui/Logo.svelte +20 -0
  44. package/src/components/ui/Msg.svelte +21 -0
  45. package/src/components/ui/Navbar.svelte +33 -0
  46. package/src/components/ui/Page.svelte +67 -0
  47. package/src/components/ui/Tabbar.svelte +60 -0
  48. package/src/components/ui/Toggle.svelte +8 -0
  49. package/src/components/ui/Window.svelte +61 -0
  50. package/src/index.ts +28 -0
  51. package/src/lib/actions.ts +58 -0
  52. package/src/lib/haptics.ts +94 -0
  53. package/src/lib/logger.ts +22 -0
  54. package/src/lib/routes.ts +37 -0
  55. package/src/lib/utils.ts +27 -0
  56. package/src/modules/app.svelte.ts +66 -0
  57. package/src/modules/auth.svelte.ts +80 -0
  58. package/src/modules/collection.svelte.ts +79 -0
  59. package/src/modules/comments.svelte.ts +34 -0
  60. package/src/modules/dom.svelte.ts +26 -0
  61. package/src/modules/domains.svelte.ts +91 -0
  62. package/src/modules/environment.svelte.ts +10 -0
  63. package/src/modules/events.svelte.ts +23 -0
  64. package/src/modules/folders.svelte.ts +64 -0
  65. package/src/modules/home.svelte.ts +29 -0
  66. package/src/modules/hover.svelte.ts +3 -0
  67. package/src/modules/index.ts +28 -0
  68. package/src/modules/keys.svelte.ts +72 -0
  69. package/src/modules/module.svelte.ts +47 -0
  70. package/src/modules/navbar.svelte.ts +11 -0
  71. package/src/modules/pages.svelte.ts +126 -0
  72. package/src/modules/project.svelte.ts +70 -0
  73. package/src/modules/router.svelte.ts +99 -0
  74. package/src/modules/tabbar.svelte.ts +21 -0
  75. package/src/modules/teams.svelte.ts +0 -0
  76. package/src/modules/toolbar.svelte.ts +34 -0
  77. package/src/modules/watch.svelte.ts +8 -0
  78. package/src/modules/win.svelte.ts +273 -0
  79. package/src/pages/Comments.svelte +32 -0
  80. package/src/pages/Error.svelte +25 -0
  81. package/src/pages/Folders.svelte +53 -0
  82. package/src/pages/Login.svelte +44 -0
  83. package/src/pages/Pages.svelte +75 -0
  84. package/src/pages/Thread.svelte +11 -0
  85. package/src/styles/global.css +16 -0
  86. package/src/styles/router.css +79 -0
  87. package/src/styles/styles.css +159 -0
  88. package/src/styles/tailwind.css +115 -0
  89. package/src/styles/variables.css +99 -0
  90. package/src/test.ts +22 -0
  91. package/src/types/fubi.ts +0 -0
  92. package/src/types/msg.ts +5 -0
  93. package/src/types/pocketbase.ts +7 -0
  94. package/src/types/user.ts +8 -0
  95. package/svelte.config.js +11 -0
  96. package/tsconfig.json +41 -0
  97. package/vite.config.ts +40 -0
@@ -0,0 +1,9 @@
1
+ # Package Managers
2
+ package-lock.json
3
+ pnpm-lock.yaml
4
+ yarn.lock
5
+ bun.lock
6
+ bun.lockb
7
+
8
+ # Miscellaneous
9
+ /static/
package/.prettierrc ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "useTabs": true,
3
+ "tabWidth": 4,
4
+ "printWidth": 120,
5
+ "plugins": [
6
+ "prettier-plugin-svelte"
7
+ ],
8
+ "pluginSearchDirs": false,
9
+ "overrides": [
10
+ {
11
+ "files": "*.astro",
12
+ "options": {
13
+ "parser": "astro"
14
+ }
15
+ },
16
+ {
17
+ "files": "*.svelte",
18
+ "options": {
19
+ "parser": "svelte"
20
+ }
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "recommendations": ["svelte.svelte-vscode"]
3
+ }
package/config.toml ADDED
@@ -0,0 +1,3 @@
1
+ [install.scopes]
2
+ @hugeicons-pro = { token = "003AA990-E4B070EC-D2C37C6C-7AD08899", url = "https://npm.hugeicons.com/" }
3
+ #@hugeicons-pro = { token = "003AA990-E4B070EC-D2C37C6C-7AD08899", url = "https://npm.hugeicons.com/" }
@@ -0,0 +1,64 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" class="" style="background: #000; color: white;">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <title>Document</title>
8
+ <script type="module">
9
+ import { fubi } from "fubi";
10
+ fubi("lqwmo71n75ihvyj");
11
+ </script>
12
+ <style>
13
+ p {
14
+ opacity: 0;
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <h1>Test demo</h1>
21
+ <input type="text" placeholder="type something here..." />
22
+ <p>Some text</p>
23
+ <p>Some text</p>
24
+ <p>Some text</p>
25
+ <p>Some text</p>
26
+ <p>Some text</p>
27
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, exercitationem ipsa? Voluptatem quidem ipsum ipsa dicta maxime, aperiam recusandae enim neque omnis sequi! Earum quo tempore
28
+ aperiam inventore labore amet.</p>
29
+ <p>Some text</p>
30
+ <p>Some text</p>
31
+ <p>Some text</p>
32
+ <p>Some text</p>
33
+ <p>Some text</p>
34
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, exercitationem ipsa? Voluptatem quidem ipsum ipsa dicta maxime, aperiam recusandae enim neque omnis sequi! Earum quo tempore
35
+ aperiam inventore labore amet.</p>
36
+ <p>Some text</p>
37
+ <p>Some text</p>
38
+ <p>Some text</p>
39
+ <p>Some text</p>
40
+ <p>Some text</p>
41
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, exercitationem ipsa? Voluptatem quidem ipsum ipsa dicta maxime, aperiam recusandae enim neque omnis sequi! Earum quo tempore
42
+ aperiam inventore labore amet.</p>
43
+ <p>Some text</p>
44
+ <p>Some text</p>
45
+ <p>Some text</p>
46
+ <p>Some text</p>
47
+ <p>Some text</p>
48
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, exercitationem ipsa? Voluptatem quidem ipsum ipsa dicta maxime, aperiam recusandae enim neque omnis sequi! Earum quo tempore
49
+ aperiam inventore labore amet.</p>
50
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, exercitationem ipsa? Voluptatem quidem ipsum ipsa dicta maxime, aperiam recusandae enim neque omnis sequi! Earum quo tempore
51
+ aperiam inventore labore amet.</p>
52
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, exercitationem ipsa? Voluptatem quidem ipsum ipsa dicta maxime, aperiam recusandae enim neque omnis sequi! Earum quo tempore
53
+ aperiam inventore labore amet.</p>
54
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, exercitationem ipsa? Voluptatem quidem ipsum ipsa dicta maxime, aperiam recusandae enim neque omnis sequi! Earum quo tempore
55
+ aperiam inventore labore amet.</p>
56
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, exercitationem ipsa? Voluptatem quidem ipsum ipsa dicta maxime, aperiam recusandae enim neque omnis sequi! Earum quo tempore
57
+ aperiam inventore labore amet.</p>
58
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, exercitationem ipsa? Voluptatem quidem ipsum ipsa dicta maxime, aperiam recusandae enim neque omnis sequi! Earum quo tempore
59
+ aperiam inventore labore amet.</p>
60
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, exercitationem ipsa? Voluptatem quidem ipsum ipsa dicta maxime, aperiam recusandae enim neque omnis sequi! Earum quo tempore
61
+ aperiam inventore labore amet.</p>
62
+ </body>
63
+
64
+ </html>
package/index.html ADDED
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" style="background: white;">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <link rel="icon" href="/logo.png" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
+ <title>test fubi</title>
9
+ </head>
10
+
11
+ <body>
12
+ <div id="app">
13
+ <div id="fubi"></div>
14
+ <h1>This is a test</h1>
15
+ </div>
16
+ <script type="module" src="/src/test.ts"></script>
17
+ </body>
18
+
19
+ </html>
package/package.json CHANGED
@@ -2,52 +2,57 @@
2
2
  "name": "fubi",
3
3
  "description": "A lightweight, universal in-page feedback and collaboration tool for web applications. ",
4
4
  "author": "Wonder Makers",
5
- "version": "0.4.7",
5
+ "version": "1.0.0-beta.1",
6
6
  "homepage": "https://fubi.dev",
7
7
  "type": "module",
8
- "scripts": {
9
- "dev": "vite",
10
- "build": "vite build",
11
- "prepare": "tw-patch install",
12
- "preview": "vite preview",
13
- "watch": "vite build --watch",
14
- "pub": "bun run publish.js"
15
- },
16
- "files": [
17
- "src/dist"
18
- ],
19
- "main": "./src/dist/fubi.js",
20
- "module": "./src/dist/fubi.js",
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
21
11
  "exports": {
22
- ".": "./src/dist/fubi.js"
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "dev": "concurrently \"vite build --watch\" \"wait-on dist/index.js && cd demo && vite --host\"",
19
+ "build": "tsc && vite build",
20
+ "typecheck": "tsc --noEmit",
21
+ "pub": "bun run publish.js",
22
+ "format": "prettier --write .",
23
+ "lint": "prettier --check ."
23
24
  },
24
25
  "devDependencies": {
25
- "@sveltejs/vite-plugin-svelte": "^5.0.3",
26
- "postcss-import": "^16.1.0",
27
- "prettier-plugin-tailwindcss": "^0.6.11",
28
- "svelte": "^5.20.2",
29
- "tailwindcss-patch": "^7.1.1",
30
- "terser": "^5.39.0",
31
- "unplugin-tailwindcss-mangle": "^4.1.1",
32
- "vite": "^6.2.0"
26
+ "@sveltejs/vite-plugin-svelte": "^4.0.4",
27
+ "@types/node": "^20.19.17",
28
+ "astro": "^4.16.19",
29
+ "concurrently": "^9.2.1",
30
+ "prettier": "^3.4.2",
31
+ "prettier-plugin-svelte": "^3.3.3",
32
+ "svelte": "^5.39.6",
33
+ "typescript": "^5.9.2",
34
+ "vite": "^5.4.20"
33
35
  },
34
36
  "dependencies": {
35
- "@floating-ui/dom": "^1.7.0",
36
- "@fontsource/inter": "^5.2.5",
37
- "@svelte-put/clickoutside": "^4.0.0",
38
- "@tailwindcss/postcss": "^4.1.3",
39
- "fubi": "0.2.0-beta.2",
40
- "html-to-image": "^1.11.13",
41
- "lenis": "v1.1.19-dev.3",
42
- "melt": "^0.30.1",
43
- "pocketbase": "^0.25.2",
44
- "prettier": "^3.5.3",
45
- "rollup-plugin-postcss": "^4.0.2",
46
- "swiper": "^11.2.10",
47
- "tailwind": "^4.0.0",
48
- "tailwindcss": "^4.1.3",
49
- "vite-plugin-compression": "^0.5.1",
50
- "vite-plugin-css-injected-by-js": "^3.5.2"
37
+ "@hugeicons-pro/core-bulk-rounded": "^1.0.17",
38
+ "@hugeicons-pro/core-duotone-rounded": "^1.1.0",
39
+ "@hugeicons-pro/core-solid-rounded": "^1.0.17",
40
+ "@hugeicons-pro/core-stroke-rounded": "^1.0.17",
41
+ "@hugeicons-pro/core-stroke-standard": "^1.0.17",
42
+ "@hugeicons/core-free-icons": "^1.0.17",
43
+ "@hugeicons/svelte": "^1.0.2",
44
+ "@tailwindcss/vite": "^4.1.13",
45
+ "bits-ui": "^2.11.3",
46
+ "commander": "^12.1.0",
47
+ "motion": "^12.23.24",
48
+ "pocketbase": "^0.26.2",
49
+ "runed": "^0.34.0",
50
+ "tailwindcss": "^4.1.13",
51
+ "tailwindcss-animate": "^1.0.7",
52
+ "wait-on": "^8.0.5"
53
+ },
54
+ "bin": {
55
+ "fubi": "./dist/index.js"
51
56
  },
52
57
  "keywords": [
53
58
  "feedback",
package/publish.js ADDED
@@ -0,0 +1,77 @@
1
+ import { spawnSync } from "child_process";
2
+ import { readFileSync } from "fs";
3
+
4
+ // Load current version from package.json
5
+ function getCurrentVersion() {
6
+ const packageJson = JSON.parse(readFileSync("./package.json", "utf8"));
7
+ return packageJson.version;
8
+ }
9
+
10
+ const currentVersion = getCurrentVersion();
11
+ const isBeta = currentVersion.includes("-beta.");
12
+ console.log(
13
+ `Current version: ${currentVersion} (${isBeta ? "beta" : "stable"})`
14
+ );
15
+
16
+ const args = process.argv.slice(2);
17
+ let newVersion = null;
18
+
19
+ if (args.length > 0) {
20
+ const arg = args[0].replace("--", "");
21
+ if (arg.startsWith("v") || arg.match(/^\d+\.\d+\.\d+(?:-beta\.\d+)?$/)) {
22
+ // Check if argument looks like a version
23
+ newVersion = arg;
24
+ } else {
25
+ console.error(
26
+ 'Invalid argument. Provide a version number like "1.2.3" or "v1.2.3".'
27
+ );
28
+ process.exit(1);
29
+ }
30
+ } else {
31
+ console.log(
32
+ "No version specified. You will need to manually update the version in package.json before publishing."
33
+ );
34
+ }
35
+
36
+ function runCommand(command, args) {
37
+ const result = spawnSync(command, args, { stdio: "inherit", shell: true });
38
+ if (result.status !== 0) {
39
+ console.error(`Command failed: ${command} ${args.join(" ")}`);
40
+ process.exit(1);
41
+ }
42
+ }
43
+
44
+ console.log("🏗️ Starting build and publish process...");
45
+ console.log("🧹 Cleaning dist directory...");
46
+ runCommand("rm", ["-rf", "./dist"]);
47
+
48
+ console.log("📦 Building project...");
49
+ runCommand("bun", ["run", "build"]);
50
+
51
+ console.log("📝 Committing changes...");
52
+ runCommand("git", ["add", "."]);
53
+ runCommand("git", ["commit", "-m", "\"build: prepare for publish\""]);
54
+
55
+ // If new version was specified, update package.json
56
+ if (newVersion) {
57
+ console.log(`📝 Setting version to ${newVersion}...`);
58
+ // Make sure `bun version` doesn't auto-increment
59
+ runCommand("bun", ["version", newVersion]);
60
+ }
61
+
62
+ console.log("🔄 Pushing changes to git...");
63
+ runCommand("git", ["push"]);
64
+ runCommand("git", ["push", "--tags"]);
65
+
66
+ console.log("🚀 Publishing to npm...");
67
+ // Publishing with appropriate tag based on version type
68
+ const finalVersion = getCurrentVersion();
69
+ const isFinalVersionBeta = finalVersion.includes("-beta.");
70
+
71
+ if (isFinalVersionBeta) {
72
+ runCommand("bun", ["publish", "--access", "public", "--tag", "beta"]);
73
+ } else {
74
+ runCommand("bun", ["publish", "--access", "public"]);
75
+ }
76
+
77
+ console.log(`✅ Published successfully! New version: ${finalVersion}`);
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import { setContext } from "svelte";
3
+ import { createApp } from "@modules/app.svelte"
4
+
5
+ // components
6
+ import Debug from "./Debug.svelte";
7
+ import Window from "./ui/Window.svelte";
8
+ import Toolbar from "./toolbar/Toolbar.svelte";
9
+
10
+ const { projectId, wrapper } = $props();
11
+
12
+ setContext("app", createApp({ projectId, wrapper }));
13
+ </script>
14
+
15
+ <Debug />
16
+ <Window />
17
+ <Toolbar />
@@ -0,0 +1,39 @@
1
+ <script lang="ts">
2
+ import { getModules } from "@modules";
3
+
4
+ const { win, auth, pages, project, folders, router, domains } = getModules();
5
+
6
+ const infos = $derived.by(() => new Map([
7
+ // ["Project", project.id],
8
+ // ["isTeamMember", JSON.stringify(project.isTeamMember)],
9
+ // ["Folder", folders.current?.id],
10
+ //["hasFolderAccess", folders.hasAccess],
11
+ //["User", JSON.stringify(auth?.user?.id)],
12
+ // ["Route", router?.current?.name],
13
+ // ["Domains", domains?.data?.length],
14
+ //["dragging", win.dragging.active],
15
+ //["hasMoved", win.dragging.hasMoved],
16
+ //["Pages", pages?.data?.length],
17
+
18
+ // pages
19
+ ["filters", pages.filters],
20
+
21
+ // router
22
+ //["currentRoute:", router.current],
23
+ //["nextRoute:", router.next],
24
+ //["previousRoute", router.previous]
25
+
26
+ // win
27
+ //["opened", win.opened],
28
+ //["drag", win.dragging.active],
29
+ //["current", win.currentBreakpoint],
30
+ //["next", win.nextBreakpoint],
31
+ //["height", win.dragging.height]
32
+ ]));
33
+ </script>
34
+
35
+ <div class="fixed bottom-8 touch:top-8 touch:bottom-auto max-w-250 left-8 bg-black text-white/50 p-16 font-mono rounded-lg text-xs/none flex flex-col space-y-8 divide-white/10 [&_span]:text-white">
36
+ {#each infos as [key, value]}
37
+ <p>{key}: <span>{value}</span></p>
38
+ {/each}
39
+ </div>
@@ -0,0 +1,47 @@
1
+ <script lang="ts">
2
+ import { Spring } from "svelte/motion";
3
+
4
+ let animatedSize = new Spring(0, {
5
+ stiffness: 0.08,
6
+ damping: 0.5
7
+ });
8
+
9
+ let contentHeight = $state(0);
10
+ let contentWidth = $state(0);
11
+
12
+ $effect(() => {
13
+ const size = animate === 'width' ? contentWidth : contentHeight;
14
+ animatedSize.set(size);
15
+ })
16
+
17
+ const {
18
+ children = null,
19
+ clip = false,
20
+ class: className = "",
21
+ classOutter = "",
22
+ animate = 'height',
23
+ ...rest
24
+ }: {
25
+ children?: any,
26
+ clip?: boolean,
27
+ class?: string,
28
+ classOutter?: string,
29
+ animate?: 'width' | 'height'
30
+ } = $props();
31
+ </script>
32
+
33
+ <div
34
+ style={`${animate}: ${animatedSize.current}px;`}
35
+ class={[clip && "overflow-clip", classOutter]}
36
+ {...rest}
37
+ >
38
+ <div
39
+ class={[animate === "width" && "w-fit", className]}
40
+ bind:clientHeight={contentHeight}
41
+ bind:clientWidth={contentWidth}
42
+ >
43
+ {#if children}
44
+ {@render children()}
45
+ {/if}
46
+ </div>
47
+ </div>
@@ -0,0 +1,49 @@
1
+ <script lang="ts">
2
+ import CommentPriority from "./CommentPriority.svelte";
3
+ import CommentFocusElement from "./CommentFocusElement.svelte";
4
+ import CommentUser from "./CommentUser.svelte";
5
+ import CommentMenu from "./CommentMenu.svelte";
6
+ import CommentReplyButton from "./CommentReplyButton.svelte";
7
+
8
+ import { getModules } from "@modules/index";
9
+ import type { CommentType } from "@modules/comments.svelte";
10
+
11
+ let { expand, text, element, unread, replies }: CommentType = $props();
12
+
13
+ const { router } = getModules();
14
+
15
+ const handleReplySelection = () => {
16
+ router.goto("thread");
17
+ }
18
+ </script>
19
+
20
+ <div
21
+ class={[
22
+ "p-10 rounded-[20px] touch:rounded-[26px] touch:p-12 flex flex-col gap-8",
23
+ unread ? "bg-slate-500/10" : "bg-slate-500/5",
24
+ ]}
25
+ >
26
+ <!-- header -->
27
+ <div class="flex justify-between items-center">
28
+ <CommentUser author={expand?.createdBy} />
29
+
30
+ <div class="flex gap-4 items-center">
31
+ <CommentFocusElement {element} />
32
+ <CommentPriority />
33
+ <CommentMenu />
34
+ </div>
35
+ </div>
36
+
37
+ <!-- msg -->
38
+ <p
39
+ class={[
40
+ "flex px-4 text-[13px] touch:text-[15px]",
41
+ unread ? "text-slate-100" : "text-slate-300"
42
+ ]}
43
+ >{text}</p>
44
+
45
+ <!-- actions -->
46
+ <div class="flex justify-between items-center pt-4">
47
+ <CommentReplyButton onclick={() => handleReplySelection()} {replies} />
48
+ </div>
49
+ </div>
@@ -0,0 +1,14 @@
1
+ <script lang="ts">
2
+ import Icon from "@ui/Icon.svelte";
3
+
4
+ let { element = null }: { element?: string | null } = $props();
5
+ </script>
6
+
7
+ <div class={[
8
+ "flex-center size-22 touch:size-28 rounded-[6px] touch:rounded-[8px]",
9
+ element ? "" : "bg-amber-600/10"
10
+ ]}>
11
+ {#if element === null}
12
+ <Icon name="alert" class="size-16 touch:size-20 text-amber-600" />
13
+ {/if}
14
+ </div>
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import Icon from "@ui/Icon.svelte";
3
+
4
+ let { checked = $bindable(false)} = $props();
5
+ </script>
6
+
7
+
8
+ <label
9
+ class={[
10
+ "flex-center size-22 touch:size-28 rounded-[6px] touch:rounded-[8px] relative touch:bg-slate-500/0",
11
+ "active:scale-95 transition-[scale] duration-100 will-change-[scale]",
12
+ "hover:bg-slate-500/20 active:bg-slate-500/10 text-slate-400/50 hover:text-slate-300 active:text-slate-300"
13
+
14
+ ]}
15
+ >
16
+ <span class="sr-only">Toggle Comment menu</span>
17
+ <Icon name="dots" class="size-16 mouse:size-14" />
18
+ </label>
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ import { haptics } from "@lib/haptics";
3
+ import Icon from "@ui/Icon.svelte";
4
+
5
+ let { checked = $bindable(false)} = $props();
6
+ </script>
7
+
8
+
9
+ <label class="flex-center size-22 touch:size-28 rounded-[6px] touch:rounded-[8px] relative cursor-pointer">
10
+ <input
11
+ type="checkbox"
12
+ class={[
13
+ "peer absolute inset-0 w-full h-full rounded-[6px] touch:rounded-[8px] appearance-none cursor-pointer",
14
+ "transition-[scale,background-color,color] duration-100 will-change-[scale]",
15
+ "active:scale-95",
16
+ "hover:bg-slate-500/20 active:bg-red-400/10",
17
+ "checked:bg-red-400/10 checked:hover:bg-red-400/20 checked:active:bg-red-400/10",
18
+ "focus-visible:ring-2 focus-visible:ring-sky-500/50 focus-visible:ring-offset-2 focus-visible:ring-offset-neutral-900"
19
+ ]}
20
+ bind:checked
21
+ onchange={() => haptics()}
22
+ />
23
+ <span class="sr-only">Add High Priority</span>
24
+ <Icon
25
+ name="chevrons-up"
26
+ class={[
27
+ "size-16 mouse:size-14 pointer-events-none relative z-10 text-slate-400/50",
28
+ "peer-hover:text-slate-300 peer-active:text-red-400",
29
+ "peer-checked:text-red-400 peer-checked:peer-hover:text-red-400 peer-checked:peer-active:text-red-400"
30
+ ]} />
31
+ </label>
@@ -0,0 +1,35 @@
1
+ <script lang="ts">
2
+ import { cubicOut } from "svelte/easing";
3
+ import { fly } from "svelte/transition";
4
+
5
+ import Icon from "@ui/Icon.svelte";
6
+ import { HugeiconsIcon } from "@hugeicons/svelte";
7
+
8
+ // icons
9
+ import { Comment03Icon } from '@hugeicons-pro/core-solid-rounded';
10
+
11
+ const { replies = 0, ...rest } = $props();
12
+ </script>
13
+
14
+ <button
15
+ class={[
16
+ "h-32 mouse:h-28 font-medium rounded-[10px] pr-6 pl-6 text-[14px]/none flex items-center gap-5 select-none",
17
+ "touch:rounded-[12px] touch:pr-8 touch:pl-8 touch:text-[15px]/none",
18
+ " active:scale-95",
19
+ "transition-[background-color,transform] duration-200 ease-out-cubic",
20
+ replies > 0
21
+ ? "text-sky-500 bg-sky-500/10 hover:bg-sky-500/20 active:bg-sky-500/10 touch:active:bg-sky-500/20"
22
+ : "text-slate-500/80 bg-slate-500/10 hover:bg-slate-500/20 active:bg-slate-500/10 touch:active:bg-slate-500/20"
23
+ ]}
24
+ {...rest}
25
+ >
26
+ <HugeiconsIcon icon={Comment03Icon} className="size-20 touch:size-22 mt-1" />
27
+ {#key replies}
28
+ <p
29
+ in:fly={{ y: -10, duration: 200, easing: cubicOut }}
30
+ out:fly={{ y: 10, duration: 200, easing: cubicOut }}
31
+ class="pb-1"
32
+ >{replies === 0 ? `Reply` : replies > 1 ? `${replies} Replies` : `1 Reply`}</p>
33
+ {/key}
34
+ <Icon name="chevron-right" class="h-12" />
35
+ </button>
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ //import defaultAvatar from "@assets/images/default-avatar.png";
3
+ import { getAssetUrl } from "@lib/utils";
4
+
5
+ let { author = null } = $props();
6
+
7
+ let { firstName, lastName } = author;
8
+
9
+ let avatarUrl = getAssetUrl(author, "avatar");
10
+ </script>
11
+
12
+ <div class="flex gap-6 items-bottom">
13
+ {#if avatarUrl}
14
+ <img src={avatarUrl} alt={firstName + " " + lastName} class="size-28 touch:size-34 rounded-full bg-white/10 glass" />
15
+ {:else}
16
+ <div class="size-29 bg-sky-500/10 rounded-full"></div>
17
+ {/if}
18
+ <div class="flex flex-col justify-center gap-2 bg-white/0 touch:-translate-y-4">
19
+ <p class="mouse:text-sm/none font-medium">{firstName} {lastName}</p>
20
+ <p class="text-xs/none text-slate-500/40">2 min</p>
21
+ </div>
22
+ </div>
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ const { ...rest } = $props();
3
+ </script>
4
+
5
+ <svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...rest}>
6
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M7.17141 1.03597C7.96854 -0.345378 10.0314 -0.345267 10.8286 1.03597L17.7339 13.0067C18.5086 14.3497 17.5 15.9998 15.9048 15.9998H2.09523C0.500172 15.9998 -0.508327 14.3496 0.266132 13.0067L7.17141 1.03597ZM9.00051 11.9998C8.44828 11.9998 8.00061 12.4476 8.00051 12.9998C8.00051 13.5521 8.44822 13.9998 9.00051 13.9998C9.55265 13.9997 10.0005 13.552 10.0005 12.9998C10.0004 12.4477 9.55259 12 9.00051 11.9998ZM9.00051 3.99983C8.44828 3.99983 8.00061 4.44764 8.00051 4.99984V9.99984C8.00051 10.5521 8.44822 10.9998 9.00051 10.9998C9.55265 10.9997 10.0005 10.552 10.0005 9.99984V4.99984C10.0004 4.44773 9.55259 4 9.00051 3.99983Z" fill="currentColor"/>
7
+ </svg>
@@ -0,0 +1,8 @@
1
+ <script lang="ts">
2
+ const { ...rest } = $props();
3
+ </script>
4
+
5
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" {...rest}>
6
+ <path d="M12 2L2 12" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="bevel"/>
7
+ <path d="M12 12L2 2" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="bevel"/>
8
+ </svg>
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ const { ...rest } = $props();
3
+ </script>
4
+
5
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" {...rest}>
6
+ <path d="M12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12C0 5.37258 5.37258 0 12 0ZM18.3838 8.11621C17.8956 7.62806 17.1044 7.62806 16.6162 8.11621L10.5 14.2324L7.88379 11.6162C7.39563 11.1281 6.60437 11.1281 6.11621 11.6162C5.62806 12.1044 5.62806 12.8956 6.11621 13.3838L9.04785 16.3154C9.84982 17.1174 11.1502 17.1174 11.9521 16.3154L18.3838 9.88379C18.8719 9.39563 18.8719 8.60437 18.3838 8.11621Z" fill="currentColor"/>
7
+ </svg>
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ const { ...rest } = $props();
3
+ </script>
4
+
5
+ <svg width="16" height="12" viewBox="0 0 16 12" fill="none" xmlns="http://www.w3.org/2000/svg" {...rest}>
6
+ <path d="M2 7L5.33709 10.3371C5.7032 10.7032 6.2968 10.7032 6.66291 10.3371L14 3" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
7
+ </svg>
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ const { ...rest } = $props();
3
+ </script>
4
+
5
+ <svg width="14" height="10" viewBox="0 0 14 10" fill="none" xmlns="http://www.w3.org/2000/svg" {...rest}>
6
+ <path d="M2 5.5L4.91995 8.41995C5.2403 8.7403 5.7597 8.7403 6.08005 8.41995L12.5 2" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
7
+ </svg>
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ const { ...rest } = $props();
3
+ </script>
4
+
5
+ <svg width="12" height="16" viewBox="0 0 12 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...rest}>
6
+ <path d="M8 2L2 8.0001L8 14" stroke="currentColor" stroke-width="2.5" stroke-miterlimit="16" stroke-linecap="round" stroke-linejoin="round"/>
7
+ </svg>
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ const { ...rest } = $props();
3
+ </script>
4
+
5
+ <svg width="10" height="16" viewBox="0 0 10 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...rest}>
6
+ <path d="M2.00005 2L8 8L2 14" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
7
+ </svg>