a tool for shared writing and social publishing
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

a bunch of little tweaks

celine 7e63af7a 213d00cd

+86 -65
+5 -5
app/globals.css
··· 179 179 background-color: transparent; 180 180 } 181 181 182 + .transparent-outline { 183 + @apply outline; 184 + @apply outline-transparent; 185 + } 186 + 182 187 .selected-outline { 183 188 @apply border; 184 189 @apply focus:outline; ··· 237 242 @apply outline-offset-1; 238 243 @apply outline-2; 239 244 @apply outline-border; 240 - } 241 - 242 - .transparent-outline { 243 - @apply outline; 244 - @apply outline-transparent; 245 245 } 246 246 247 247 .container {
+1 -1
app/lish/[did]/[publication]/dashboard/Actions.tsx
··· 6 6 import { useRouter } from "next/navigation"; 7 7 import { Popover } from "components/Popover"; 8 8 import { SettingsSmall } from "components/Icons/SettingsSmall"; 9 - import { CreatePubForm } from "app/lish/createPub/CreatePubForm"; 10 9 import { ShareSmall } from "components/Icons/ShareSmall"; 11 10 import { Menu } from "components/Layout"; 12 11 import { MenuItem } from "components/Layout"; ··· 105 104 return ( 106 105 <Popover 107 106 asChild 107 + className="w-80" 108 108 trigger={ 109 109 <ActionButton 110 110 id="pub-settings-button"
+9 -7
app/lish/[did]/[publication]/page.tsx
··· 51 51 return ( 52 52 <ThemeProvider entityID={null}> 53 53 <div className="publicationWrapper w-screen h-screen flex place-items-center bg-[#FDFCFA]"> 54 - <div className="publication max-w-prose w-full mx-auto h-full pt-8 px-2 pb-12 sm:pb-8"> 55 - <div className="flex flex-col pb-6 w-full text-center justify-center "> 56 - <div className="flex flex-row gap-3 justify-center"> 54 + <div className="publication max-w-prose w-full mx-auto h-full sm:pt-8 pt-4 px-3 pb-12 sm:pb-8"> 55 + <div className="flex flex-col pb-8 w-full text-center justify-center "> 56 + <div className="flex flex-col gap-3 justify-center place-items-center"> 57 57 {record.icon && ( 58 58 <div 59 - className="shrink-0 w-8 h-8 rounded-full mt-1" 59 + className="shrink-0 w-10 h-10 rounded-full" 60 60 style={{ 61 61 backgroundImage: `url(https://bsky.social/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${(record.icon.ref as unknown as { $link: string })["$link"]})`, 62 62 backgroundRepeat: "no-repeat", ··· 65 65 }} 66 66 /> 67 67 )} 68 - <h2 className="text-accent-contrast">{publication.name}</h2> 68 + <h2 className="text-accent-contrast sm:text-xl text-[22px]"> 69 + {publication.name} 70 + </h2> 69 71 </div> 70 - <p className="text-lg text-tertiary">{record.description} </p> 72 + <p className="sm:text-lg text-tertiary">{record.description} </p> 71 73 </div> 72 - <div className="publicationPostList w-full flex flex-col gap-4 pb-6"> 74 + <div className="publicationPostList w-full flex flex-col gap-4"> 73 75 {publication.documents_in_publications 74 76 .filter((d) => !!d?.documents) 75 77 .sort((a, b) => {
+43 -27
app/lish/createPub/CreatePubForm.tsx
··· 12 12 import { getPublicationURL } from "./getPublicationURL"; 13 13 import { string } from "zod"; 14 14 15 + type DomainState = 16 + | { status: "empty" } 17 + | { status: "valid" } 18 + | { status: "invalid" } 19 + | { status: "pending" } 20 + | { status: "error"; message: string }; 21 + 15 22 export const CreatePubForm = () => { 16 23 let [nameValue, setNameValue] = useState(""); 17 24 let [descriptionValue, setDescriptionValue] = useState(""); 18 25 let [logoFile, setLogoFile] = useState<File | null>(null); 19 26 let [logoPreview, setLogoPreview] = useState<string | null>(null); 20 27 let [domainValue, setDomainValue] = useState(""); 28 + let [domainState, setDomainState] = useState<DomainState>({ 29 + status: "empty", 30 + }); 21 31 let fileInputRef = useRef<HTMLInputElement>(null); 22 32 23 33 let router = useRouter(); ··· 94 104 setDescriptionValue(e.currentTarget.value); 95 105 }} 96 106 /> 97 - <DomainInput domain={domainValue} setDomain={setDomainValue} /> 107 + <DomainInput 108 + domain={domainValue} 109 + setDomain={setDomainValue} 110 + domainState={domainState} 111 + setDomainState={setDomainState} 112 + /> 98 113 99 114 <div className="flex w-full justify-center"> 100 - <ButtonPrimary type="submit">Create Publication!</ButtonPrimary> 115 + <ButtonPrimary 116 + type="submit" 117 + disabled={ 118 + !nameValue || !domainValue || domainState.status !== "valid" 119 + } 120 + > 121 + Create Publication! 122 + </ButtonPrimary> 101 123 </div> 102 124 </form> 103 125 ); ··· 110 132 function DomainInput(props: { 111 133 domain: string; 112 134 setDomain: (d: string) => void; 135 + domainState: DomainState; 136 + setDomainState: (s: DomainState) => void; 113 137 }) { 114 - type DomainState = 115 - | { status: "empty" } 116 - | { status: "valid" } 117 - | { status: "invalid" } 118 - | { status: "pending" } 119 - | { status: "error"; message: string }; 120 - 121 - let [state, setState] = useState<DomainState>({ status: "empty" }); 122 - 123 138 useEffect(() => { 124 139 if (!props.domain) { 125 - setState({ status: "empty" }); 140 + props.setDomainState({ status: "empty" }); 126 141 } else { 127 142 let valid = subdomainValidator.safeParse(props.domain); 128 143 if (!valid.success) { 129 144 let reason = valid.error.errors[0].code; 130 - setState({ 145 + props.setDomainState({ 131 146 status: "error", 132 147 message: 133 148 reason === "too_small" 134 149 ? "Must be at least 3 characters long" 135 150 : reason === "invalid_string" 136 - ? "Must contain only lowercase letters, numbers, and dashes" 151 + ? "Must contain only lowercase a-z, 0-9, and -" 137 152 : "", 138 153 }); 139 154 return; 140 155 } 141 - setState({ status: "pending" }); 156 + props.setDomainState({ status: "pending" }); 142 157 } 143 158 }, [props.domain]); 144 159 145 160 useDebouncedEffect( 146 161 async () => { 147 - if (!props.domain) return setState({ status: "empty" }); 162 + if (!props.domain) return props.setDomainState({ status: "empty" }); 148 163 149 164 let valid = subdomainValidator.safeParse(props.domain); 150 165 if (!valid.success) { ··· 154 169 domain: props.domain, 155 170 }); 156 171 console.log(status); 157 - if (status.error === "Not Found") setState({ status: "valid" }); 158 - else setState({ status: "invalid" }); 172 + if (status.error === "Not Found") 173 + props.setDomainState({ status: "valid" }); 174 + else props.setDomainState({ status: "invalid" }); 159 175 }, 160 176 500, 161 177 [props.domain], ··· 164 180 return ( 165 181 <div className="flex flex-col gap-1"> 166 182 <label className=" input-with-border flex flex-col text-sm text-tertiary font-bold italic leading-tight !py-1 !px-[6px]"> 167 - <div>Domain</div> 183 + <div>Choose your domain</div> 168 184 <div className="flex flex-row items-center"> 169 185 <Input 170 186 minLength={3} ··· 180 196 <div 181 197 className={"text-sm italic "} 182 198 style={{ 183 - fontWeight: state.status === "valid" ? "bold" : "normal", 199 + fontWeight: props.domainState.status === "valid" ? "bold" : "normal", 184 200 color: 185 - state.status === "valid" 201 + props.domainState.status === "valid" 186 202 ? theme.colors["accent-contrast"] 187 203 : theme.colors.tertiary, 188 204 }} 189 205 > 190 - {state.status === "valid" 206 + {props.domainState.status === "valid" 191 207 ? "Available!" 192 - : state.status === "error" 193 - ? state.message 194 - : state.status === "invalid" 208 + : props.domainState.status === "error" 209 + ? props.domainState.message 210 + : props.domainState.status === "invalid" 195 211 ? "Already Taken ):" 196 - : state.status === "pending" 212 + : props.domainState.status === "pending" 197 213 ? "Checking Availability..." 198 - : "Choose a domain! Numbers, characters, and hyphens only!"} 214 + : "a-z, 0-9, and - only!"} 199 215 </div> 200 216 </div> 201 217 );
+27 -24
app/lish/createPub/UpdatePubForm.tsx
··· 3 3 import { createPublication } from "./createPublication"; 4 4 import { ButtonPrimary } from "components/Buttons"; 5 5 import { AddSmall } from "components/Icons/AddSmall"; 6 - import { Input, InputWithLabel } from "components/Input"; 7 - import { useRouter } from "next/navigation"; 6 + import { InputWithLabel } from "components/Input"; 8 7 import { useState, useRef, useEffect } from "react"; 9 - import { getPublicationURL } from "./getPublicationURL"; 10 8 import { updatePublication } from "./updatePublication"; 11 9 import { usePublicationData } from "../[did]/[publication]/dashboard/PublicationSWRProvider"; 12 10 import { PubLeafletPublication } from "lexicons/api"; 13 11 import { mutate } from "swr"; 12 + import { AddTiny } from "components/Icons/AddTiny"; 14 13 15 14 export const EditPubForm = () => { 16 15 let pubData = usePublicationData(); 17 - let [nameValue, setNameValue] = useState(""); 18 - let [descriptionValue, setDescriptionValue] = useState(""); 19 - let [logoFile, setLogoFile] = useState<File | null>(null); 20 - let [logoPreview, setLogoPreview] = useState<string | null>(null); 16 + let record = pubData?.record as PubLeafletPublication.Record; 17 + 18 + let [nameValue, setNameValue] = useState(record?.name || ""); 19 + let [descriptionValue, setDescriptionValue] = useState( 20 + record?.description || "", 21 + ); 22 + let [iconFile, setIconFile] = useState<File | null>(null); 23 + let [iconPreview, setIconPreview] = useState<string | null>(null); 21 24 let fileInputRef = useRef<HTMLInputElement>(null); 22 25 useEffect(() => { 23 26 if (!pubData || !pubData.record) return; 24 - let record = pubData.record as PubLeafletPublication.Record; 25 27 setNameValue(record.name); 26 28 setDescriptionValue(record.description || ""); 27 29 if (record.icon) 28 - setLogoPreview( 30 + setIconPreview( 29 31 `url(https://bsky.social/xrpc/com.atproto.sync.getBlob?did=${pubData.identity_did}&cid=${(record.icon.ref as unknown as { $link: string })["$link"]})`, 30 32 ); 31 33 }, [pubData]); 32 34 33 - let router = useRouter(); 34 35 return ( 35 36 <form 36 - className="flex flex-col gap-3" 37 + className="flex flex-col gap-3 w-full py-1" 37 38 onSubmit={async (e) => { 38 39 if (!pubData) return; 39 40 e.preventDefault(); ··· 41 42 uri: pubData.uri, 42 43 name: nameValue, 43 44 description: descriptionValue, 44 - iconFile: logoFile, 45 + iconFile: iconFile, 45 46 }); 46 47 mutate("publication-data"); 47 48 }} 48 49 > 49 - <div className="flex flex-col items-center mb-4 gap-2"> 50 + <div className="flex items-center justify-between gap-2 "> 50 51 <div className="text-center text-secondary flex flex-col "> 51 - <h3 className="-mb-1">Logo</h3> 52 - <p className="italic text-tertiary">(optional)</p> 52 + <p className=" font-bold text-secondary"> 53 + Logo{" "} 54 + <span className="italic text-tertiary font-normal">(optional)</span> 55 + </p> 53 56 </div> 54 57 <div 55 - className="w-24 h-24 rounded-full border-2 border-dotted border-accent-1 flex items-center justify-center cursor-pointer hover:border-accent-contrast" 58 + className={`w-8 h-8 rounded-full flex items-center justify-center cursor-pointer ${iconPreview ? "border border-border-light hover:outline-border" : "border border-dotted border-accent-contrast hover:outline-accent-contrast"} selected-outline`} 56 59 onClick={() => fileInputRef.current?.click()} 57 60 > 58 - {logoPreview ? ( 61 + {iconPreview ? ( 59 62 <img 60 - src={logoPreview} 63 + src={iconPreview} 61 64 alt="Logo preview" 62 65 className="w-full h-full rounded-full object-cover" 63 66 /> 64 67 ) : ( 65 - <AddSmall className="text-accent-1" /> 68 + <AddTiny className="text-accent-1" /> 66 69 )} 67 70 </div> 68 71 <input ··· 73 76 onChange={(e) => { 74 77 const file = e.target.files?.[0]; 75 78 if (file) { 76 - setLogoFile(file); 79 + setIconFile(file); 77 80 const reader = new FileReader(); 78 81 reader.onload = (e) => { 79 - setLogoPreview(e.target?.result as string); 82 + setIconPreview(e.target?.result as string); 80 83 }; 81 84 reader.readAsDataURL(file); 82 85 } ··· 104 107 }} 105 108 /> 106 109 107 - <div className="flex w-full justify-center"> 108 - <ButtonPrimary type="submit">Update Publication!</ButtonPrimary> 109 - </div> 110 + <ButtonPrimary className="place-self-end" type="submit"> 111 + Update Publication 112 + </ButtonPrimary> 110 113 </form> 111 114 ); 112 115 };
+1 -1
components/Pages/PublicationMetadata.tsx
··· 61 61 > 62 62 {pub.publications?.name} 63 63 </Link> 64 - <div className="font-bold text-tertiary px-1 bg-border-light rounded-md "> 64 + <div className="font-bold text-tertiary px-1 text-sm flex place-items-center bg-border-light rounded-md "> 65 65 Editor 66 66 </div> 67 67 </div>