a tool for shared writing and social publishing
1"use client";
2import { ButtonPrimary } from "components/Buttons";
3import { BlueskyTiny } from "components/Icons/BlueskyTiny";
4import { Input } from "components/Input";
5import { Popover } from "components/Popover";
6import Link from "next/link";
7import { useState } from "react";
8import {
9 LogoBlacksky,
10 LogoBluesky,
11 LogoEurosky,
12 LogoLeaflet,
13 LogoTangled,
14} from "./Logos";
15
16import { Separator } from "components/Layout";
17
18export const SubscribeWithHandle = (props: {
19 autoFocus?: boolean;
20 user: {
21 loggedIn: boolean;
22 email: string | undefined;
23 handle: string | undefined;
24 };
25}) => {
26 if (props.user.loggedIn && props.user.handle) {
27 return (
28 <ButtonPrimary className="mx-auto max-w-full">
29 <span className="shrink-0">Subscribe as</span>
30 <span className="flex gap-1 items-center max-w-full grow min-w-0">
31 <div className="w-4 h-4 shrink-0 rounded-full bg-test" />
32
33 <div className="grow truncate">{props.user.handle}</div>
34 </span>
35 </ButtonPrimary>
36 );
37 } else
38 return (
39 <div className="max-w-sm mx-auto w-full ">
40 <HandleInput autoFocus={props.autoFocus} />
41 <div className="flex gap-2 justify-center items-center mx-auto pt-0.5 ">
42 <UniversalHandleInfo />
43 <Separator classname="h-3! border-accent-contrast!" />
44 <div className="text-sm text-accent-contrast font-bold">Create</div>
45 </div>
46 </div>
47 );
48};
49
50export const LinkHandle = (props: { compact?: boolean }) => {
51 return (
52 <div
53 className={`flex flex-col text-center justify-center ${props.compact ? "gap-3" : "gap-4"}`}
54 >
55 <div
56 className={`text-secondary flex flex-col ${props.compact && "text-sm leading-snug"}`}
57 >
58 <h4 className={`${props.compact && "text-sm"}`}>
59 Link your universal handle
60 </h4>
61 <div className="text-tertiary">
62 to comment, recommend, and see what your friends are reading
63 </div>
64 <UniversalHandleInfo />
65 </div>
66 <HandleInputandOAuth link compact />
67 </div>
68 );
69};
70
71export const HandleInput = (props: { autoFocus?: boolean; link?: boolean }) => {
72 let [handleValue, setHandleValue] = useState("");
73 return (
74 <div className="handleInput input-with-border relative pl-0! py-0! flex gap-0 w-full">
75 <div className="border-r border-border text-tertiary text-center w-8 shrink-0 mr-2">
76 @
77 </div>
78 <Input
79 autoFocus={props.autoFocus}
80 className={`appearance-none! outline-none! w-full py-0.5 pr-22`}
81 placeholder="universal.handle"
82 size={0}
83 value={handleValue}
84 onChange={(e) => setHandleValue(e.target.value)}
85 />
86
87 <div className="absolute top-0 bottom-0 right-[4px] flex items-center">
88 <ButtonPrimary
89 compact
90 className="leading-tight! outline-none! text-sm!"
91 >
92 {props.link ? "Link" : "Subscribe"}
93 </ButtonPrimary>
94 </div>
95 </div>
96 );
97};
98
99export const HandleInputandOAuth = (props: {
100 link?: boolean;
101 compact?: boolean;
102}) => {
103 return (
104 <div className="handleInputAndOAuth flex flex-col">
105 <HandleInput link={props.link} />
106 <div
107 className={`${props.compact ? "mt-1 mb-2 text-xs" : "text-sm mt-2 mb-3"} w-full flex gap-2 items-center`}
108 >
109 <hr className="grow border-border-light" />
110 <div className="shrink-0 text-tertiary">
111 or {props.link ? "link with" : "sign in via"}
112 </div>
113 <hr className="grow border-border-light" />
114 </div>
115 <ButtonPrimary
116 compact={props.compact}
117 className={`${props.compact && "text-sm"} `}
118 fullWidth
119 >
120 <BlueskyTiny /> Bluesky
121 </ButtonPrimary>
122 </div>
123 );
124};
125
126export const AtSubscribeSuccess = (props: {}) => {
127 return (
128 <div className="flex flex-col text-center justify-center p-4 text-secondary max-w-md">
129 <h2 className="text-primary pb-1">You've Subscribed!</h2>
130 You'll recieve new posts in the <br />
131 <Link href={"/reader"}>Leaflet Reader</Link>
132 <br />
133 <span className="text-tertiary text-sm">
134 or any standard.site enabled reader!
135 </span>
136 <hr className="my-4 border-border-light" />
137 <div className="flex flex-col">
138 <h4>Other ways to follow</h4>
139 <Link href="">Get the RSS Feed</Link>
140 <Link href="">Pin Custom Feed in Bluesky</Link>
141 </div>
142 </div>
143 );
144};
145
146export const UniversalHandleInfo = (props: { trigger?: React.ReactNode }) => {
147 return (
148 <Popover
149 className="z-100! max-w-sm flex flex-col gap-2"
150 trigger={
151 props.trigger ? (
152 props.trigger
153 ) : (
154 <div className="text-accent-contrast text-sm">
155 What's a universal handle?
156 </div>
157 )
158 }
159 >
160 <div className="font-bold text-secondary">
161 Your universal handle is the username you use to sign into enabled apps
162 like...{" "}
163 </div>
164 <div className="opaque-container px-4 pt-2 pb-2 flex gap-2 w-full justify-between">
165 <AtApp logo={<LogoLeaflet />} name="Leaflet" />
166 <AtApp logo={<LogoBluesky />} name="Bluesky" />
167 <AtApp logo={<LogoBlacksky />} name="Blacksky" />
168 <AtApp logo={<LogoEurosky />} name="Eurosky" />
169 <AtApp logo={<LogoTangled />} name="Tangled" />
170 </div>
171 <div className="text-secondary flex flex-col gap-1">
172 <div>A handle can log into ANY enabled app.</div>
173 <div>
174 ie, you can log into <strong>Leaflet</strong> with the handle you made
175 for <strong>Bluesky</strong>!
176 </div>
177 </div>
178 <ButtonPrimary fullWidth className="mx-auto mb-3 mt-1">
179 Create a handle on Bluesky!
180 </ButtonPrimary>
181 </Popover>
182 );
183};
184
185const AtApp = (props: { logo: React.ReactNode; name: string }) => {
186 return (
187 <div className="basis-1/5 flex flex-col gap-2 justify-center text-tertiary font-bold text-sm text-center">
188 <div className="mx-auto">{props.logo}</div>
189 {props.name}
190 </div>
191 );
192};