+ );
+};
+
+export default Viewer;
diff --git a/components/LongFormContentCard/index.tsx b/components/LongFormContentCard/index.tsx
new file mode 100644
index 0000000..8d3399e
--- /dev/null
+++ b/components/LongFormContentCard/index.tsx
@@ -0,0 +1,83 @@
+"use client";
+import Image from "next/image";
+import Link from "next/link";
+import { RiMoreFill } from "react-icons/ri";
+import { HiOutlineLightningBolt } from "react-icons/hi";
+import {
+ HiOutlineHandThumbUp,
+ HiOutlineChatBubbleLeftEllipsis,
+ HiOutlineEllipsisHorizontal,
+} from "react-icons/hi2";
+
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card";
+import { Avatar, AvatarImage, AvatarFallback } from "@radix-ui/react-avatar";
+import { formatDate } from "@/lib/utils/dates";
+import { Button } from "../ui/button";
+
+type CreatorCardProps = {
+ displayName: string;
+ about: string;
+ picture: string;
+ banner: string;
+};
+
+export default function LongFormContentCard() {
+ return (
+
+
+
+
+
+ SC
+
+
+ Derek Seivers
+
+
+
+ {formatDate(new Date("10-5-23"), "MMM Do")}
+
+
+
+
+
+ The start of the Nostr revolution
+
+
+ This is the summary of this artilce. Let's hope that it is a good
+ article and that it will end up being worth reading. I don't want to
+ waste my time on some random other stuff.
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/components/spinner.tsx b/components/spinner.tsx
new file mode 100644
index 0000000..8375f73
--- /dev/null
+++ b/components/spinner.tsx
@@ -0,0 +1,26 @@
+const Spinner = () => {
+ return (
+
+ );
+};
+
+export default Spinner;
diff --git a/lib/utils/dates.ts b/lib/utils/dates.ts
index 7939775..8cb9a44 100644
--- a/lib/utils/dates.ts
+++ b/lib/utils/dates.ts
@@ -1,73 +1,81 @@
import dayjs from "dayjs";
import relative from "dayjs/plugin/relativeTime";
import updateLocale from "dayjs/plugin/updateLocale";
+import advancedFormat from "dayjs/plugin/advancedFormat";
+import timezone from "dayjs/plugin/timezone";
+
export function relativeTimeUnix(timestamp: number) {
- const config = {
- thresholds: [
- { l: "s", r: 1 },
- { l: "m", r: 1 },
- { l: "mm", r: 59, d: "minute" },
- { l: "h", r: 1 },
- { l: "hh", r: 23, d: "hour" },
- { l: "d", r: 1 },
- { l: "dd", r: 364, d: "day" },
- { l: "y", r: 1 },
- { l: "yy", d: "year" },
- ],
- rounding: Math.floor,
- };
- dayjs.extend(updateLocale);
-
- dayjs.updateLocale("en", {
- relativeTime: {
- future: "in %s",
- past: "%s ago",
- s: "%s seconds",
- m: "1 min",
- mm: "%d mins",
- h: "1 hour",
- hh: "%d hours",
- d: "1 day",
- dd: "%d days",
- y: "1 year",
- yy: "%d years",
- },
- });
- dayjs.extend(relative, config);
- return dayjs(timestamp * 1000).fromNow();
- }
- export function relativeTime(timestamp: Date) {
- const config = {
- thresholds: [
- { l: "s", r: 1 },
- { l: "m", r: 1 },
- { l: "mm", r: 59, d: "minute" },
- { l: "h", r: 1 },
- { l: "hh", r: 23, d: "hour" },
- { l: "d", r: 1 },
- { l: "dd", r: 364, d: "day" },
- { l: "y", r: 1 },
- { l: "yy", d: "year" },
- ],
- rounding: Math.floor,
- };
- dayjs.extend(updateLocale);
-
- dayjs.updateLocale("en", {
- relativeTime: {
- future: "in %s",
- past: "%s ago",
- s: "%s seconds",
- m: "1 min",
- mm: "%d mins",
- h: "1 hour",
- hh: "%d hours",
- d: "1 day",
- dd: "%d days",
- y: "1 year",
- yy: "%d years",
- },
- });
- dayjs.extend(relative, config);
- return dayjs(timestamp).fromNow();
- }
\ No newline at end of file
+ const config = {
+ thresholds: [
+ { l: "s", r: 1 },
+ { l: "m", r: 1 },
+ { l: "mm", r: 59, d: "minute" },
+ { l: "h", r: 1 },
+ { l: "hh", r: 23, d: "hour" },
+ { l: "d", r: 1 },
+ { l: "dd", r: 364, d: "day" },
+ { l: "y", r: 1 },
+ { l: "yy", d: "year" },
+ ],
+ rounding: Math.floor,
+ };
+ dayjs.extend(updateLocale);
+
+ dayjs.updateLocale("en", {
+ relativeTime: {
+ future: "in %s",
+ past: "%s ago",
+ s: "%s seconds",
+ m: "1 min",
+ mm: "%d mins",
+ h: "1 hour",
+ hh: "%d hours",
+ d: "1 day",
+ dd: "%d days",
+ y: "1 year",
+ yy: "%d years",
+ },
+ });
+ dayjs.extend(relative, config);
+ return dayjs(timestamp * 1000).fromNow();
+}
+export function relativeTime(timestamp: Date) {
+ const config = {
+ thresholds: [
+ { l: "s", r: 1 },
+ { l: "m", r: 1 },
+ { l: "mm", r: 59, d: "minute" },
+ { l: "h", r: 1 },
+ { l: "hh", r: 23, d: "hour" },
+ { l: "d", r: 1 },
+ { l: "dd", r: 364, d: "day" },
+ { l: "y", r: 1 },
+ { l: "yy", d: "year" },
+ ],
+ rounding: Math.floor,
+ };
+ dayjs.extend(updateLocale);
+
+ dayjs.updateLocale("en", {
+ relativeTime: {
+ future: "in %s",
+ past: "%s ago",
+ s: "%s seconds",
+ m: "1 min",
+ mm: "%d mins",
+ h: "1 hour",
+ hh: "%d hours",
+ d: "1 day",
+ dd: "%d days",
+ y: "1 year",
+ yy: "%d years",
+ },
+ });
+ dayjs.extend(relative, config);
+ return dayjs(timestamp).fromNow();
+}
+export function formatDate(timestamp: Date, format?: string) {
+ dayjs.extend(advancedFormat);
+ dayjs.extend(timezone);
+ return dayjs(timestamp).format(format ?? "MMMM Do, YYYY");
+}
diff --git a/package.json b/package.json
index 511fe7e..09c5247 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,8 @@
"lint": "next lint"
},
"dependencies": {
+ "@blocknote/core": "^0.9.5",
+ "@blocknote/react": "^0.9.5",
"@hookform/resolvers": "^3.3.2",
"@noble/hashes": "^1.3.2",
"@nostr-dev-kit/ndk": "^2.0.0",
@@ -29,6 +31,7 @@
"focus-trap-react": "^10.2.3",
"framer-motion": "^10.16.4",
"next": "13.5.4",
+ "next-themes": "^0.2.1",
"node-html-parser": "^6.1.10",
"nostr-tools": "^1.16.0",
"ramda": "^0.29.1",
@@ -45,6 +48,7 @@
"zustand": "^4.4.3"
},
"devDependencies": {
+ "@tailwindcss/typography": "^0.5.10",
"@types/crypto-js": "^4.1.2",
"@types/node": "^20",
"@types/ramda": "^0.29.6",
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 3d9b16b..e49271a 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -84,16 +84,20 @@ module.exports = {
80: 80,
90: 90,
99: 99,
- mobileTabs: 980,
- "header-": 989,
- header: 990,
- "header+": 991,
- headerDialog: 991,
- "modal-": 995,
- modal: 996,
- "modal+": 997,
- "top-": 998,
- top: 999,
+ mobileTabs: 900,
+ "header-": 919,
+ header: 920,
+ "header+": 921,
+ headerDialog: 922,
+ "overlay-": 929,
+ overlay: 930,
+ "overlay+": 931,
+ "modal-": 939,
+ modal: 940,
+ "modal+": 941,
+ "top-": 949,
+ top: 950,
+ "top+": 951,
},
flex: {
2: 2,
@@ -106,5 +110,6 @@ module.exports = {
require("tailwindcss-animate"),
require("@tailwindcss/container-queries"),
require("tailwind-scrollbar"),
+ require("@tailwindcss/typography"),
],
};
diff --git a/test.md b/test.md
new file mode 100644
index 0000000..c03243e
--- /dev/null
+++ b/test.md
@@ -0,0 +1,221 @@
+# h1 Heading 8-)
+
+## h2 Heading
+
+### h3 Heading
+
+#### h4 Heading
+
+##### h5 Heading
+
+###### h6 Heading
+
+## Horizontal Rules
+
+---
+
+---
+
+---
+
+## Typographic replacements
+
+Enable typographer option to see result.
+
+(c) (C) (r) (R) (tm) (TM) (p) (P) +-
+
+test.. test... test..... test?..... test!....
+
+!!!!!! ???? ,, -- ---
+
+"Smartypants, double quotes" and 'single quotes'
+
+## Emphasis
+
+**This is bold text**
+
+**This is bold text**
+
+_This is italic text_
+
+_This is italic text_
+
+~~Strikethrough~~
+
+## Blockquotes
+
+> Blockquotes can also be nested...
+>
+> > ...by using additional greater-than signs right next to each other...
+> >
+> > > ...or with spaces between arrows.
+
+## Lists
+
+Unordered
+
+- Create a list by starting a line with `+`, `-`, or `*`
+- Sub-lists are made by indenting 2 spaces:
+ - Marker character change forces new list start:
+ - Ac tristique libero volutpat at
+ * Facilisis in pretium nisl aliquet
+ - Nulla volutpat aliquam velit
+- Very easy!
+
+Ordered
+
+1. Lorem ipsum dolor sit amet
+2. Consectetur adipiscing elit
+3. Integer molestie lorem at massa
+
+4. You can use sequential numbers...
+5. ...or keep all the numbers as `1.`
+
+Start numbering with offset:
+
+57. foo
+1. bar
+
+## Code
+
+Inline `code`
+
+Indented code
+
+ // Some comments
+ line 1 of code
+ line 2 of code
+ line 3 of code
+
+Block code "fences"
+
+```
+Sample text here...
+```
+
+Syntax highlighting
+
+```js
+var foo = function (bar) {
+ return bar++;
+};
+
+console.log(foo(5));
+```
+
+## Tables
+
+| Option | Description |
+| ------ | ------------------------------------------------------------------------- |
+| data | path to data files to supply the data that will be passed into templates. |
+| engine | engine to be used for processing templates. Handlebars is the default. |
+| ext | extension to be used for dest files. |
+
+Right aligned columns
+
+| Option | Description |
+| -----: | ------------------------------------------------------------------------: |
+| data | path to data files to supply the data that will be passed into templates. |
+| engine | engine to be used for processing templates. Handlebars is the default. |
+| ext | extension to be used for dest files. |
+
+## Links
+
+[link text](http://dev.nodeca.com)
+
+[link with title](http://nodeca.github.io/pica/demo/ "title text!")
+
+Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
+
+## Images
+
+
+
+
+Like links, Images also have a footnote style syntax
+
+![Alt text][id]
+
+With a reference later in the document defining the URL location:
+
+[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
+
+## Plugins
+
+The killer feature of `markdown-it` is very effective support of
+[syntax plugins](https://www.npmjs.org/browse/keyword/markdown-it-plugin).
+
+### [Emojies](https://github.com/markdown-it/markdown-it-emoji)
+
+> Classic markup: :wink: :crush: :cry: :tear: :laughing: :yum:
+>
+> Shortcuts (emoticons): :-) :-( 8-) ;)
+
+see [how to change output](https://github.com/markdown-it/markdown-it-emoji#change-output) with twemoji.
+
+### [Subscript](https://github.com/markdown-it/markdown-it-sub) / [Superscript](https://github.com/markdown-it/markdown-it-sup)
+
+- 19^th^
+- H~2~O
+
+### [\](https://github.com/markdown-it/markdown-it-ins)
+
+++Inserted text++
+
+### [\](https://github.com/markdown-it/markdown-it-mark)
+
+==Marked text==
+
+### [Footnotes](https://github.com/markdown-it/markdown-it-footnote)
+
+Footnote 1 link[^first].
+
+Footnote 2 link[^second].
+
+Inline footnote^[Text of inline footnote] definition.
+
+Duplicated footnote reference[^second].
+
+[^first]: Footnote **can have markup**
+
+ and multiple paragraphs.
+
+[^second]: Footnote text.
+
+### [Definition lists](https://github.com/markdown-it/markdown-it-deflist)
+
+Term 1
+
+: Definition 1
+with lazy continuation.
+
+Term 2 with _inline markup_
+
+: Definition 2
+
+ { some code, part of Definition 2 }
+
+ Third paragraph of definition 2.
+
+_Compact style:_
+
+Term 1
+~ Definition 1
+
+Term 2
+~ Definition 2a
+~ Definition 2b
+
+### [Abbreviations](https://github.com/markdown-it/markdown-it-abbr)
+
+This is HTML abbreviation example.
+
+It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on.
+
+\*[HTML]: Hyper Text Markup Language
+
+### [Custom containers](https://github.com/markdown-it/markdown-it-container)
+
+::: warning
+_here be dragons_
+:::