skylinebulletin/src/App.tsx

129 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Skyline Bulletin — Simple, responsive "Coming Soon" page
File: src/App.tsx (React + Vite + TypeScript)
This single-file starter provides a focused, responsive "Coming Soon" landing page with:
- Hero with headline, subtitle, and email capture
- Responsive layout that works on mobile, tablet, desktop
- Accessible form (no backend; front-end mock) and success state
- Small features list and social links area
- Plain CSS inlined as separate file content below (create src/styles.css)
- No Tailwind; uses modern CSS with CSS variables and flex/grid
How to use:
1. Create a Vite + React + TS project if you haven't: `npm create vite@latest skyline-bulletin -- --template react-ts`
2. Install optional icons (lucide-react) if you want icons: `npm install lucide-react`
3. Replace src/App.tsx with this file and create src/styles.css with the CSS provided below.
4. Run `npm run dev`.
*/
import React, { useState } from "react";
import { Mail, Twitter, Linkedin, Sun, Moon } from "lucide-react";
import "./styles.css";
import logo from "./assets/Skybulletin_logo.jpeg";
export default function App(){
const [email, setEmail] = useState("");
const [subscribed, setSubscribed] = useState(false);
const [theme, setTheme] = useState<"light"|"dark">("light");
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!email) return;
// mock subscribe
setSubscribed(true);
};
return (
<div className="cs-root" data-theme={theme}>
<header className="cs-header">
<img src={logo} alt="Skyline Bulletin logo" style={{ height: '50px'}}/>
<div className="brand">Skyline Bulletin</div>
<div className="header-actions">
<button onClick={() => setTheme(t => t === "light" ? "dark" : "light")} className="icon-btn" aria-label="Toggle theme">
{theme === 'light' ? <Moon /> : <Sun />}
</button>
</div>
</header>
<main className="cs-main">
<section className="hero">
<div className="hero-inner">
<h1 className="title">Skyline Bulletin Coming Soon</h1>
<p className="subtitle">Short, verified, people-first news. Clean design. No noise. Launching soon.</p>
<div className="signup-card">
{subscribed ? (
<div className="subscribe-ok">
<strong>Thanks youre on the list.</strong>
<p className="muted">Well email you when Skyline Bulletin launches.</p>
</div>
) : (
<form onSubmit={onSubmit} className="signup-form" aria-label="Subscribe to launch updates">
<label className="sr-only">Email address</label>
<input
className="email-input"
type="email"
placeholder="you@email.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
<button className="btn-primary" type="submit">
<Mail className="icon-left" /> Notify me
</button>
</form>
)}
<div className="meta-row">
<span className="pill">No advertisment Human-first</span>
<span className="muted">Expected launch: Q4</span>
</div>
</div>
<div className="features">
<div className="feature">
<strong>Concise briefs</strong>
<p className="muted">Quick reads for busy days.</p>
</div>
<div className="feature">
<strong>Verified sources</strong>
<p className="muted">Transparent sourcing and context.</p>
</div>
<div className="feature">
<strong>People-first</strong>
<p className="muted">Human editorial judgement over algorithms.</p>
</div>
</div>
</div>
<aside className="hero-side" aria-hidden>
<div className="visual-card">
<div className="visual-label">Preview</div>
<div className="visual-skyline">
<img src={logo} alt="preview" style={{height: '200px'}}/>
</div>
</div>
</aside>
</section>
<section className="socials">
<div className="socials-inner">
<div className="small">Follow our progress</div>
<div className="icons">
<a href="#" aria-label="Twitter" className="social-link"><Twitter /></a>
<a href="#" aria-label="LinkedIn" className="social-link"><Linkedin /></a>
</div>
</div>
</section>
</main>
<footer className="cs-footer">
<div className="footer-inner">© {new Date().getFullYear()} Skyline Bulletin Built with care.</div>
</footer>
</div>
);
}