a tool for shared writing and social publishing

add description and published-at

+73 -20
+1 -1
actions/publishToPublication.ts
··· 86 86 author: credentialSession.did!, 87 87 title: title || "Untitled", 88 88 publication: publication_uri, 89 - publishedAt: draft ? undefined : new Date().toISOString(), 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 - 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 - import { getPds, IdResolver } from "@atproto/identity"; 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 - <div className="postPage w-full h-screen bg-[#FDFCFA] flex items-stretch"> 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 - <p className="italic text-secondary"> 73 - This is a placeholder description and I want it to be longer so it 74 - spans two lines. 75 - </p> 76 - <p className="text-sm text-tertiary pt-3">Published 06/02/2025</p> 72 + {record.description ? ( 73 + <p className="italic text-secondary">{record.description}</p> 74 + ) : null} 75 + {record.publishedAt ? ( 76 + <p className="text-sm text-tertiary pt-3"> 77 + Published{" "} 78 + {new Date(record.publishedAt).toLocaleDateString(undefined, { 79 + year: "2-digit", 80 + month: "long", 81 + day: "2-digit", 82 + })} 83 + </p> 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 - <p className="italic text-secondary"> 114 - This is a placeholder for description 115 - </p> 116 - <p className="text-sm text-tertiary pt-2"> 117 - {record.publishedAt} PlaceholderDate 118 - </p> 113 + {record.description ? ( 114 + <p className="italic text-secondary"> 115 + {record.description} 116 + </p> 117 + ) : null} 118 + {record.publishedAt ? ( 119 + <p className="text-sm text-tertiary pt-3"> 120 + Published{" "} 121 + {new Date( 122 + record.publishedAt, 123 + ).toLocaleDateString(undefined, { 124 + year: "2-digit", 125 + month: "long", 126 + day: "2-digit", 127 + })} 128 + </p> 129 + ) : null} 119 130 </Link> 120 131 {leaflet && ( 121 132 <Link
+34 -2
app/lish/createPub/CreatePubForm.tsx
··· 1 1 "use client"; 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 - import { InputWithLabel } from "components/Input"; 7 + import { Input, InputWithLabel } from "components/Input"; 7 8 import { useRouter } from "next/navigation"; 8 - import { useState, useRef } from "react"; 9 + import { useState, useRef, useEffect } from "react"; 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 + 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 + <DomainInput domain={domainValue} setDomain={setDomainValue} /> 86 + 82 87 <InputWithLabel 83 88 label="Description (optional)" 84 89 textarea ··· 96 101 </form> 97 102 ); 98 103 }; 104 + 105 + function DomainInput(props: { 106 + domain: string; 107 + setDomain: (d: string) => void; 108 + }) { 109 + let [state, setState] = useState<"normal" | "valid" | "invalid">("normal"); 110 + useEffect(() => { 111 + setState("normal"); 112 + }, [props.domain]); 113 + useDebouncedEffect( 114 + () => { 115 + let status = callRPC("get_domain_status", { domain: props.domain }); 116 + console.log(status); 117 + }, 118 + 500, 119 + [props.domain], 120 + ); 121 + return ( 122 + <div className="flex flex-row gap-1"> 123 + <Input 124 + value={props.domain} 125 + onChange={(e) => props.setDomain(e.currentTarget.value)} 126 + /> 127 + .leaflet.pub 128 + </div> 129 + ); 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 - .nodeAt(_pos - 2) 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 + 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 - 48 - module.exports = withMDX(nextConfig); 48 + const withBundleAnalyzer = require("@next/bundle-analyzer")({ 49 + enabled: process.env.ANALYZE === "true", 50 + }); 51 + module.exports = withBundleAnalyzer(withMDX(nextConfig));