A calm place to write long-form, and publish it to the open social web.
skypress.blog/
1import { useState } from 'react';
2
3import { ATMOSPHERE_WEB_BASE } from '../lib/social/atmosphere-url';
4
5interface Props {
6 /** True when opened from "Publish" — the copy promises a publish on return. */
7 forPublish: boolean;
8 error: string | null;
9 onSubmit: ( value: string ) => void;
10 onCancel?: () => void;
11}
12
13/**
14 * Signed-out handle entry for the writing-first flow. OAuth is sign-in only, so this never
15 * creates an account — it links out to Bluesky's hosted signup instead (brief guardrail). The
16 * caller persists the draft + sets publish intent before the redirect.
17 */
18export default function SignInPanel( { forPublish, error, onSubmit, onCancel }: Props ) {
19 const [ value, setValue ] = useState( '' );
20
21 return (
22 <form
23 className="signin-panel"
24 onSubmit={ ( event ) => {
25 event.preventDefault();
26 onSubmit( value.trim() );
27 } }
28 >
29 <h2 className="signin-panel__title">
30 { forPublish ? 'Sign in to publish' : 'Sign in' }
31 </h2>
32 <p className="signin-panel__lede">
33 { forPublish
34 ? "Your draft is saved. Sign in and we'll pick up right where you left off and publish it."
35 : 'Use your existing Bluesky / AT Protocol identity. Your work stays in your own account.' }
36 </p>
37 <label className="signin-panel__label" htmlFor="write-handle">
38 Your handle, DID, or PDS URL
39 </label>
40 <input
41 id="write-handle"
42 className="signin-panel__input"
43 name="handle"
44 autoComplete="username"
45 autoCapitalize="none"
46 autoCorrect="off"
47 spellCheck={ false }
48 placeholder="alice.bsky.social"
49 value={ value }
50 onChange={ ( event ) => setValue( event.target.value ) }
51 />
52 <div className="signin-panel__actions">
53 <button className="signin-panel__submit" type="submit">
54 Sign in with AT Protocol
55 </button>
56 { onCancel && (
57 <button className="signin-panel__cancel" type="button" onClick={ onCancel }>
58 Cancel
59 </button>
60 ) }
61 </div>
62 { error && (
63 <p className="signin-panel__error" role="alert">
64 { error }
65 </p>
66 ) }
67 <p className="signin-panel__signup">
68 Need an account?{ ' ' }
69 <a
70 className="signin-panel__signup-link"
71 href={ ATMOSPHERE_WEB_BASE }
72 target="_blank"
73 rel="noopener noreferrer"
74 aria-label="Create an account on the ATmosphere (opens in a new tab)"
75 >
76 Create one on the ATmosphere
77 { /* Standard external-link glyph — same icon as the author page's external link. */ }
78 <svg
79 className="signin-panel__external"
80 width="11"
81 height="11"
82 viewBox="0 0 24 24"
83 fill="none"
84 stroke="currentColor"
85 strokeWidth="2.5"
86 strokeLinecap="round"
87 strokeLinejoin="round"
88 aria-hidden="true"
89 >
90 <path d="M7 17 17 7" />
91 <path d="M8 7h9v9" />
92 </svg>
93 </a>
94 </p>
95 </form>
96 );
97}