A calm place to write long-form, and publish it to the open social web. skypress.blog/
0

Configure Feed

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

Rewrite landing as a time-of-day sunrise hero

+195 -26
+195 -26
src/pages/index.astro
··· 1 1 --- 2 2 import Base from '../layouts/Base.astro'; 3 3 import Logo from '../components/Logo.astro'; 4 + import { PHASES, DEFAULT_PHASE } from '../lib/landing/time-of-day'; 5 + 6 + const fallback = PHASES[ DEFAULT_PHASE ]; 4 7 --- 5 8 6 9 <Base 7 10 title="SkyPress — a writing studio for the open social web" 8 11 description="A standalone, long-form writing studio for the AT Protocol. Write in blocks; your words are saved to your own server." 9 12 > 10 - <div class="page sun-wash"> 13 + <Fragment slot="head"> 14 + <script is:inline> 15 + // Set the sky phase before first paint so there is no flash. 16 + // Boundaries mirror src/lib/landing/time-of-day.ts (kept in sync by its test). 17 + ( function () { 18 + var h = new Date().getHours(); 19 + var p = 20 + h >= 21 || h < 5 ? 'night' 21 + : h < 7 ? 'dawn' 22 + : h < 10 ? 'morning' 23 + : h < 16 ? 'midday' 24 + : h < 19 ? 'golden' 25 + : 'dusk'; 26 + document.documentElement.dataset.phase = p; 27 + } )(); 28 + </script> 29 + </Fragment> 30 + 31 + <div class="page" data-phase={DEFAULT_PHASE}> 32 + <div class="sky" aria-hidden="true"> 33 + <div class="stars"></div> 34 + <div class="bloom"></div> 35 + <div class="halo"></div> 36 + <div class="horizon"></div> 37 + </div> 38 + 11 39 <header class="masthead"> 12 40 <Logo /> 13 41 <a class="btn btn--ghost" href="/editor">Open the studio</a> 14 42 </header> 15 43 16 44 <main class="hero"> 17 - <p class="eyebrow">Long-form for the AT Protocol</p> 18 - <h1 class="hero__title"> 19 - The open sky meets the<br /><span class="hero__em">typesetter's bench.</span> 20 - </h1> 21 - <p class="hero__lede"> 22 - A calm, block-based writing studio for the open social web. Compose rich 23 - long-form pieces and publish them straight to <em>your own</em> server — SkyPress 24 - is just the studio you write in. 25 - </p> 45 + <p class="eyebrow" id="greet">{fallback.greeting}</p> 46 + <h1 class="hero__title" id="headline" set:html={fallback.headlineHtml} /> 47 + <p class="hero__lede" id="lede">{fallback.lede}</p> 26 48 <div class="hero__actions"> 27 49 <a class="btn btn--primary" href="/editor">Start writing</a> 28 50 <a class="btn btn--ghost" href="/preview">Read a sample</a> ··· 32 54 </p> 33 55 </main> 34 56 57 + <section class="how"> 58 + <ol class="steps"> 59 + <li><span class="steps__n">01</span><h2>Sign in, no new account</h2><p>Use your existing Bluesky / AT&nbsp;Protocol identity.</p></li> 60 + <li><span class="steps__n">02</span><h2>Write in blocks</h2><p>Rich long-form, powered by the Gutenberg editor.</p></li> 61 + <li><span class="steps__n">03</span><h2>Own your words</h2><p>Saved to your own server, on the open web.</p></li> 62 + </ol> 63 + <p class="how__honest">Publishing also creates a Bluesky post that links back — so your piece is discoverable. We always say so before you publish.</p> 64 + </section> 65 + 35 66 <footer class="footer"> 36 - <span>Your data, your server, the open web.</span> 67 + <span>Your words, your server, the open web.</span> 37 68 <span class="footer__mark">GPL-2.0 · built on Gutenberg</span> 38 69 </footer> 39 70 </div> 40 71 </Base> 41 72 73 + <script> 74 + import { PHASES, phaseForHour } from '../lib/landing/time-of-day'; 75 + 76 + const now = new Date(); 77 + const phase = PHASES[ phaseForHour( now.getHours() ) ]; 78 + const greet = document.getElementById( 'greet' ); 79 + const headline = document.getElementById( 'headline' ); 80 + const lede = document.getElementById( 'lede' ); 81 + const hh = String( now.getHours() ).padStart( 2, '0' ); 82 + const mm = String( now.getMinutes() ).padStart( 2, '0' ); 83 + if ( greet ) greet.textContent = `${ phase.greeting } · ${ hh }:${ mm }`; 84 + if ( headline ) headline.innerHTML = phase.headlineHtml; 85 + if ( lede ) lede.textContent = phase.lede; 86 + </script> 87 + 42 88 <style> 43 89 .page { 90 + position: relative; 44 91 min-height: 100vh; 45 92 display: flex; 46 93 flex-direction: column; 94 + overflow: hidden; 47 95 } 96 + 97 + /* ===== Atmospheric sky (hero backdrop) — varies by [data-phase] ===== */ 98 + .sky { 99 + position: absolute; 100 + inset: 0 0 auto 0; 101 + height: 78vh; 102 + min-height: 32rem; 103 + z-index: 0; 104 + pointer-events: none; 105 + } 106 + .sky .stars, 107 + .sky .bloom, 108 + .sky .halo { 109 + position: absolute; 110 + inset: 0; 111 + transition: opacity 0.6s ease; 112 + } 113 + .bloom { 114 + background: radial-gradient( 115 + ellipse 46% 42% at 50% 78%, 116 + rgba(255, 238, 200, 0.55), 117 + rgba(255, 200, 120, 0.3) 40%, 118 + transparent 72% 119 + ); 120 + } 121 + .halo { 122 + background: radial-gradient(circle at 50% 62%, transparent 0 70px, rgba(255, 236, 200, 0.85) 71px 73px, transparent 74px); 123 + filter: drop-shadow(0 0 26px rgba(255, 200, 120, 0.45)); 124 + } 125 + .horizon { 126 + position: absolute; 127 + left: 0; 128 + right: 0; 129 + top: 70%; 130 + height: 1px; 131 + background: linear-gradient(90deg, transparent, rgba(232, 146, 12, 0.7), transparent); 132 + } 133 + .stars { 134 + opacity: 0; 135 + background-image: 136 + radial-gradient(1.5px 1.5px at 20% 18%, #fff, transparent), 137 + radial-gradient(1.5px 1.5px at 67% 12%, #fff, transparent), 138 + radial-gradient(1px 1px at 43% 30%, #fff, transparent), 139 + radial-gradient(1px 1px at 82% 24%, #fff, transparent), 140 + radial-gradient(1.5px 1.5px at 12% 38%, #fff, transparent), 141 + radial-gradient(1px 1px at 90% 40%, #fff, transparent), 142 + radial-gradient(1px 1px at 33% 9%, #fff, transparent); 143 + } 144 + 145 + /* Per-phase sky gradient + star visibility + hero text colour */ 146 + [data-phase='night'] .sky { background: linear-gradient(180deg, #080611, #140f28 50%, #231a38); } 147 + [data-phase='night'] .stars { opacity: 1; } 148 + [data-phase='dawn'] .sky { background: linear-gradient(180deg, #231533, #7a2f63 42%, #d7613a 78%, #f4a14a); } 149 + [data-phase='dawn'] .stars { opacity: 0.5; } 150 + [data-phase='morning'] .sky { background: linear-gradient(180deg, #3a2752, #c0567f 34%, #f5934a 70%, #ffd98a); } 151 + [data-phase='midday'] .sky { background: linear-gradient(180deg, #e9b977, #f7dca5 45%, #fdf0d6); } 152 + [data-phase='golden'] .sky { background: linear-gradient(180deg, #4a2150, #b5417a 30%, #ef7d3a 64%, #f9c25a 92%, #ffe6ab); } 153 + [data-phase='dusk'] .sky { background: linear-gradient(180deg, #140f2a, #4a2150 38%, #93324f 70%, #c75a3b); } 154 + [data-phase='dusk'] .stars { opacity: 0.5; } 155 + 156 + /* Light-text phases (dark skies) vs ink-text phase (pale midday). */ 157 + [data-phase='night'] .hero, 158 + [data-phase='dawn'] .hero, 159 + [data-phase='morning'] .hero, 160 + [data-phase='golden'] .hero, 161 + [data-phase='dusk'] .hero { --hero-ink: #f6f0e3; --hero-soft: rgba(246, 240, 227, 0.82); } 162 + [data-phase='midday'] .hero { --hero-ink: #241a10; --hero-soft: rgba(36, 26, 16, 0.72); } 163 + 48 164 .masthead { 165 + position: relative; 166 + z-index: 2; 49 167 display: flex; 50 168 align-items: center; 51 169 justify-content: space-between; 52 170 padding: 1.5rem clamp(1.25rem, 5vw, 4rem); 53 171 } 54 172 .hero { 173 + position: relative; 174 + z-index: 2; 55 175 flex: 1; 56 - max-width: 52rem; 176 + width: 100%; 177 + max-width: 46rem; 57 178 margin: 0 auto; 58 - padding: clamp(3rem, 10vh, 7rem) clamp(1.25rem, 5vw, 4rem); 179 + padding: clamp(2rem, 9vh, 5rem) clamp(1.25rem, 5vw, 4rem) clamp(3rem, 8vh, 5rem); 59 180 display: flex; 60 181 flex-direction: column; 61 - align-items: flex-start; 182 + align-items: center; 183 + text-align: center; 62 184 } 185 + .hero .eyebrow { color: var(--sun); } 63 186 .hero__title { 64 - font-size: clamp(2.6rem, 8vw, 5rem); 65 - font-weight: 560; 66 - line-height: 1.02; 67 - margin: 1rem 0 0; 187 + font-size: clamp(2.7rem, 8vw, 5rem); 188 + font-weight: 760; 189 + letter-spacing: -0.035em; 190 + line-height: 0.98; 191 + margin: 0.75rem 0 0; 192 + max-width: 14ch; 193 + color: var(--hero-ink); 68 194 } 69 - .hero__em { 195 + .hero__title :global(em) { 70 196 font-style: italic; 71 197 color: var(--sun); 72 198 } 73 199 .hero__lede { 74 - font-size: clamp(1.15rem, 2.4vw, 1.4rem); 75 - line-height: 1.55; 76 - color: var(--ink-soft); 77 - max-width: 38ch; 78 - margin: 1.75rem 0 0; 200 + font-size: clamp(1.1rem, 2.2vw, 1.35rem); 201 + line-height: 1.5; 202 + color: var(--hero-soft); 203 + max-width: 36ch; 204 + margin: 1.25rem 0 0; 79 205 } 80 206 .hero__actions { 81 207 display: flex; 82 208 gap: 0.85rem; 83 - margin: 2.25rem 0 0; 209 + margin: 2rem 0 0; 84 210 flex-wrap: wrap; 211 + justify-content: center; 85 212 } 86 213 .hero__note { 214 + color: var(--hero-soft); 215 + font-size: 0.95rem; 216 + margin-top: 1.5rem; 217 + } 218 + 219 + /* ===== How it works (standard themed surface, below the sky) ===== */ 220 + .how { 221 + position: relative; 222 + z-index: 2; 223 + background: var(--paper); 224 + border-top: 1px solid var(--line); 225 + padding: clamp(2.5rem, 6vw, 4rem) clamp(1.25rem, 5vw, 4rem); 226 + } 227 + .steps { 228 + list-style: none; 229 + margin: 0 auto; 230 + padding: 0; 231 + max-width: 60rem; 232 + display: grid; 233 + gap: 1.75rem; 234 + grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); 235 + } 236 + .steps li { margin: 0; } 237 + .steps__n { 238 + font-family: var(--font-mono); 239 + font-weight: 500; 240 + color: var(--sun); 241 + font-size: 1.1rem; 242 + letter-spacing: 0.04em; 243 + } 244 + .steps h2 { font-size: 1.2rem; margin: 0.4rem 0 0.3rem; } 245 + .steps p { margin: 0; color: var(--ink-soft); } 246 + .how__honest { 247 + max-width: 60rem; 248 + margin: 2rem auto 0; 87 249 color: var(--muted); 88 250 font-size: 0.95rem; 89 - margin-top: 1.5rem; 90 251 } 252 + 91 253 .footer { 254 + position: relative; 255 + z-index: 2; 256 + background: var(--paper); 92 257 display: flex; 93 258 justify-content: space-between; 94 259 gap: 1rem; ··· 99 264 font-family: var(--font-mono); 100 265 font-size: 0.72rem; 101 266 letter-spacing: 0.04em; 267 + } 268 + 269 + @media (prefers-reduced-motion: reduce) { 270 + .sky .stars, .sky .bloom, .sky .halo { transition: none; } 102 271 } 103 272 </style>