From 0aadaaa4db67a77d63006b40abc49bf66c85c851 Mon Sep 17 00:00:00 2001 From: ravixalgorithm <11aravipratapsingh@gmail.com> Date: Fri, 25 Sep 2026 15:28:19 +0530 Subject: [PATCH] feat(site): public landing page, marketing pages and sponsors - Landing at / (app moved to /dashboard) with a live NYSE session dial and the real product preview; About, Help, Architecture and Terms made public and rebuilt. - /sponsor page with monthly tiers, one-time and custom options, prefilled GitHub Sponsors checkout links, and a sponsors band (open slots, previous sponsors) on every public page. Siray moved to previous sponsors. Co-Authored-By: Claude Opus 5.5 --- README.md | 39 +++- app/(marketing)/about/page.tsx | 64 +++++++ app/(marketing)/api-docs/page.tsx | 129 ++++++++++++++ app/(marketing)/help/page.tsx | 88 +++++++++ app/(marketing)/layout.tsx | 77 ++++++++ app/(marketing)/page.tsx | 226 +++++++++++++++++++++++ app/(marketing)/sponsor/page.tsx | 185 +++++++++++++++++++ app/(marketing)/terms/page.tsx | 87 +++++++++ app/(root)/about/page.tsx | 133 -------------- app/(root)/api-docs/page.tsx | 247 -------------------------- app/(root)/help/page.tsx | 124 ------------- app/(root)/terms/page.tsx | 98 ---------- components/landing/MarketClock.tsx | 93 ++++++++++ components/landing/ProductPreview.tsx | 55 ++++++ components/marketing/IconCard.tsx | 16 ++ components/marketing/PageHero.tsx | 13 ++ components/marketing/SectionHead.tsx | 9 + components/sponsors/SponsorsBand.tsx | 72 ++++++++ lib/github.ts | 19 ++ lib/market-session.ts | 40 +++++ lib/sponsors.ts | 60 +++++++ public/assets/images/siray-logo.png | Bin 61691 -> 0 bytes 22 files changed, 1267 insertions(+), 607 deletions(-) create mode 100644 app/(marketing)/about/page.tsx create mode 100644 app/(marketing)/api-docs/page.tsx create mode 100644 app/(marketing)/help/page.tsx create mode 100644 app/(marketing)/layout.tsx create mode 100644 app/(marketing)/page.tsx create mode 100644 app/(marketing)/sponsor/page.tsx create mode 100644 app/(marketing)/terms/page.tsx delete mode 100644 app/(root)/about/page.tsx delete mode 100644 app/(root)/api-docs/page.tsx delete mode 100644 app/(root)/help/page.tsx delete mode 100644 app/(root)/terms/page.tsx create mode 100644 components/landing/MarketClock.tsx create mode 100644 components/landing/ProductPreview.tsx create mode 100644 components/marketing/IconCard.tsx create mode 100644 components/marketing/PageHero.tsx create mode 100644 components/marketing/SectionHead.tsx create mode 100644 components/sponsors/SponsorsBand.tsx create mode 100644 lib/github.ts create mode 100644 lib/market-session.ts create mode 100644 lib/sponsors.ts delete mode 100644 public/assets/images/siray-logo.png diff --git a/README.md b/README.md index d2bba52..de3d7ea 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,19 @@ GEMINI_API_KEY=your_gemini_api_key # Get this from your Inngest dashboard: https://app.inngest.com/env/settings/keys INNGEST_SIGNING_KEY=your_inngest_signing_key +# Market data (optional) +# Several free Finnhub keys, rotated per request: each adds 60 requests/min. +# FINNHUB_API_KEYS=key_one,key_two +# "cached" (default) refreshes quotes hourly for everyone; "realtime" refreshes every 15s. +# NEXT_PUBLIC_OPENSTOCK_DATA_MODE=cached + +# Social sign-in (optional; each provider is hidden server-side until set) +# Callback URLs: /api/auth/callback/google and /api/auth/callback/github +GOOGLE_CLIENT_ID=your_google_client_id +GOOGLE_CLIENT_SECRET=your_google_client_secret +GITHUB_CLIENT_ID=your_github_client_id +GITHUB_CLIENT_SECRET=your_github_client_secret + # Email (Nodemailer via Gmail; consider App Passwords if 2FA) NODEMAILER_EMAIL=youraddress@gmail.com NODEMAILER_PASSWORD=your_gmail_app_password @@ -325,6 +338,19 @@ GEMINI_API_KEY=your_gemini_api_key # Get this from your Inngest dashboard: https://app.inngest.com/env/settings/keys INNGEST_SIGNING_KEY=your_inngest_signing_key +# Market data (optional) +# Several free Finnhub keys, rotated per request: each adds 60 requests/min. +# FINNHUB_API_KEYS=key_one,key_two +# "cached" (default) refreshes quotes hourly for everyone; "realtime" refreshes every 15s. +# NEXT_PUBLIC_OPENSTOCK_DATA_MODE=cached + +# Social sign-in (optional; each provider is hidden server-side until set) +# Callback URLs: /api/auth/callback/google and /api/auth/callback/github +GOOGLE_CLIENT_ID=your_google_client_id +GOOGLE_CLIENT_SECRET=your_google_client_secret +GITHUB_CLIENT_ID=your_github_client_id +GITHUB_CLIENT_SECRET=your_github_client_secret + # Email (Nodemailer via Gmail; consider App Passwords if 2FA) NODEMAILER_EMAIL=youraddress@gmail.com NODEMAILER_PASSWORD=your_gmail_app_password @@ -482,13 +508,16 @@ OpenStock is and will remain free and open for everyone. This project is license -## ❤️ Partners & Backers +## ❤️ Sponsors - - Siray.ai Logo - +OpenStock is open for sponsors. It stays free because people and companies back it, and sponsors are shown on the website, in the app and here. See the tiers on the `/sponsor` page of the site, or [talk with us](mailto:opendevsociety@gmail.com) about a custom partnership. -**[Siray.ai](https://www.siray.ai/)** — The robust AI infrastructure backing OpenStock. Siray.ai ensures our market insights never sleep. +- **Sponsor:** [GitHub Sponsors](https://github.com/sponsors/ravixalgorithm), monthly tiers from $5 or one-time +- **Contribute:** pick a [good first issue](https://github.com/Open-Dev-Society/OpenStock/issues?q=is%3Aopen+label%3A%22good+first+issue%22) +- **Spread the word:** star the repo and share it + +**Current sponsors:** your logo here. +**Previously backed by:** [Siray.ai](https://www.siray.ai/) (2026) ## Special thanks Huge thanks to [Adrian Hajdin (JavaScript Mastery)](https://github.com/adrianhajdin) — his excellent Stock Market App tutorial was instrumental in building OpenStock for the open-source community under the Open Dev Society. diff --git a/app/(marketing)/about/page.tsx b/app/(marketing)/about/page.tsx new file mode 100644 index 0000000..0d34ea3 --- /dev/null +++ b/app/(marketing)/about/page.tsx @@ -0,0 +1,64 @@ +import Image from 'next/image'; +import { Code, Globe, Heart } from 'lucide-react'; +import PageHero from '@/components/marketing/PageHero'; +import SectionHead from '@/components/marketing/SectionHead'; +import IconCard from '@/components/marketing/IconCard'; +import { GOOD_FIRST_ISSUES_URL, REPO_URL } from '@/lib/constants'; + +export const metadata = { + title: 'About | OpenStock', + description: 'The story behind OpenStock and the Open Dev Society.', +}; + +const PRINCIPLES = [ + { icon: Globe, title: 'Open access', body: 'No premium tiers for core features. Charts, watchlists and alerts stay free for everyone.' }, + { icon: Code, title: 'Open source', body: 'Fully transparent codebase. Audit our algorithms, contribute features, and build with us.' }, + { icon: Heart, title: 'Community driven', body: 'Powered by donations and volunteers. We answer to our users, not shareholders.' }, +]; + +export default function AboutPage() { + return ( + <> + + See the code + Contribute + + +
+ +
+ {PRINCIPLES.map(({ icon, title, body }) => {body})} +
+
+ +
+
+
+
+

Open Dev Society

+

Born from a simple frustration.

+

+ Why are powerful financial tools so expensive? OpenStock is our answer. +

+

+ We are a collective of developers, designers and financial enthusiasts working under the Open Dev Society + banner. Our mission is to democratise software by building high-quality, open-source alternatives to + proprietary platforms. +

+ + Open Dev Society on GitHub + +
+
+ Open Dev Society +
+
+
+
+ + ); +} diff --git a/app/(marketing)/api-docs/page.tsx b/app/(marketing)/api-docs/page.tsx new file mode 100644 index 0000000..5c8c18a --- /dev/null +++ b/app/(marketing)/api-docs/page.tsx @@ -0,0 +1,129 @@ +import { BarChart2, Clock, Mail, UserX } from 'lucide-react'; +import PageHero from '@/components/marketing/PageHero'; +import SectionHead from '@/components/marketing/SectionHead'; +import IconCard from '@/components/marketing/IconCard'; +import { REPO_URL } from '@/lib/constants'; + +export const metadata = { + title: 'Architecture | OpenStock', + description: 'How OpenStock works: market data, background jobs and the AI behind the emails.', +}; + +const DATA_MODES = [ + { name: 'Cached', cadence: 'Hourly', body: 'Default for the public site. Quotes are fetched once an hour and shared by every user, so cost grows with symbols, not people.' }, + { name: 'Realtime', cadence: 'Every 15 seconds', body: 'For OpenStock Cloud and self-hosting. Set NEXT_PUBLIC_OPENSTOCK_DATA_MODE=realtime and on-screen prices refresh live.' }, +]; + +const COVERAGE = [ + ['US stocks, crypto', 'Live', 'Yes'], + ['Forex', 'Live', 'No'], + ['Canada, Australia', 'Delayed', 'No'], + ['India (BSE), Germany', 'End of day', 'No'], +]; + +const FLOW = ['A user signs up, or a cron fires', 'Inngest runs the function', 'Gemini writes the text', 'MiniMax takes over if Gemini fails', 'The email goes out']; + +const JOBS = [ + { icon: Mail, title: 'Welcome email', trigger: 'On sign-up', body: 'An AI-written intro tailored to the country, goal, risk and industry picked at sign-up.' }, + { icon: BarChart2, title: 'Weekly news', trigger: 'Mon 09:00', body: 'Summarises the week’s market news and sends it as a Kit broadcast.' }, + { icon: Clock, title: 'Price alerts', trigger: 'Every 5 min', body: 'Checks every active alert against Finnhub quotes and emails the owner when one fires.' }, + { icon: UserX, title: 'Re-engagement', trigger: 'Daily 10:00', body: 'Finds dormant accounts and sends a gentle nudge.' }, +]; + +const STACK = [ + ['Finnhub', 'Quotes, company profiles, search and news. A pool of keys, rotated per request.', 'https://finnhub.io'], + ['TradingView', 'Charts, heatmaps, technicals and market widgets, embedded live.', 'https://www.tradingview.com/widget/'], + ['Inngest', 'Background jobs and schedules, with retries.', 'https://www.inngest.com'], + ['Better Auth', 'Email, Google and GitHub sign-in with MongoDB sessions.', 'https://www.better-auth.com'], + ['MongoDB Atlas', 'Users, watchlists and alerts.', 'https://www.mongodb.com/atlas'], + ['Kit', 'Newsletter broadcasts for the weekly digest.', 'https://kit.com'], +]; + +export default function ArchitecturePage() { + return ( + <> + + v1.0.0 + Gemini with MiniMax fallback + Open source · AGPL-3.0 + + +
+ +
+ {DATA_MODES.map(({ name, cadence, body }) => ( +
+
+
+

{name}

+ {cadence} +
+

{body}

+
+
+ ))} +
+
+
+ + + + {COVERAGE.map(([market, charts, quotes]) => ( + + + + + + ))} + +
MarketChartsOur quotes and alerts
{market}{charts}{quotes}
+
+
+ Full market support notes +
+ +
+
+ +
+
+
    + {FLOW.map((step, i) => ( +
  1. + {i + 1} + {step} +
  2. + ))} +
+
+
+ +
+ +
+ {JOBS.map(({ icon, title, trigger, body }) => ( + {trigger}}>{body} + ))} +
+
+ +
+ +
+
+ {STACK.map(([name, body, url]) => ( + + {name} + {body} + + ))} +
+
+
+ + ); +} diff --git a/app/(marketing)/help/page.tsx b/app/(marketing)/help/page.tsx new file mode 100644 index 0000000..5c18408 --- /dev/null +++ b/app/(marketing)/help/page.tsx @@ -0,0 +1,88 @@ +import { Metadata } from 'next'; +import { BookOpen, ChevronDown, Github, MessageCircle } from 'lucide-react'; +import PageHero from '@/components/marketing/PageHero'; +import SectionHead from '@/components/marketing/SectionHead'; +import IconCard from '@/components/marketing/IconCard'; +import { DISCORD_URL, REPO_URL } from '@/lib/constants'; + +export const metadata: Metadata = { + title: 'Help | OpenStock', + description: 'Community-driven support for OpenStock. No paywalls, just help.', +}; + +const FAQS = [ + { + question: 'Is OpenStock really free?', + answer: 'Yes. We run on sponsors and community contributions. Core features (charts, watchlists, alerts) stay free. OpenStock Cloud, coming soon, adds live quotes for $5 a month.', + }, + { + question: 'How do I add a stock to my watchlist?', + answer: 'Press ⌘K (or Search stocks in the sidebar), open the company, then press Watch. It shows up in your watchlist and in the sidebar.', + }, + { + question: 'Where does the market data come from?', + answer: 'Charts come live from TradingView. Quotes, watchlist prices and alerts come from Finnhub; on this site they refresh hourly and every price shows when it was last traded.', + }, + { + question: 'Which markets are supported?', + answer: 'US stocks, crypto and forex live; Canada and Australia delayed; India (through BSE) and Germany end of day. Alerts work for US stocks and crypto.', + }, + { + question: 'My alert hasn’t fired.', + answer: 'Alerts are checked every five minutes and emailed to your account address when the price crosses your target. Check the alert’s status on the watchlist page.', + }, + { + question: 'Can I contribute code or designs?', + answer: 'Absolutely. Issues labelled “good first issue” are a good start. We welcome designers, developers and writers alike.', + }, +]; + +export default function HelpPage() { + return ( + <> + + +
+ Read the architecture}> + Data sources, background jobs and the AI behind the emails. + + Join Discord}> + Get answers from other users and the maintainers. + + Open an issue}> + Found something broken? Tell us on GitHub. + +
+ +
+ +
+
+ {FAQS.map(({ question, answer }) => ( +
+ {/* Padding lives on the summary so the whole row is the click target, in every browser */} + + {question} + + +

{answer}

+
+ ))} +
+
+
+ +
+
+
+
+

Still stuck?

+

Our team and community answer emails, for free.

+
+ Email support +
+
+
+ + ); +} diff --git a/app/(marketing)/layout.tsx b/app/(marketing)/layout.tsx new file mode 100644 index 0000000..a87f8c8 --- /dev/null +++ b/app/(marketing)/layout.tsx @@ -0,0 +1,77 @@ +import Link from "next/link"; +import Image from "next/image"; +import { Github } from "lucide-react"; +import { getSession } from "@/lib/better-auth/auth"; +import { formatCount, getRepoStats } from "@/lib/github"; +import OpenDevSocietyBranding from "@/components/OpenDevSocietyBranding"; +import SponsorsBand from "@/components/sponsors/SponsorsBand"; +import { DISCORD_URL, REPO_URL } from "@/lib/constants"; + +const FOOTER_LINKS = [ + { href: '/about', label: 'About' }, + { href: '/help', label: 'Help' }, + { href: '/api-docs', label: 'Architecture' }, + { href: '/terms', label: 'Terms' }, + { href: '/sponsor', label: 'Sponsor' }, + { href: REPO_URL, label: 'GitHub' }, + { href: DISCORD_URL, label: 'Discord' }, + { href: 'https://www.linkedin.com/company/opendevsociety-in/', label: 'LinkedIn' }, +]; + +export default async function MarketingLayout({ children }: { children: React.ReactNode }) { + const [session, repo] = await Promise.all([getSession(), getRepoStats()]); + const signedIn = !!session?.user; + + return ( +
+
+
+ + OpenStock + + +
+ + + {repo && {formatCount(repo.stars)}} + + {signedIn ? ( + Open dashboard + ) : ( + <> + Sign in + Get started + + )} +
+
+
+ +
{children}
+ + + +
+
+ OpenStock +

© {new Date().getFullYear()} Open Dev Society · AGPL-3.0

+
+ + +
+
+ ); +} diff --git a/app/(marketing)/page.tsx b/app/(marketing)/page.tsx new file mode 100644 index 0000000..49f22db --- /dev/null +++ b/app/(marketing)/page.tsx @@ -0,0 +1,226 @@ +import Link from "next/link"; +import { Bell, CandlestickChart, Command, GitPullRequest, Github, Grid3x3, HeartHandshake, MailOpen, MessagesSquare, Star } from "lucide-react"; +import { MarketDial, MarketStatus } from "@/components/landing/MarketClock"; +import ProductPreview from "@/components/landing/ProductPreview"; +import SectionHead from "@/components/marketing/SectionHead"; +import IconCard from "@/components/marketing/IconCard"; +import { getSession } from "@/lib/better-auth/auth"; +import { formatCount, getRepoStats } from "@/lib/github"; +import { cn } from "@/lib/utils"; +import { DISCORD_URL, GOOD_FIRST_ISSUES_URL, REPO_URL } from "@/lib/constants"; + +const FEATURES = [ + { icon: CandlestickChart, title: 'Charts that move', body: 'TradingView candles, technicals and financials for any listed company, full screen when you need room.' }, + { icon: Bell, title: 'Alerts by email', body: 'Set a target above or below the price. We check every five minutes and write when it crosses.' }, + { icon: MessagesSquare, title: 'Sentiment in one read', body: 'Buzz and bullishness from Reddit, X.com, news and Polymarket, side by side for each stock.' }, + { icon: Grid3x3, title: 'The whole market', body: 'Sector heatmap, movers and top stories on one screen before the bell.' }, + { icon: Command, title: 'Find anything with ⌘K', body: 'Search every exchange Finnhub covers and open a stock as a tab, like a browser.' }, + { icon: MailOpen, title: 'A Monday digest', body: 'A short, AI-written summary of the week’s news for the stocks you watch.' }, +]; + +const TIERS = [ + { + name: 'Community', price: 'Free', cadence: 'Hourly', perHour: 1, + body: 'This site. Quotes refresh every hour and are shared by everyone from the edge. Charts stay live.', + cta: { label: 'Get started', href: '/sign-up' }, + }, + { + name: 'OpenStock Cloud', price: '$5', per: '/month', tag: 'Coming soon', cadence: 'Every 15 seconds', perHour: 240, + body: 'The same app with live quotes, hosted on a pool of market data keys. Nothing to set up.', + cta: { label: 'Get notified on Discord', href: DISCORD_URL }, + }, + { + name: 'Self-host', price: 'Free', cadence: 'Your call', perHour: 240, + body: 'Run it on your own server with your own Finnhub keys, realtime for you and your team.', + cta: { label: 'Setup guide', href: '#self-host' }, + }, +]; + +const SUPPORT = [ + { + icon: HeartHandshake, title: 'Sponsor', primary: true, + body: 'Monthly tiers from $5, a one-time gift, or a custom partnership. Sponsors are shown on this site, in the app and in the README.', + cta: { label: 'See sponsor tiers', href: '/sponsor' }, + }, + { + icon: GitPullRequest, title: 'Contribute', + body: 'Pick a good first issue, improve the docs or design a screen. Every merged pull request keeps OpenStock moving.', + cta: { label: 'Good first issues', href: GOOD_FIRST_ISSUES_URL }, + }, + { + icon: Star, title: 'Spread the word', + body: 'Star the repo and share it with someone paying for a terminal they barely use.', + cta: { label: 'Star on GitHub', href: REPO_URL }, + }, +]; + +// 60 minutes of updates drawn as ticks: one line per refresh. +const CadenceRail = ({ perHour }: { perHour: number }) => ( +
1 + ? `repeating-linear-gradient(90deg, var(--brand) 0 1px, transparent 1px calc(100% / ${perHour}))` + : 'linear-gradient(90deg, var(--brand) 0 2px, transparent 2px)', + }} + aria-hidden + /> +); + +export default async function LandingPage() { + const [session, repo] = await Promise.all([getSession(), getRepoStats()]); + const start = session?.user ? { href: '/dashboard', label: 'Open dashboard' } : { href: '/sign-up', label: 'Get started free' }; + + return ( + <> +
+
+ +

+ Markets, minus
the paywall. +

+

+ OpenStock is an open-source alternative to expensive market platforms. Track prices, set alerts and dig into + company insights, built openly, for everyone. +

+ +
+
+
+
+
+ +
+ +
+ +
+ +
+ {FEATURES.map(({ icon, title, body }) => ( + {body} + ))} +
+
+ +
+ +
+ {TIERS.map((tier) => ( +
+
+
+

{tier.name}

+ {tier.tag && {tier.tag}} +
+

{tier.price}{tier.per && {tier.per}}

+

{tier.body}

+
+ +

+ {tier.cadence} + {tier.perHour} {tier.perHour === 1 ? 'update' : 'updates'} an hour +

+
+ + {tier.cta.label} + +
+
+ ))} +
+
+ +
+ +
+
+                        $ git clone {REPO_URL}.git{'\n'}
+                        $ cd OpenStock{'\n\n'}
+                        # .env (every variable is in the README){'\n'}
+                        FINNHUB_API_KEYS=key_one,key_two,key_three{'\n'}
+                        NEXT_PUBLIC_OPENSTOCK_DATA_MODE=realtime{'\n\n'}
+                        $ docker compose up -d --build
+                    
+
+
+ + + +
+
+
+
+

Open Dev Society

+
+ Technology should belong to everyone. Knowledge should be open, free, and accessible. +
+
+ {start.label} + Read the manifesto +
+
+ {repo && ( +
+ {[ + ['Stars', formatCount(repo.stars)], + ['Forks', formatCount(repo.forks)], + ['License', repo.license ?? 'AGPL-3.0'], + ['Written in', 'TypeScript'], + ].map(([label, value]) => ( +
+
{label}
+
{value}
+
+ ))} +
+ )} +
+
+
+ + ); +} diff --git a/app/(marketing)/sponsor/page.tsx b/app/(marketing)/sponsor/page.tsx new file mode 100644 index 0000000..3126753 --- /dev/null +++ b/app/(marketing)/sponsor/page.tsx @@ -0,0 +1,185 @@ +import { Check, HandCoins, MessageCircle, Minus } from "lucide-react"; +import { getRepoStats, formatCount } from "@/lib/github"; +import { DISCORD_URL, sponsorCheckoutUrl } from "@/lib/constants"; +import { ACTIVE_SPONSORS, SPONSOR_CONTACT_EMAIL, SPONSOR_GOAL, SPONSOR_TIERS, type SponsorTierId } from "@/lib/sponsors"; +import { cn } from "@/lib/utils"; + +export const metadata = { + title: 'Sponsor OpenStock', + description: 'Back free, open-source market data. Monthly tiers, one-time gifts, or talk with us about a partnership.', +}; + +const MAILTO = `mailto:${SPONSOR_CONTACT_EMAIL}?subject=Sponsoring%20OpenStock`; + +// Where each tier shows up. Mirrors the perks in lib/sponsors.ts. +const PLACEMENTS: { label: string; from: SponsorTierId }[] = [ + { label: 'Name in the README sponsor list', from: 'backer' }, + { label: 'Name and avatar on the sponsor wall', from: 'supporter' }, + { label: 'Logo in the footer of every public page', from: 'company' }, + { label: 'Logo in the README', from: 'company' }, + { label: 'Logo on the landing page', from: 'partner' }, + { label: 'Sponsor slot in the app sidebar', from: 'partner' }, +]; +const TIER_ORDER: SponsorTierId[] = ['backer', 'supporter', 'company', 'partner']; + +const FAQ = [ + ['How do I pay?', 'Through GitHub Sponsors, by card or PayPal. Pick a monthly amount or give once.'], + ['Can I stop?', 'Yes, any time from your GitHub Sponsors settings.'], + ['Can we sponsor as a company?', 'Yes. Sponsor from your organisation’s GitHub account, then send us your logo and link. For invoices or a custom deal, talk with us.'], +]; + +export default async function SponsorPage() { + const repo = await getRepoStats(); + const goalPercent = Math.min(100, (SPONSOR_GOAL.current / SPONSOR_GOAL.target) * 100); + + return ( +
+
+
+

Open for sponsors

+

Back free
market data.

+

+ OpenStock is an open-source market terminal{repo ? ` with ${formatCount(repo.stars)} stars on GitHub` : ''}. + Sponsors keep it free and independent for everyone who can’t pay for a terminal. +

+ +
+ +
+
+
+

Goal

+

{SPONSOR_GOAL.current} of {SPONSOR_GOAL.target.toLocaleString('en-US')}

+
+

{SPONSOR_GOAL.target.toLocaleString('en-US')} {SPONSOR_GOAL.label}

+
+
+
+ {repo && ( +
+ {[['Stars', formatCount(repo.stars)], ['Forks', formatCount(repo.forks)]].map(([label, value]) => ( +
+
{label}
+
{value}
+
+ ))} +
+ )} +
+
+
+ +
+

Monthly

+

Pick a tier.

+ +
+ {SPONSOR_TIERS.map((tier) => { + const filled = ACTIVE_SPONSORS.filter((s) => s.tier === tier.id).length; + const taken = tier.slots ? filled >= tier.slots : false; + return ( +
+
+
+

{tier.name}

+ {tier.featured && Best for teams} + {tier.slots && {taken ? 'All taken' : `${tier.slots - filled} of ${tier.slots} open`}} +
+

${tier.monthly} /month

+

{tier.blurb}

+
    + {tier.perks.map((perk) => ( +
  • + + {perk} +
  • + ))} +
+ + {taken ? 'Join the waitlist' : `Sponsor $${tier.monthly}/month`} + +
+
+ ); + })} +
+ +
+
+
+ +
+

Give once

+

Any amount, one time, through GitHub Sponsors.

+
+ Give once +
+
+
+
+ +
+

Something else in mind?

+

Data or infrastructure credits, a custom placement or a partnership.

+
+ +
+
+
+
+ +
+

Placements

+

Where your name shows up.

+
+
+ + + + + {TIER_ORDER.map((id) => )} + + + + {PLACEMENTS.map(({ label, from }) => ( + + + {TIER_ORDER.map((id) => ( + + ))} + + ))} + +
Placement{SPONSOR_TIERS.find((t) => t.id === id)!.name}
{label} + {TIER_ORDER.indexOf(id) >= TIER_ORDER.indexOf(from) + ? + : } +
+
+
+
+ +
+ {FAQ.map(([q, a]) => ( +
+
+

{q}

+

{a}

+
+
+ ))} +
+
+ ); +} diff --git a/app/(marketing)/terms/page.tsx b/app/(marketing)/terms/page.tsx new file mode 100644 index 0000000..bd7d167 --- /dev/null +++ b/app/(marketing)/terms/page.tsx @@ -0,0 +1,87 @@ +import { Metadata } from 'next'; +import { AlertTriangle, Check, X } from 'lucide-react'; +import PageHero from '@/components/marketing/PageHero'; +import SectionHead from '@/components/marketing/SectionHead'; + +export const metadata: Metadata = { + title: 'Terms of Service | OpenStock', + description: 'Fair, transparent, and open terms for our community.', +}; + +const PROMISES = [ + 'Core features will remain free forever.', + 'We will never sell your personal data.', + 'Terms changes will be discussed openly.', + 'You own your watchlists and analysis.', +]; + +const RULES = { + do: ['Share knowledge freely', 'Use the API for personal projects', 'Respect other members'], + dont: ['Scrape data excessively', 'Share API keys', 'Use OpenStock for high-frequency trading'], +}; + +export default function TermsPage() { + return ( + <> + + +
+
+
+ +
+

Investment disclaimer

+

+ OpenStock is an educational and analysis tool, not a financial advisor.{' '} + Data is provided as is, for information only. Never invest money you cannot afford to lose. Always do your own + research or consult a certified professional before making financial decisions. +

+
+
+
+
+ +
+ +
+ {PROMISES.map((promise) => ( +
+
+ + {promise} +
+
+ ))} +
+
+ +
+ +
+ {([['Do', RULES.do, Check, 'text-up'], ['Don’t', RULES.dont, X, 'text-down']] as const).map(([title, items, Icon, tone]) => ( +
+
+

{title}

+
    + {items.map((item) => ( +
  • + + {item} +
  • + ))} +
+
+
+ ))} +
+

+ Questions about these terms? Email opendevsociety@gmail.com. +

+
+ + ); +} diff --git a/app/(root)/about/page.tsx b/app/(root)/about/page.tsx deleted file mode 100644 index e47294d..0000000 --- a/app/(root)/about/page.tsx +++ /dev/null @@ -1,133 +0,0 @@ - -import React from 'react'; -import Image from 'next/image'; -import Link from 'next/link'; -import { - Users, - Globe, - Heart, - Code, - Github, - Twitter, - Linkedin, - ArrowRight -} from 'lucide-react'; - -export const metadata = { - title: 'About Us | OpenStock', - description: 'The story behind OpenStock and the Open Dev Society.', -}; - -export default function AboutPage() { - return ( -
- {/* Hero Section */} -
-
-
- Open Dev Society -
-
- -

- Tools for Everyone. -

-

- We believe financial intelligence shouldn't be locked behind paywalls. - OpenStock is built by the community, for the community. -

-
- - {/* Mission Grid */} -
- } - title="Open Access" - desc="No premium tiers for core features. Real-time data and insights available to all, forever." - color="blue" - /> - } - title="Open Source" - desc="Fully transparent codebase. Audit our algorithms, contribute features, and build with us." - color="purple" - /> - } - title="Community Driven" - desc="Powered by donations and volunteers. We answer to our users, not shareholders." - color="red" - /> -
- - {/* Story Section */} -
-
-

The Open Dev Society

-

- OpenStock was born from a simple frustration: why are powerful financial tools so expensive? -

-

- We are a collective of developers, designers, and financial enthusiasts working under the Open Dev Society banner. Our mission is to democratize software by building high-quality, open-source alternatives to proprietary platforms. -

-
- - Visit our GitHub - -
-
-
- Open Dev Society -
-
- - {/* Team / Contributors */} -
-

Backed by Amazing Partners

-
-
- - Siray - Siray.ai - -
-
-
- -
- ); -} - -function FeatureCard({ icon, title, desc, color }: any) { - const borders: any = { - blue: 'hover:border-blue-500/50', - purple: 'hover:border-purple-500/50', - red: 'hover:border-red-500/50', - }; - - return ( -
-
{icon}
-

{title}

-

{desc}

-
- ); -} - -function SocialButton({ href, icon, label }: any) { - return ( - - {icon} - {label} - - ); -} diff --git a/app/(root)/api-docs/page.tsx b/app/(root)/api-docs/page.tsx deleted file mode 100644 index b24f07e..0000000 --- a/app/(root)/api-docs/page.tsx +++ /dev/null @@ -1,247 +0,0 @@ - -import React from 'react'; -import Image from 'next/image'; -import Link from 'next/link'; -import { - Server, - Cpu, - ShieldCheck, - Clock, - Database, - Mail, - BarChart2, - Zap, - ArrowRight, - CheckCircle2, - AlertTriangle -} from 'lucide-react'; - -export const metadata = { - title: 'API & Architecture | OpenStock', - description: 'Technical documentation for OpenStock architecture, AI integrations, and background jobs.', -}; - -export default function ApiDocsPage() { - return ( -
- {/* Hero Section */} -
-
-
- openstock -
- + -
- Siray -
-
- -

- OpenStock Architecture -

-

- A transparent look at the event-driven, multi-provider system powering your market insights. -

- -
- v1.0.0 Active - Gemini + Siray AI - Open Source AGPL-3.0 -
-
- - {/* AI Architecture Section */} -
-
-
- -

Intelligent UI

-
-

- We prioritize uptime for generative features (Welcome Emails, News Summaries) using a robust - multi-provider strategy. Our system automatically routes around outages. -

- -
-
-
- -
-
-

- Primary: Google Gemini - Flash Lite 2.5 -

-

- Handles high-volume inference for news summarization and personalization. -

-
-
- -
- -
-
- -
-
-

- Fallback: Siray.ai - Ultra 1.0 -

-

- Instant failover protection. If Gemini wavers, Siray takes over to ensure zero dropped requests. -

-
-
-
-
- - {/* Diagram / Visual */} -
-
- - {/* Visual Flowchart */} -
-
- User Action / Cron Job -
-
-
-
- Inngest Function -
- Attempt Gemini - -
-
- - Fallback to Siray - - - -
-
-
-
- Content Delivered -
-
-
-
- - {/* Background Jobs */} -
-
- -

Serverless Infrastructure

-
- -
- } - title="Sign Up Email" - trigger="Event" - desc="Generates personalized welcome/onboarding email via AI." - color="purple" - /> - } - title="Weekly News" - trigger="Cron: Mon 9am" - desc="Summarizes market news and broadcasts via ConvertKit." - color="teal" - /> - } - title="Stock Alerts" - trigger="Cron: 5m" - desc="Checks user price targets against real-time data." - color="yellow" - /> - } - title="Re-engagement" - trigger="Cron: Daily" - desc="Identifies dormant users and sends nudges." - color="red" - /> -
-
- - {/* Integration Stack */} -
-
- -

Tech Stack & Data

-
- -
- - - -
-
- -
- ); -} - -// Helper Components - -function Badge({ children, color }: { children: React.ReactNode, color: 'green' | 'purple' | 'blue' }) { - const colors = { - green: 'bg-green-500/10 text-green-400 border-green-500/20', - purple: 'bg-purple-500/10 text-purple-400 border-purple-500/20', - blue: 'bg-blue-500/10 text-blue-400 border-blue-500/20', - }; - return ( - - {children} - - ); -} - -function JobCard({ icon, title, trigger, desc, color }: any) { - const colorClasses: any = { - purple: 'text-purple-400 bg-purple-500/10 border-purple-500/20 hover:border-purple-500/40', - teal: 'text-teal-400 bg-teal-500/10 border-teal-500/20 hover:border-teal-500/40', - yellow: 'text-yellow-400 bg-yellow-500/10 border-yellow-500/20 hover:border-yellow-500/40', - red: 'text-red-400 bg-red-500/10 border-red-500/20 hover:border-red-500/40', - }; - - return ( -
-
{icon}
-

{title}

-
{trigger}
-

{desc}

-
- ); -} - -function StackItem({ title, desc, url }: any) { - return ( - -
-
-

{title}

-

{desc}

-
- -
- - ); -} diff --git a/app/(root)/help/page.tsx b/app/(root)/help/page.tsx deleted file mode 100644 index 92f5bd1..0000000 --- a/app/(root)/help/page.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { Metadata } from 'next'; -import { - HelpCircle, - MessageCircle, - BookOpen, - Lightbulb, - Mail, - Github, - ChevronDown -} from 'lucide-react'; - -export const metadata: Metadata = { - title: 'Help Center | OpenStock', - description: 'Community-driven support for OpenStock. No paywalls, just help.', -}; - -export default function HelpPage() { - const faqs = [ - { - question: "Is OpenStock really free forever?", - answer: "Yes! We run on donations and community contribution. Core features (tracking, alerts, analysis) will remain free. We believe financial tools shouldn't be luxury items." - }, - { - question: "How do I add stocks to my watchlist?", - answer: "Use the search bar at the top or in the header to find a company. On the stock's detail page, click the 'Heart' or 'Star' icon to instantly add it to your dashboard." - }, - { - question: "Where does the market data come from?", - answer: "We partner with Finnhub and other providers to offer real-time and delayed data. While robust, please use it for analysis rather than high-frequency trading." - }, - { - question: "Can I contribute code or designs?", - answer: "Absolutely! Check our GitHub repository. We label issues as 'good first issue' for beginners. We welcome designers, developers, and writers alike." - }, - { - question: "My alerts aren't triggering.", - answer: "Alerts run every 5 minutes via our background jobs. Ensure you've confirmed your email address, as we send notifications primarily via email." - } - ]; - - return ( -
- - {/* Header */} -
-
- -
-

How can we help?

-

Community-powered support for everyone.

-
- - {/* Quick Action Grid */} -
- } - title="Read Docs" - desc="Deep dive into features and API integration." - link="/api-docs" - linkText="View Documentation" - /> - } - title="Community Chat" - desc="Get real-time answers from other users." - link="https://discord.gg/JkJ8kfxgxB" - linkText="Join Discord" - /> - } - title="Report Bugs" - desc="Found an issue? Let our developers know." - link="https://github.com/Open-Dev-Society/OpenStock/issues" - linkText="Open Issue" - /> -
- - {/* FAQs */} -
-

Frequently Asked Questions

-
- {faqs.map((faq, idx) => ( -
-

- - {faq.question} -

-

- {faq.answer} -

-
- ))} -
-
- - {/* Direct Contact */} -
-

Still stuck?

-

Our team (and community) answers emails, usually entirely for free.

- - - Contact Support - -
- -
- ); -} - -function HelpCard({ icon, title, desc, link, linkText }: any) { - return ( -
-
{icon}
-

{title}

-

{desc}

- - {linkText} - -
- ); -} diff --git a/app/(root)/terms/page.tsx b/app/(root)/terms/page.tsx deleted file mode 100644 index 0e67904..0000000 --- a/app/(root)/terms/page.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { Metadata } from 'next'; -import { Shield, FileText, Check, AlertTriangle, Scale } from 'lucide-react'; - -export const metadata: Metadata = { - title: 'Terms of Service | OpenStock', - description: 'Fair, transparent, and open terms for our community.', -}; - -export default function TermsPage() { - return ( -
- - {/* Hero */} -
-
- -
-

Terms of Service

-

- Built on trust, transparency, and community values. No hidden gotchas, just clear rules. -

-

Last updated: October 2025

-
- -
- {/* Core Philosophy */} -
-

- - Our Promise -

-
- - - - -
-
- - {/* Disclaimer */} -
-
- -
-

Investment Disclaimer

-

- **OpenStock is an educational and analysis tool, not a financial advisor.** - Data is provided "as is" for informational purposes. Never invest money you cannot afford to lose. - Always conduct your own research or consult a certified professional before making financial decisions. -

-
-
-
- - {/* User Responsibilities */} -
-

Community Rules

-
-
-

✅ Do's

-
    -
  • Share knowledge freely
  • -
  • Use API for personal projects
  • -
  • Respect other members
  • -
-
-
-

❌ Don'ts

-
    -
  • × Scrape data excessively
  • -
  • × Share API keys
  • -
  • × Use for high-frequency trading
  • -
-
-
-
- - {/* Footer Note */} -
-

- Questions about these terms? Email us at opendevsociety@gmail.com -

-
-
-
- ); -} - -function PromiseItem({ text }: { text: string }) { - return ( -
-
- -
- {text} -
- ); -} diff --git a/components/landing/MarketClock.tsx b/components/landing/MarketClock.tsx new file mode 100644 index 0000000..158ab53 --- /dev/null +++ b/components/landing/MarketClock.tsx @@ -0,0 +1,93 @@ +'use client'; + +import { useEffect, useState } from "react"; +import { cn } from "@/lib/utils"; + +import { AFTER_END, CLOSE, DAY, OPEN, PRE, isWeekday, newYorkNow, sessionOf, type Phase } from "@/lib/market-session"; + +function useNewYorkClock() { + const [now, setNow] = useState | null>(null); + useEffect(() => { + const tick = () => setNow(newYorkNow(new Date())); + tick(); + const id = setInterval(tick, 15_000); + return () => clearInterval(id); + }, []); + return now; +} + +// The live session line for the hero; renders a stable line until the client knows the time. +export function MarketStatus() { + const now = useNewYorkClock(); + const session = now ? sessionOf(now.weekday, now.minutes) : null; + return ( + + + {session?.line ?? 'NYSE · New York time'} + + ); +} + +const R = 88; +const C = 2 * Math.PI * R; +const ARCS: { phase: Phase; from: number; to: number; label: string }[] = [ + { phase: 'pre', from: PRE, to: OPEN, label: 'Pre' }, + { phase: 'open', from: OPEN, to: CLOSE, label: 'Regular' }, + { phase: 'after', from: CLOSE, to: AFTER_END, label: 'After' }, +]; + +// A 24h dial of the New York trading day. Sessions that aren't happening now are hatched. +export function MarketDial() { + const now = useNewYorkClock(); + const session = now ? sessionOf(now.weekday, now.minutes) : null; + const weekend = now ? !isWeekday(now.weekday) : false; + const markerAngle = now ? (now.minutes / DAY) * 360 : null; + + return ( +
+
+ + + + + + + + + {ARCS.map(({ phase, from, to }) => { + const active = !weekend && session?.phase === phase; + return ( + + ); + })} + {markerAngle !== null && ( + + + + )} + +
+ + {now?.time ?? '--:--'} + New York + +
+
+
    + {ARCS.map(({ phase, label }) => ( +
  • + + {label} +
  • + ))} +
+
+ ); +} diff --git a/components/landing/ProductPreview.tsx b/components/landing/ProductPreview.tsx new file mode 100644 index 0000000..2a23ea9 --- /dev/null +++ b/components/landing/ProductPreview.tsx @@ -0,0 +1,55 @@ +import { Suspense } from "react"; +import { Plus } from "lucide-react"; +import IndexPulse, { PulseSkeleton } from "@/components/IndexPulse"; +import DataFreshness from "@/components/DataFreshness"; +import TradingViewWidget from "@/components/TradingViewWidget"; +import { cn } from "@/lib/utils"; + +const MINI_CHART = 'https://s3.tradingview.com/external-embedding/embed-widget-mini-symbol-overview.js'; +const miniChart = (symbol: string) => ({ + symbol, locale: 'en', dateRange: '1M', colorTheme: 'dark', isTransparent: true, autosize: true, + trendLineColor: '#47d9bb', underLineColor: 'rgba(71, 217, 187, 0.14)', underLineBottomColor: 'rgba(71, 217, 187, 0)', +}); + +// The real app chrome with the same live data a signed-in user sees. Used on the landing and auth pages, +// so marketing never shows a stale screenshot. +export default function ProductPreview() { + return ( +
+
+ {[['Overview', true], ['AAPL', false], ['NVDA', false]].map(([label, active]) => ( + + {label} + + ))} + +
+
+
+
+
+

Index pulse

+

Tracking ETFs via Finnhub

+
+ +
+ }> + + +
+
+ {['AMEX:SPY', 'NASDAQ:QQQ'].map((symbol) => ( +
+
+ +
+
+ ))} +
+
+
+ ); +} diff --git a/components/marketing/IconCard.tsx b/components/marketing/IconCard.tsx new file mode 100644 index 0000000..e1bd5ab --- /dev/null +++ b/components/marketing/IconCard.tsx @@ -0,0 +1,16 @@ +import React from "react"; +import type { LucideIcon } from "lucide-react"; + +// Hatch shell holding one card: icon well, title, short body, optional footer (a link or a pill). +export default function IconCard({ icon: Icon, title, children, footer }: { icon: LucideIcon; title: string; children: React.ReactNode; footer?: React.ReactNode }) { + return ( +
+
+ +

{title}

+
{children}
+ {footer &&
{footer}
} +
+
+ ); +} diff --git a/components/marketing/PageHero.tsx b/components/marketing/PageHero.tsx new file mode 100644 index 0000000..097669b --- /dev/null +++ b/components/marketing/PageHero.tsx @@ -0,0 +1,13 @@ +import React from "react"; + +// Top of every public page: kicker, one headline, one supporting line, optional actions. +export default function PageHero({ kicker, title, sub, children }: { kicker: string; title: React.ReactNode; sub?: string; children?: React.ReactNode }) { + return ( +
+

{kicker}

+

{title}

+ {sub &&

{sub}

} + {children &&
{children}
} +
+ ); +} diff --git a/components/marketing/SectionHead.tsx b/components/marketing/SectionHead.tsx new file mode 100644 index 0000000..deffbb5 --- /dev/null +++ b/components/marketing/SectionHead.tsx @@ -0,0 +1,9 @@ +export default function SectionHead({ kicker, title, sub }: { kicker: string; title: string; sub?: string }) { + return ( +
+

{kicker}

+

{title}

+ {sub &&

{sub}

} +
+ ); +} diff --git a/components/sponsors/SponsorsBand.tsx b/components/sponsors/SponsorsBand.tsx new file mode 100644 index 0000000..ff5720b --- /dev/null +++ b/components/sponsors/SponsorsBand.tsx @@ -0,0 +1,72 @@ +import Link from "next/link"; +import { ACTIVE_SPONSORS, PREVIOUS_SPONSORS, SPONSOR_CONTACT_EMAIL, SPONSOR_TIERS, type Sponsor } from "@/lib/sponsors"; +import { cn } from "@/lib/utils"; + +const SponsorMark = ({ sponsor, muted }: { sponsor: Sponsor; muted?: boolean }) => ( + + {sponsor.logo ? {sponsor.name} : {sponsor.name}} + {muted && sponsor.period && {sponsor.period}} + +); + +// Open slots are real: each one is a tier someone can take today. +const OpenSlot = ({ tier }: { tier: string }) => ( + + {tier} slot open + +); + +export default function SponsorsBand() { + const openTiers = SPONSOR_TIERS.filter((t) => t.id === 'company' || t.id === 'partner') + .filter((t) => !t.slots || ACTIVE_SPONSORS.filter((s) => s.tier === t.id).length < t.slots); + + return ( +
+
+
+
+
+

Open for sponsors

+

Keep market data free for everyone.

+
+ +
+

Current sponsors

+
+ {ACTIVE_SPONSORS.map((s) => )} + {openTiers.map((t) => )} +
+
+ + {PREVIOUS_SPONSORS.length > 0 && ( +
+

Previously backed by

+
+ {PREVIOUS_SPONSORS.map((s) => )} +
+
+ )} +
+ +
+ Become a sponsor + Talk with us +
+
+
+
+ ); +} diff --git a/lib/github.ts b/lib/github.ts new file mode 100644 index 0000000..616129e --- /dev/null +++ b/lib/github.ts @@ -0,0 +1,19 @@ +import { cache } from "react"; + +// Real repo numbers for the public site, refreshed daily. Null hides the stat instead of guessing. +export const getRepoStats = cache(async () => { + try { + const res = await fetch('https://api.github.com/repos/Open-Dev-Society/OpenStock', { + next: { revalidate: 86400 }, + signal: AbortSignal.timeout(4000), + }); + if (!res.ok) return null; + const repo = await res.json(); + return { stars: repo.stargazers_count as number, forks: repo.forks_count as number, license: repo.license?.spdx_id as string | undefined }; + } catch { + return null; + } +}); + +export const formatCount = (n: number) => + new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }).format(n); diff --git a/lib/market-session.ts b/lib/market-session.ts new file mode 100644 index 0000000..ab6c23f --- /dev/null +++ b/lib/market-session.ts @@ -0,0 +1,40 @@ +// NYSE trading sessions, in New York minutes-of-day. +// ponytail: exchange holidays and half-days are ignored; add a holiday list if it matters. +export const PRE = 4 * 60, OPEN = 9 * 60 + 30, CLOSE = 16 * 60, AFTER_END = 20 * 60; +export const DAY = 24 * 60; + +export type Phase = 'pre' | 'open' | 'after' | 'closed'; + +export function newYorkNow(date: Date) { + const parts = Object.fromEntries( + new Intl.DateTimeFormat('en-US', { timeZone: 'America/New_York', weekday: 'short', hour: 'numeric', minute: 'numeric', hourCycle: 'h23' }) + .formatToParts(date).map((p) => [p.type, p.value]), + ); + const weekday = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].indexOf(parts.weekday); + return { weekday, minutes: Number(parts.hour) * 60 + Number(parts.minute), time: `${parts.hour.padStart(2, '0')}:${parts.minute}` }; +} + +export const isWeekday = (d: number) => d >= 1 && d <= 5; + +export function sessionOf(weekday: number, minutes: number): { phase: Phase; line: string } { + const until = (target: number) => formatSpan(target - minutes); + if (isWeekday(weekday)) { + if (minutes >= OPEN && minutes < CLOSE) return { phase: 'open', line: `Market open · closes in ${until(CLOSE)}` }; + if (minutes >= PRE && minutes < OPEN) return { phase: 'pre', line: `Pre-market · opens in ${until(OPEN)}` }; + if (minutes >= CLOSE && minutes < AFTER_END) return { phase: 'after', line: `After hours · ends in ${until(AFTER_END)}` }; + if (minutes < PRE) return { phase: 'closed', line: `Market closed · opens in ${until(OPEN)}` }; + } + // Next weekday open, counting whole days from today + let days = 1; + while (!isWeekday((weekday + days) % 7)) days++; + return { phase: 'closed', line: `Market closed · opens in ${formatSpan(days * DAY + OPEN - minutes)}` }; +} + +export function formatSpan(totalMinutes: number) { + const d = Math.floor(totalMinutes / DAY); + const h = Math.floor((totalMinutes % DAY) / 60); + const m = totalMinutes % 60; + if (d > 0) return `${d}d ${h}h`; + return h > 0 ? `${h}h ${String(m).padStart(2, '0')}m` : `${m}m`; +} + diff --git a/lib/sponsors.ts b/lib/sponsors.ts new file mode 100644 index 0000000..acd711b --- /dev/null +++ b/lib/sponsors.ts @@ -0,0 +1,60 @@ +// Everything sponsor-related lives here: edit this file when someone starts or stops sponsoring. +// Perks only name placements the code actually renders (README, sponsor wall, site footer, +// landing page, in-app sidebar), so the page never promises something the site doesn't do. + +export type Sponsor = { + name: string; + url: string; + logo?: string; // white/transparent logo in /public, shown on dark surfaces + tier?: SponsorTierId; + period?: string; // e.g. "2026" +}; + +export type SponsorTierId = 'backer' | 'supporter' | 'company' | 'partner'; + +// Partners share the app sidebar; the Partner tier sells exactly this many slots. +export const SIDEBAR_SPONSOR_SLOTS = 3; + +export const SPONSOR_TIERS: { + id: SponsorTierId; + name: string; + monthly: number; + blurb: string; + perks: string[]; + slots?: number; + featured?: boolean; +}[] = [ + { + id: 'backer', name: 'Backer', monthly: 5, + blurb: 'For people who use OpenStock and want it to stay free.', + perks: ['Your name in the README sponsor list', 'Our thanks, every month'], + }, + { + id: 'supporter', name: 'Supporter', monthly: 25, + blurb: 'For regulars who want to be seen backing open source.', + perks: ['Everything in Backer', 'Name and avatar on the sponsor wall', 'Listed on this page'], + }, + { + id: 'company', name: 'Company', monthly: 100, featured: true, + blurb: 'For teams and products that reach developers and investors.', + perks: ['Logo in the footer of every public page', 'Logo in the README', 'Logo on this page, linked to your site'], + }, + { + id: 'partner', name: 'Partner', monthly: 500, slots: SIDEBAR_SPONSOR_SLOTS, + blurb: 'The most visible spots in OpenStock, limited to three.', + perks: ['Everything in Company', 'One of three sponsor slots in the app sidebar, seen by every signed-in user', 'Logo on the landing page'], + }, +]; + +export const ACTIVE_SPONSORS: Sponsor[] = []; + +export const PREVIOUS_SPONSORS: Sponsor[] = [ + { name: 'Siray.ai', url: 'https://www.siray.ai', logo: '/assets/icons/siray.svg', period: '2026' }, +]; + +// Counted from GitHub Sponsors; individual sponsors stay anonymous unless they sponsor publicly. +export const SPONSOR_GOAL = { label: 'monthly sponsors', target: 1000, current: 1 }; + +export const SPONSOR_CONTACT_EMAIL = 'opendevsociety@gmail.com'; + +export const sidebarSponsors = () => ACTIVE_SPONSORS.filter((s) => s.tier === 'partner').slice(0, SIDEBAR_SPONSOR_SLOTS); diff --git a/public/assets/images/siray-logo.png b/public/assets/images/siray-logo.png deleted file mode 100644 index dd18af80d3f5183e0c1f216c507a04ec43c30c96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61691 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

&EL}GGNU6zaWoQcO~Z23*qan27{Ya!fAN? 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