tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
28
pulls
pipelines
add description and published-at
awarm.space
10 months ago
aafcf521
71486a1e
+73
-20
7 changed files
expand all
collapse all
unified
split
actions
publishToPublication.ts
app
[leaflet_id]
page.tsx
lish
[handle]
[publication]
[rkey]
page.tsx
dashboard
page.tsx
createPub
CreatePubForm.tsx
components
Blocks
TextBlock
index.tsx
next.config.js
+1
-1
actions/publishToPublication.ts
···
86
86
author: credentialSession.did!,
87
87
title: title || "Untitled",
88
88
publication: publication_uri,
89
89
-
publishedAt: draft ? undefined : new Date().toISOString(),
89
89
+
publishedAt: new Date().toISOString(),
90
90
description: description || "",
91
91
pages: [
92
92
{
-1
app/[leaflet_id]/page.tsx
···
10
10
import { getRSVPData } from "actions/getRSVPData";
11
11
import { PageSWRDataProvider } from "components/PageSWRDataProvider";
12
12
import { getPollData } from "actions/pollActions";
13
13
-
import { PublicationContextProvider } from "components/Providers/PublicationContext";
14
13
import { supabaseServerClient } from "supabase/serverClient";
15
14
import { get_leaflet_data } from "app/api/rpc/[command]/get_leaflet_data";
16
15
+15
-7
app/lish/[handle]/[publication]/[rkey]/page.tsx
···
1
1
import Link from "next/link";
2
2
-
import { getPds, IdResolver } from "@atproto/identity";
2
2
+
import { IdResolver } from "@atproto/identity";
3
3
import { supabaseServerClient } from "supabase/serverClient";
4
4
import { AtUri } from "@atproto/syntax";
5
5
import { ids } from "lexicons/api/lexicons";
···
58
58
blocks = firstPage.blocks || [];
59
59
}
60
60
return (
61
61
-
<div className="postPage w-full h-screen bg-[#FDFCFA] flex items-stretch">
61
61
+
<div className="postPage w-full h-screen bg-bg-leaflet flex items-stretch">
62
62
<div className="pubWrapper flex flex-col w-full ">
63
63
<div className="pubContent flex flex-col px-3 sm:px-4 py-3 sm:py-9 mx-auto max-w-prose h-full w-full overflow-auto">
64
64
<div className="flex flex-col pb-8">
···
69
69
{decodeURIComponent((await props.params).publication)}
70
70
</Link>
71
71
<h2 className="">{record.title}</h2>
72
72
-
<p className="italic text-secondary">
73
73
-
This is a placeholder description and I want it to be longer so it
74
74
-
spans two lines.
75
75
-
</p>
76
76
-
<p className="text-sm text-tertiary pt-3">Published 06/02/2025</p>
72
72
+
{record.description ? (
73
73
+
<p className="italic text-secondary">{record.description}</p>
74
74
+
) : null}
75
75
+
{record.publishedAt ? (
76
76
+
<p className="text-sm text-tertiary pt-3">
77
77
+
Published{" "}
78
78
+
{new Date(record.publishedAt).toLocaleDateString(undefined, {
79
79
+
year: "2-digit",
80
80
+
month: "long",
81
81
+
day: "2-digit",
82
82
+
})}
83
83
+
</p>
84
84
+
) : null}
77
85
</div>
78
86
{blocks.map((b, index) => {
79
87
switch (true) {
+17
-6
app/lish/[handle]/[publication]/dashboard/page.tsx
···
110
110
<h3 className="text-primary">
111
111
{record.title}
112
112
</h3>
113
113
-
<p className="italic text-secondary">
114
114
-
This is a placeholder for description
115
115
-
</p>
116
116
-
<p className="text-sm text-tertiary pt-2">
117
117
-
{record.publishedAt} PlaceholderDate
118
118
-
</p>
113
113
+
{record.description ? (
114
114
+
<p className="italic text-secondary">
115
115
+
{record.description}
116
116
+
</p>
117
117
+
) : null}
118
118
+
{record.publishedAt ? (
119
119
+
<p className="text-sm text-tertiary pt-3">
120
120
+
Published{" "}
121
121
+
{new Date(
122
122
+
record.publishedAt,
123
123
+
).toLocaleDateString(undefined, {
124
124
+
year: "2-digit",
125
125
+
month: "long",
126
126
+
day: "2-digit",
127
127
+
})}
128
128
+
</p>
129
129
+
) : null}
119
130
</Link>
120
131
{leaflet && (
121
132
<Link
+34
-2
app/lish/createPub/CreatePubForm.tsx
···
1
1
"use client";
2
2
+
import { callRPC } from "app/api/rpc/client";
2
3
import { createPublication } from "./createPublication";
3
4
import { ButtonPrimary } from "components/Buttons";
4
5
import { AddSmall } from "components/Icons/AddSmall";
5
6
import { useIdentityData } from "components/IdentityProvider";
6
6
-
import { InputWithLabel } from "components/Input";
7
7
+
import { Input, InputWithLabel } from "components/Input";
7
8
import { useRouter } from "next/navigation";
8
8
-
import { useState, useRef } from "react";
9
9
+
import { useState, useRef, useEffect } from "react";
10
10
+
import { useDebouncedEffect } from "src/hooks/useDebouncedEffect";
9
11
10
12
export const CreatePubForm = () => {
11
13
let [nameValue, setNameValue] = useState("");
12
14
let [descriptionValue, setDescriptionValue] = useState("");
13
15
let [logoFile, setLogoFile] = useState<File | null>(null);
14
16
let [logoPreview, setLogoPreview] = useState<string | null>(null);
17
17
+
let [domainValue, setDomainValue] = useState("");
15
18
let fileInputRef = useRef<HTMLInputElement>(null);
16
19
17
20
let router = useRouter();
···
79
82
}}
80
83
/>
81
84
85
85
+
<DomainInput domain={domainValue} setDomain={setDomainValue} />
86
86
+
82
87
<InputWithLabel
83
88
label="Description (optional)"
84
89
textarea
···
96
101
</form>
97
102
);
98
103
};
104
104
+
105
105
+
function DomainInput(props: {
106
106
+
domain: string;
107
107
+
setDomain: (d: string) => void;
108
108
+
}) {
109
109
+
let [state, setState] = useState<"normal" | "valid" | "invalid">("normal");
110
110
+
useEffect(() => {
111
111
+
setState("normal");
112
112
+
}, [props.domain]);
113
113
+
useDebouncedEffect(
114
114
+
() => {
115
115
+
let status = callRPC("get_domain_status", { domain: props.domain });
116
116
+
console.log(status);
117
117
+
},
118
118
+
500,
119
119
+
[props.domain],
120
120
+
);
121
121
+
return (
122
122
+
<div className="flex flex-row gap-1">
123
123
+
<Input
124
124
+
value={props.domain}
125
125
+
onChange={(e) => props.setDomain(e.currentTarget.value)}
126
126
+
/>
127
127
+
.leaflet.pub
128
128
+
</div>
129
129
+
);
130
130
+
}
+1
-1
components/Blocks/TextBlock/index.tsx
···
248
248
.nodeAt(_pos - 1)
249
249
?.marks.find((f) => f.type === schema.marks.link) ||
250
250
node
251
251
-
.nodeAt(_pos - 2)
251
251
+
.nodeAt(Math.min(_pos - 2, 0))
252
252
?.marks.find((f) => f.type === schema.marks.link);
253
253
if (mark) {
254
254
window.open(mark.attrs.href, "_blank");
+5
-2
next.config.js
···
5
5
turbopack: {
6
6
resolveExtensions: [".mdx", ".tsx", ".ts", ".jsx", ".js", ".mjs", ".json"],
7
7
},
8
8
+
allowedDevOrigins: ["localhost", "127.0.0.1"],
8
9
webpack: (config) => {
9
10
config.resolve.extensionAlias = {
10
11
".js": [".ts", ".tsx", ".js"],
···
44
45
const withMDX = require("@next/mdx")({
45
46
extension: /\.mdx?$/,
46
47
});
47
47
-
48
48
-
module.exports = withMDX(nextConfig);
48
48
+
const withBundleAnalyzer = require("@next/bundle-analyzer")({
49
49
+
enabled: process.env.ANALYZE === "true",
50
50
+
});
51
51
+
module.exports = withBundleAnalyzer(withMDX(nextConfig));