Skip to content

Commit

Permalink
A fresh UI for adding and viewing
Browse files Browse the repository at this point in the history
  • Loading branch information
derwebcoder committed Sep 23, 2024
1 parent 61dbaa9 commit f0f4f14
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 38 deletions.
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@tiptap/react": "^2.6.6",
"@tiptap/starter-kit": "^2.6.6",
"astro": "^4.14.3",
"date-fns": "^4.1.0",
"dexie": "^4.0.8",
"dexie-react-hooks": "^1.1.7",
"preline": "^2.4.1",
Expand Down
72 changes: 68 additions & 4 deletions src/application/SparkList/SparkList.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,78 @@
import { useLiveQuery } from "dexie-react-hooks";
import { sparkService } from "../../scripts/db/SparkService";
import { format } from "date-fns";
import type Spark from "../../interfaces/Spark";

export const SparkList = () => {
const sparks = useLiveQuery(() => sparkService.listSparks());

const grouped = sparks?.reduce<
{
key: string;
prefixTags: string[];
sparks: Spark[];
}[]
>((tmpGrouped, spark) => {
const prevKey =
tmpGrouped.length > 0
? tmpGrouped[tmpGrouped.length - 1].key
: `${Math.random()}`;
const nextKey =
spark.contextTags.length > 0
? spark.contextTags.join("/")
: `${Math.random()}`;
if (prevKey === "" || prevKey !== nextKey) {
tmpGrouped.push({
key: nextKey,
prefixTags: spark.contextTags,
sparks: [spark],
});
return tmpGrouped;
}

tmpGrouped[tmpGrouped.length - 1].sparks.push(spark);
return tmpGrouped;
}, []);

return (
<ul>
{sparks?.map((spark) => (
<li key={spark.id}>{spark.plainText}</li>
<div className="flex flex-col gap-16 py-10 bg-white h-full overflow-y-auto px-8">
{grouped?.map((group) => (
<section
key={group.key}
className="grid grid-cols-[25%_1fr] gap-8"
>
<div className="py-2 border-e border-slate-300 pe-4">
<div className="sticky top-1 flex flex-col gap-1">
{group.prefixTags.map((tag) => (
<span
key={tag}
className="font-bold text-md text-neutral-400"
>
{tag}
</span>
))}
</div>
</div>
<div className="flex flex-col gap-10 py-2">
{group.sparks?.map((spark) => (
<article
key={spark.id}
className="flex flex-col gap-1"
>
<p className="text-neutral-900">
{spark.plainText}
</p>
<span className="text-neutral-500 font-thin text-xs ps-2">
{format(
new Date(spark.creationDate),
"dd.MM.yyyy",
)}
</span>
</article>
))}
</div>
</section>
))}
</ul>
</div>
);
};
4 changes: 2 additions & 2 deletions src/layouts/BaseLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { title } = Astro.props;
---

<!doctype html>
<html lang="en" class="bg-base-100">
<html lang="en" class="bg-slate-100 h-full">
<head>
<meta charset="UTF-8" />
<meta name="robots" content="noindex" />
Expand All @@ -18,7 +18,7 @@ const { title } = Astro.props;
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body class="hidden">
<body class="hidden h-full">
<slot />
</body>
</html>
Expand Down
27 changes: 12 additions & 15 deletions src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,17 @@ import Layout from "../layouts/BaseLayout.astro";
<!-- <script src="../scripts/pip.ts"></script>
<script src="../scripts/db/index.ts"></script> -->
<Layout title="Sparktags Demo Page">
<main>
<h1>Sparktag - Under Construction</h1>

<div>
<label>
<span>New spark</span>
<SparkInput client:only />
</label>
<div>
<span>Sparks</span>
<SparkList client:only />
</div>
</div>

<p>sparktag@derwebcoder.de</p>
<main class="grid lg:grid-cols-[1fr_400px_600px_1fr] gap-6 h-full relative">
<div></div>
<aside
class="py-10 flex justify-between flex-col max-h-screen sticky top-0"
>
<SparkInput client:only />
<p>sparktag@derwebcoder.de</p>
</aside>
<section>
<SparkList client:only />
</section>
<div></div>
</main>
</Layout>
10 changes: 7 additions & 3 deletions src/scripts/db/SparkService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ export class SparkService {
constructor(private db: AppDB) {}

public async addSpark(plainText: string, html: string) {
const [prefixTags, remainingTags] = extractTags(plainText);
const [prefixTags, remainingTags, strippedContent] =
extractTags(plainText);
await this.db.sparks.add({
plainText,
plainText: strippedContent,
html,
creationDate: Date.now(),
tags: remainingTags,
Expand All @@ -25,7 +26,10 @@ export class SparkService {
}

public async listSparks() {
return await this.db.sparks.toCollection().sortBy("creationDate");
return await this.db.sparks
.toCollection()
.reverse()

Check failure on line 31 in src/scripts/db/SparkService.ts

View workflow job for this annotation

GitHub Actions / unit-tests

src/scripts/db/SparkService.test.ts > SparkService > listSparks > returns a sorted list of sparks from the database

TypeError: this.db.sparks.toCollection(...).reverse is not a function ❯ SparkService.listSparks src/scripts/db/SparkService.ts:31:5 ❯ src/scripts/db/SparkService.test.ts:61:23
.sortBy("creationDate");
}
}

Expand Down
20 changes: 16 additions & 4 deletions src/scripts/utils/stringUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,55 @@ describe("extractTags", () => {
const content = "#tag1 #tag2 I am great #tag3";
const expectedPrefixTags = ["#tag1", "#tag2"];
const expectedRemainingTags = ["#tag3"];
const expectStrippedContent = "I am great #tag3";

const [prefixTags, remainingTags] = extractTags(content);
const [prefixTags, remainingTags, strippedContent] =
extractTags(content);

expect(prefixTags).toEqual(expectedPrefixTags);
expect(remainingTags).toEqual(expectedRemainingTags);
expect(strippedContent).toEqual(expectStrippedContent);
});

test("returns empty arrays when there are no tags", () => {
const content = "This is a sample text without any tags";
const expectedPrefixTags: string[] = [];
const expectedRemainingTags: string[] = [];
const expectStrippedContent = "This is a sample text without any tags";

const [prefixTags, remainingTags] = extractTags(content);
const [prefixTags, remainingTags, strippedContent] =
extractTags(content);

expect(prefixTags).toEqual(expectedPrefixTags);
expect(remainingTags).toEqual(expectedRemainingTags);
expect(strippedContent).toEqual(expectStrippedContent);
});

test("returns empty arrays when the content is empty", () => {
const content = "";
const expectedPrefixTags: string[] = [];
const expectedRemainingTags: string[] = [];
const expectStrippedContent = "";

const [prefixTags, remainingTags] = extractTags(content);
const [prefixTags, remainingTags, strippedContent] =
extractTags(content);

expect(prefixTags).toEqual(expectedPrefixTags);
expect(remainingTags).toEqual(expectedRemainingTags);
expect(strippedContent).toEqual(expectStrippedContent);
});

test("returns empty prefixTags and correct remainingTags when there are no prefix tags and one or more remaining tags", () => {
const content = "Hello world #tag1 #tag2 #tag3";
const expectedPrefixTags: string[] = [];
const expectedRemainingTags = ["#tag1", "#tag2", "#tag3"];
const expectStrippedContent = "Hello world #tag1 #tag2 #tag3";

const [prefixTags, remainingTags] = extractTags(content);
const [prefixTags, remainingTags, strippedContent] =
extractTags(content);

expect(prefixTags).toEqual(expectedPrefixTags);
expect(remainingTags).toEqual(expectedRemainingTags);
expect(strippedContent).toEqual(expectStrippedContent);
});
});
10 changes: 7 additions & 3 deletions src/scripts/utils/stringUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@
* @returns An array containing two arrays: prefixTags and remainingTags.
* - prefixTags: An array of tags that have a prefix.
* - remainingTags: An array of tags without a prefix.
* - strippedContent: The content without the prefixTags
*/
export const extractTags = (content: string): [string[], string[]] => {
export const extractTags = (content: string): [string[], string[], string] => {
const token = content.split(" ");

const prefixTags: string[] = [];
let prefixTagsLength = 0;
while (token.length > 0 && token[0].startsWith("#")) {
console.log("look", token[0]);
prefixTags.push(token[0]);
prefixTagsLength += token[0].length;
token.shift();
}

const remainingTags = token.filter((t) => t.startsWith("#"));

return [prefixTags, remainingTags];
const strippedContent = content.slice(prefixTagsLength + prefixTags.length);

return [prefixTags, remainingTags, strippedContent];
};
7 changes: 1 addition & 6 deletions src/ui/components/TextInput/TextInput.config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ import StarterKit from "@tiptap/starter-kit";

export const extensions = [
StarterKit.configure({
paragraph: {
HTMLAttributes: {
class: "text-gray-800 dark:text-neutral-200",
},
},
bold: {
HTMLAttributes: {
class: "font-bold",
Expand All @@ -31,7 +26,7 @@ export const extensions = [
},
}),
Placeholder.configure({
placeholder: "Add a message, if you'd like.",
placeholder: "Your next spark",
emptyNodeClass: "text-gray-400 dark:text-neutral-200",
}),
ListKeymap,
Expand Down
7 changes: 6 additions & 1 deletion src/ui/components/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { EditorContent, useEditor, type Editor } from "@tiptap/react";
import { extensions } from "./TextInput.config";
import "./TextInput.css";
import { extractTags } from "../../../scripts/utils/stringUtils";

export type TextInputProps = {
onSubmit?: (plainText: string, html: string) => void;
Expand All @@ -15,7 +16,7 @@ export const TextInput = (props: TextInputProps) => {
editorProps: {
attributes: {
"aria-label": "Add a spark",
class: "p-4 block w-full border border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600",
class: "p-4 min-h-32 block w-full bg-white border border-blue-300 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600",
},
handleKeyDown: (view, event) => {
if (!onSubmit) {
Expand All @@ -30,6 +31,10 @@ export const TextInput = (props: TextInputProps) => {
return false;
}
onSubmit(plainText, html);
const [prefixTags] = extractTags(plainText);
editor?.commands.setContent(`${prefixTags.join(" ")} `, false, {
preserveWhitespace: true,
});
return true;
},
},
Expand Down
1 change: 1 addition & 0 deletions tailwind.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export default {
require("@tailwindcss/forms"),
require("preline/plugin"),
],
darkMode: "selector",
};

0 comments on commit f0f4f14

Please sign in to comment.