a tool for shared writing and social publishing
at feature/email 192 lines 6.1 kB view raw
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};