diff --git a/app/[leaflet_id]/publish/BskyPostEditorProsemirror.tsx b/app/[leaflet_id]/publish/BskyPostEditorProsemirror.tsx
index 26a74252..793aafb0 100644
--- a/app/[leaflet_id]/publish/BskyPostEditorProsemirror.tsx
+++ b/app/[leaflet_id]/publish/BskyPostEditorProsemirror.tsx
@@ -304,7 +304,7 @@ export function BlueskyPostEditorProsemirror(props: {
/>
{editorState?.doc.textContent.length === 0 && (
- Write a post to share your writing!
+ post something...
)}
{
let editorStateRef = useRef
(null);
+ let [state, setState] = useState<"post-details" | "share-options">(
+ "post-details",
+ );
let [charCount, setCharCount] = useState(0);
- let [shareOption, setShareOption] = useState<"bluesky" | "quiet">("bluesky");
+ let [shareState, setShareState] = useState({
+ bluesky: true,
+ postToReaders: true,
+ email: true,
+ quiet: false,
+ });
let [isLoading, setIsLoading] = useState(false);
let [oauthError, setOauthError] = useState<
import("src/atproto-oauth").OAuthSessionError | null
@@ -82,6 +93,7 @@ const PublishPostForm = (
tx.get("publication_tags"),
);
let [localTags, setLocalTags] = useState([]);
+ let [showTagSelector, setShowTagSelector] = useState(false);
let [localPublishedAt, setLocalPublishedAt] = useState(
undefined,
@@ -152,7 +164,7 @@ const PublishPostForm = (
let [text, facets] = editorStateRef.current
? editorStateToFacetedText(editorStateRef.current)
: [];
- if (shareOption === "bluesky") {
+ if (shareState.bluesky) {
let bskyResult = await publishPostToBsky({
facets: facets || [],
text: text || "",
@@ -181,69 +193,181 @@ const PublishPostForm = (
}}
>
-
-
+ {state === "post-details" ? (
+ <>
+
Publish: Post Details
+
+
-
-
-
-
-
Tags
-
-
-
-
-
-
-
-
-
- Back
-
- 300}
- >
- {isLoading ? (
-
- ) : (
- "Publish this Post!"
- )}
-
-
- {oauthError && (
-
- )}
-
+
+
+
+
Tags
+
+ {currentTags.length !== 0 || showTagSelector === true ? (
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+
Social Preview
+
+
+
+
+
+ {props.title || "Untitled"}
+
+ {props.description && (
+
+ {props.description}
+
+ )}
+
+
+ {(props.record?.url || "leaflet.pub").replace(
+ /^https?:\/\//,
+ "",
+ )}
+
+
+
+
+
+
+
+
+ Back
+
+ setState("share-options")}
+ >
+ Next: Share
+
+
+ >
+ ) : (
+ <>
+
Publish: Share Options
+
+
+
+
+
+
+ 300}
+ >
+ {isLoading ? (
+
+ ) : (
+ "Publish this Post!"
+ )}
+
+
+ {oauthError && (
+
+ )}
+
+ >
+ )}
);
};
+const SocialPreviewImage = (props: {
+ rootEntity: string;
+ did: string;
+ coverImageCid: string | null;
+}) => {
+ const firstPage = useEntity(props.rootEntity, "root/page")[0];
+ const page = firstPage?.data.value || props.rootEntity;
+
+ if (props.coverImageCid) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ );
+};
+
const BackdateOptions = (props: {
publishedAt: Date | undefined;
setPublishedAt: (date: Date | undefined) => void;
@@ -305,14 +429,16 @@ const BackdateOptions = (props: {
return (
-
Publish Date
+
Publish Date
{formattedDate}
+
+ {formattedDate}
+
) : (
- now
+ Now
)
}
>
@@ -332,108 +458,17 @@ const BackdateOptions = (props: {
);
};
-const ShareOptions = (props: {
- shareOption: "quiet" | "bluesky";
- setShareOption: (option: typeof props.shareOption) => void;
- charCount: number;
- setCharCount: (c: number) => void;
- editorStateRef: React.MutableRefObject;
- title: string;
- profile: ProfileViewDetailed;
- description: string;
- record?: NormalizedPublication | null;
-}) => {
- return (
-
-
Share and Notify
-
{
- if (e.target === e.currentTarget) {
- props.setShareOption("quiet");
- }
- }}
- name="share-options"
- id="share-quietly"
- value="Share Quietly"
- >
-
-
Share Quietly
-
- No one will be notified about this post
-
-
-
-
{
- if (e.target === e.currentTarget) {
- props.setShareOption("bluesky");
- }
- }}
- name="share-options"
- id="share-bsky"
- value="Share on Bluesky"
- >
-
-
Share on Bluesky
-
- Pub subscribers will be updated via a custom Bluesky feed
-
-
-
-
-
-
-

-
-
-
{props.profile.displayName}
-
@{props.profile.handle}
-
-
-
-
-
-
-
{props.title}
-
{props.description}
-
-
- {props.record?.url?.replace(/^https?:\/\//, "")}
-
-
-
-
- {props.charCount}/300
-
-
-
-
-
-
- );
-};
-
const PublishingTo = (props: {
publication_uri?: string;
record?: NormalizedPublication | null;
}) => {
if (props.publication_uri && props.record) {
return (
-
-
Publishing to
-
-
+
);
diff --git a/app/[leaflet_id]/publish/ShareOptions.tsx b/app/[leaflet_id]/publish/ShareOptions.tsx
new file mode 100644
index 00000000..269a0078
--- /dev/null
+++ b/app/[leaflet_id]/publish/ShareOptions.tsx
@@ -0,0 +1,152 @@
+"use client";
+import { Checkbox } from "components/Checkbox";
+import { BlueskyPostEditorProsemirror } from "./BskyPostEditorProsemirror";
+import { EditorState } from "prosemirror-state";
+import { ProfileViewDetailed } from "@atproto/api/dist/client/types/app/bsky/actor/defs";
+import type { NormalizedPublication } from "src/utils/normalizeRecords";
+
+export type ShareState = {
+ bluesky: boolean;
+ postToReaders: boolean;
+ email: boolean;
+ quiet: boolean;
+};
+
+type Props = {
+ shareState: ShareState;
+ setShareState: (state: ShareState) => void;
+ charCount: number;
+ setCharCount: (c: number) => void;
+ editorStateRef: React.MutableRefObject
;
+ title: string;
+ profile: ProfileViewDetailed;
+ description: string;
+ record?: NormalizedPublication | null;
+ subscriberCount?: number;
+};
+
+export function ShareOptions(props: Props) {
+ const { shareState, setShareState } = props;
+ const handleChange = (
+ key: keyof Omit,
+ checked: boolean,
+ ) => {
+ setShareState({ ...shareState, [key]: checked, quiet: false });
+ };
+
+ const handleQuietChange = (checked: boolean) => {
+ if (checked) {
+ setShareState({
+ bluesky: false,
+ postToReaders: false,
+ email: false,
+ quiet: true,
+ });
+ } else {
+ setShareState({ ...shareState, quiet: false });
+ }
+ };
+
+ return (
+
+
handleChange("email", e.target.checked)}
+ >
+
+
+ Email{" "}
+ {props.subscriberCount !== undefined
+ ? `${props.subscriberCount} `
+ : ""}
+ Subscribers
+
+
+
+
+
handleChange("postToReaders", e.target.checked)}
+ >
+
+
Post to Readers
+
+ This post will show up in Leaflet feeds and other Standard Site
+ enabled reader feeds
+
+
+
+
+
handleChange("bluesky", e.target.checked)}
+ >
+
+
Share on Bluesky
+
+ Pub subscribers will be updated via a custom Bluesky feed
+
+
+
+
+
+
+

+
+
+
{props.profile.displayName}
+
@{props.profile.handle}
+
+
+
+
+
+
+
+ {props.title}
+
+
+ {props.description}
+
+
+
+ {props.record?.url?.replace(/^https?:\/\//, "")}
+
+
+
+
+ {props.charCount}/300
+
+
+
+
+
+
+
+
+
handleQuietChange(e.target.checked)}
+ >
+
+
Post Quietly
+
+ No one will be notified about this post
+
+
+
+
+ );
+}
diff --git a/components/Tags.tsx b/components/Tags.tsx
index bd6ec822..8ad403b9 100644
--- a/components/Tags.tsx
+++ b/components/Tags.tsx
@@ -39,15 +39,19 @@ export const Tag = (props: {
export const TagSelector = (props: {
selectedTags: string[];
setSelectedTags: (tags: string[]) => void;
+ rightAlign?: boolean;
}) => {
return (
{props.selectedTags.length > 0 ? (
-
+
{props.selectedTags.map((tag) => (
) : (
- no tags selected
+
+ no tags selected
+
)}
);
};
export const TagSearchInput = (props: {
+ rightAlign?: boolean;
selectedTags: string[];
setSelectedTags: (tags: string[]) => void;
}) => {
@@ -203,7 +212,9 @@ export const TagSearchInput = (props: {
}}
/>
{props.selectedTags.length > 0 ? (
-
+
{props.selectedTags.map((tag) => (
) : (
-