diff --git a/apps/web/public/images/bauhaus-echo.png b/apps/web/public/images/bauhaus-echo.png new file mode 100644 index 0000000..81d9f77 Binary files /dev/null and b/apps/web/public/images/bauhaus-echo.png differ diff --git a/apps/web/public/images/smirk-logo.svg b/apps/web/public/images/smirk-logo.svg new file mode 100644 index 0000000..cbcf8fc --- /dev/null +++ b/apps/web/public/images/smirk-logo.svg @@ -0,0 +1,60 @@ + + + + diff --git a/apps/web/public/images/smirk-wallet.png b/apps/web/public/images/smirk-wallet.png index b97d645..6f78126 100644 Binary files a/apps/web/public/images/smirk-wallet.png and b/apps/web/public/images/smirk-wallet.png differ diff --git a/apps/web/src/app/about/page.tsx b/apps/web/src/app/about/page.tsx index 2fcfb2e..c18ecc4 100644 --- a/apps/web/src/app/about/page.tsx +++ b/apps/web/src/app/about/page.tsx @@ -1,5 +1,6 @@ import { FounderSignature } from "@/components/about/founder-signature"; import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; import { FaMapMarkerAlt, FaPhone, FaBuilding, FaExternalLinkAlt } from "react-icons/fa"; import { FaXTwitter, FaTelegram, FaDiscord } from "react-icons/fa6"; import type { Metadata } from "next"; @@ -22,7 +23,7 @@ export default function AboutPage() {
-
+

About Us

@@ -95,6 +96,7 @@ export default function AboutPage() {
+
); } diff --git a/apps/web/src/app/blog/bauhaus-echo-launch/page.tsx b/apps/web/src/app/blog/bauhaus-echo-launch/page.tsx new file mode 100644 index 0000000..47beb38 --- /dev/null +++ b/apps/web/src/app/blog/bauhaus-echo-launch/page.tsx @@ -0,0 +1,71 @@ +import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; +import Link from "next/link"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Bauhaus Echo is Live | Such Software Blog", + description: "Our first mobile game is available on Android and iOS. A visual memory puzzle inspired by Bauhaus design.", + alternates: { canonical: "/blog/bauhaus-echo-launch" }, +}; + +export default function BauhausEchoLaunchPost() { + return ( +
+
+
+ + ← Back to Blog + + +
+ +

Bauhaus Echo is Live

+
+ +
+

+ Bauhaus Echo is now available on Google Play and the App Store. It is a visual memory game + where you memorize tile arrangements, watch them shuffle, and reconstruct the original pattern. +

+ +

The Concept

+

+ The game shows you a grid of colorful geometric tiles inspired by Bauhaus design. You get a + few seconds to memorize their positions. Then the tiles spin, shrink, and scatter to the + bottom of the screen. Your job is to drag them back to where they belong. +

+ +

Four Game Modes

+
    +
  • Classic - The core experience. Memorize and reconstruct.
  • +
  • Speed - Tiles appear one at a time. Place each before the next drops.
  • +
  • Endless - Speed mode that loops forever. See how long you last.
  • +
  • Memory - Traditional card-matching pairs.
  • +
+ +

Tech Stack

+

+ Built with libGDX, a cross-platform Java game framework. The same codebase runs on Android, + iOS (via RoboVM), desktop, and web (via GWT). The tile assets are packed into a TextureAtlas + for efficient rendering. +

+ +

Download

+

+ Get it on{" "} + + Google Play + {" "} + or the{" "} + + App Store + + . Free with ads, or pay once to remove them. +

+
+
+ +
+ ); +} diff --git a/apps/web/src/app/blog/page.tsx b/apps/web/src/app/blog/page.tsx new file mode 100644 index 0000000..242155a --- /dev/null +++ b/apps/web/src/app/blog/page.tsx @@ -0,0 +1,69 @@ +import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; +import { Card } from "@repo/ui/components/card"; +import Link from "next/link"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Blog | Such Software", + description: "News, updates, and technical articles from Such Software.", + alternates: { canonical: "/blog" }, +}; + +// For now, hardcoded posts. Can migrate to MDX/CMS later. +const posts = [ + { + slug: "smirk-wallet-release", + title: "Smirk Wallet v0.1.6", + date: "2026-02-06", + excerpt: "Non-custodial browser extension for social tipping with BTC, LTC, XMR, WOW, and GRIN. Now on GitHub, Chrome Web Store pending.", + draft: false, + }, + { + slug: "website-relaunch-2026", + title: "Website Relaunch", + date: "2026-02-06", + excerpt: "We rebuilt such.software from the ground up. Here is what we used and why.", + draft: false, + }, + { + slug: "bauhaus-echo-launch", + title: "Bauhaus Echo is Live", + date: "2026-02-06", + excerpt: "Our first mobile game is available on Android and iOS. A visual memory puzzle inspired by Bauhaus design.", + draft: true, + }, +]; + +const publishedPosts = posts.filter((p) => !p.draft); + +export default function BlogPage() { + return ( +
+
+
+

Blog

+

+ News, launches, and technical notes. +

+ + {publishedPosts.length === 0 ? ( +

No posts yet. Check back soon.

+ ) : ( +
+ {publishedPosts.map((post) => ( + + + +

{post.title}

+

{post.excerpt}

+
+ + ))} +
+ )} +
+ +
+ ); +} diff --git a/apps/web/src/app/blog/smirk-wallet-release/page.tsx b/apps/web/src/app/blog/smirk-wallet-release/page.tsx new file mode 100644 index 0000000..2e17c1e --- /dev/null +++ b/apps/web/src/app/blog/smirk-wallet-release/page.tsx @@ -0,0 +1,114 @@ +import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; +import Link from "next/link"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Smirk Wallet v0.1.6 | Such Software Blog", + description: "Announcing Smirk Wallet, a non-custodial browser extension for social tipping with BTC, LTC, XMR, WOW, and GRIN.", + alternates: { canonical: "/blog/smirk-wallet-release" }, +}; + +export default function SmirkWalletReleasePost() { + return ( +
+
+
+ + ← Back to Blog + + +
+ +

Smirk Wallet v0.1.6

+
+ +
+

+ Smirk Wallet is a non-custodial browser extension that lets you tip people cryptocurrency + by their Telegram or Discord username. We have shipped six releases and the extension is + available now on GitHub. +

+ +

What It Does

+

+ One 12-word seed phrase gives you addresses for five currencies: Bitcoin, Litecoin, Monero, + Wownero, and Grin. Link your Telegram or Discord account on smirk.cash, and anyone running + Smirk can send you crypto by username. +

+

+ Tips are encrypted with the recipient's public key. Only they can claim. If a tip goes + unclaimed, the sender can claw it back. No funds get lost. +

+ +

Non-Custodial by Design

+

+ Your private spend keys are generated locally and never leave your browser. They are + encrypted with your password. We store only public keys and view keys (for Monero/Wownero + balance scanning). We cannot move your funds. +

+ +

What We Built

+
    +
  • Browser extension (TypeScript, Preact, Vite)
  • +
  • Backend API (Rust, Axum, PostgreSQL)
  • +
  • Light wallet servers for XMR and WOW
  • +
  • Grin wallet with client-side WASM
  • +
  • Telegram and Discord bots for tip notifications
  • +
  • User dashboard at smirk.cash
  • +
+ +

Chrome Web Store Status

+

+ Our initial submission was rejected for requesting an unused permission (activeTab). + We had included it for a planned feature that was not yet implemented. The fix is already + in v0.1.6. We have removed the permission and resubmitted. +

+

+ In the meantime, you can install manually from{" "} + + GitHub Releases + + . Firefox support is also available. +

+ +

Open Source

+

+ Everything is open source. The extension, backend, and WASM libraries are all on GitHub: +

+ + +

Get Started

+

+ Visit{" "} + + smirk.cash + {" "} + to learn more, or join the community on{" "} + + Telegram + {" "} + or{" "} + + Discord + + . +

+
+
+ +
+ ); +} diff --git a/apps/web/src/app/blog/website-relaunch-2026/page.tsx b/apps/web/src/app/blog/website-relaunch-2026/page.tsx new file mode 100644 index 0000000..d0634d9 --- /dev/null +++ b/apps/web/src/app/blog/website-relaunch-2026/page.tsx @@ -0,0 +1,76 @@ +import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; +import Link from "next/link"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Website Relaunch | Such Software Blog", + description: "We rebuilt such.software from the ground up. Here is what we used and why.", + alternates: { canonical: "/blog/website-relaunch-2026" }, +}; + +export default function WebsiteRelaunchPost() { + return ( +
+
+
+ + ← Back to Blog + + +
+ +

Website Relaunch

+
+ +
+

+ We rebuilt such.software. New design, new infrastructure, same focus on performance and accessibility. +

+ +

Stack

+
    +
  • Framework: Next.js 15 (App Router)
  • +
  • Language: TypeScript
  • +
  • Styling: Tailwind CSS with CSS variables for theming
  • +
  • Animation: Framer Motion
  • +
  • Monorepo: Turborepo + pnpm workspaces
  • +
  • Testing: Playwright with axe-core for accessibility
  • +
  • Bot Protection: Cloudflare Turnstile
  • +
  • Email: Resend
  • +
+ +

Procedural Graphics

+

+ The homepage features two custom procedural animations: NebulaField and DataGrid. Both are + SVG-based, theme-aware, and respect prefers-reduced-motion. NebulaField renders animated + data streams flowing toward a central icon using quadratic Bezier curves. DataGrid draws + a pulsing grid with traveling data packets. +

+ +

Accessibility

+

+ We run 42 automated accessibility tests across Chromium, Firefox, and WebKit on every build. + Tests cover WCAG 2.2 AA compliance, heading hierarchy, color contrast, keyboard navigation, + and form accessibility. Lighthouse scores are 99-100 across all pages. +

+ +

Performance

+

+ The NebulaField component is lazy loaded with next/dynamic and requestIdleCallback. Canvas + rendering is throttled. Fonts are loaded via next/font for zero layout shift. Images use + next/image for automatic optimization. +

+ +

Structure

+

+ The site now has Products, Services, Blog, and About sections. Products showcases our + standalone offerings: Webshops, Custom Websites, Smirk Wallet, and Bauhaus Echo. Services + covers our partnership model and consulting work. Mobile users get a bottom navigation bar. +

+
+
+ +
+ ); +} diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index c9b9d2a..ee3be83 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -5,6 +5,7 @@ import { ContactForm } from "@/components/contact/contact-form"; import { FounderSignature } from "@/components/about/founder-signature"; import { ServicesPreview } from "@/components/landing/services-preview"; import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; import { DynamicBackground } from "@/components/landing/dynamic-background"; import Link from "next/link"; import { Button } from "@repo/ui/components/button"; @@ -103,7 +104,7 @@ export default function Home() { -
+

Start a Project

@@ -114,6 +115,7 @@ export default function Home() {

+ ); } \ No newline at end of file diff --git a/apps/web/src/app/products/bauhaus-echo/page.tsx b/apps/web/src/app/products/bauhaus-echo/page.tsx new file mode 100644 index 0000000..199f421 --- /dev/null +++ b/apps/web/src/app/products/bauhaus-echo/page.tsx @@ -0,0 +1,97 @@ +import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; +import { Card } from "@repo/ui/components/card"; +import { Button } from "@repo/ui/components/button"; +import Link from "next/link"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Bauhaus Echo | Such Software", + description: "Visual memory puzzle game inspired by Bauhaus design. Memorize, shuffle, reconstruct. Android, iOS, Web, Desktop.", + alternates: { canonical: "/products/bauhaus-echo" }, +}; + +const gameModes = [ + { name: "Classic", description: "Memorize tile positions, reconstruct after shuffle" }, + { name: "Speed", description: "Tiles drop one at a time, place each before the next appears" }, + { name: "Endless", description: "Speed mode with tile cycling, play forever" }, + { name: "Memory", description: "Traditional card-matching pairs game" }, +]; + +export default function BauhausEchoPage() { + return ( +
+
+
+ + ← Back to Products + + +

+ Bauhaus Echo +

+ +
+

+ A visual memory puzzle game inspired by Bauhaus design aesthetics. + Memorize arrangements of geometric tiles, watch them shuffle, then reconstruct the pattern. +

+
+ + + +

How It Works

+
+
    +
  1. 1. Memorization — Tiles appear in a grid. Study their positions.
  2. +
  3. 2. Shuffle — Tiles spin, shrink, and scatter to the bottom.
  4. +
  5. 3. Reconstruction — Drag tiles back to their original positions.
  6. +
  7. 4. Scoring — Earn points based on accuracy and speed.
  8. +
+
+ +

Game Modes

+
+ {gameModes.map((mode) => ( + +

{mode.name}

+

{mode.description}

+
+ ))} +
+ +

Features

+
+ +

500+ Tile Designs

+

Curated Bauhaus-style geometric art

+
+ +

Multiple Grid Sizes

+

2×2, 3×3, 4×4, 5×5

+
+ +

Cross-Platform

+

Android, iOS, Web, Desktop

+
+
+ +
+ + Privacy Policy + + • + Contact: apps@such.software +
+
+ +
+ ); +} diff --git a/apps/web/src/app/products/bauhaus-echo/privacy/page.tsx b/apps/web/src/app/products/bauhaus-echo/privacy/page.tsx new file mode 100644 index 0000000..ab83af7 --- /dev/null +++ b/apps/web/src/app/products/bauhaus-echo/privacy/page.tsx @@ -0,0 +1,147 @@ +import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; +import Link from "next/link"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Privacy Policy | Bauhaus Echo | Such Software", + description: "Privacy policy for Bauhaus Echo mobile game.", + alternates: { canonical: "/products/bauhaus-echo/privacy" }, +}; + +export default function BauhausEchoPrivacyPage() { + return ( +
+
+
+ + ← Back to Bauhaus Echo + + +

Privacy Policy for Bauhaus Echo

+

Last Updated: January 31, 2026

+ +
+

+ Such Software LLC ("we," "us," or "our") operates the Bauhaus Echo mobile + application (the "App"). This page informs you of our policies regarding the collection, + use, and disclosure of personal data when you use our App. +

+ +

Information We Collect

+ +

Advertising Data

+

+ We use Google AdMob to display advertisements. AdMob may collect and use + data to show you personalized ads. This data may include: +

+
    +
  • Device identifiers (Advertising ID)
  • +
  • IP address
  • +
  • General location (country/region)
  • +
  • App usage data
  • +
+

+ For more information on how Google uses data, visit:{" "} + + How Google uses information from sites or apps that use our services + +

+

+ iOS Users: We will ask for your permission via App Tracking Transparency (ATT) + before collecting data for personalized advertising. You can deny this request and still use + the app with non-personalized ads. +

+ +

In-App Purchases

+

+ If you purchase the "Remove Ads" upgrade, your transaction is processed by Google Play (Android) + or the Apple App Store (iOS). We do not have access to your payment information. We only receive + confirmation of your purchase status. +

+ +

High Scores & Leaderboards

+

If you submit scores to our online leaderboards, we collect:

+
    +
  • Your chosen display name (anonymous by default)
  • +
  • Your game scores and statistics
  • +
  • A randomly generated anonymous player ID
  • +
+

+ We do not require or collect your real name, email, or any other personal + information to use leaderboards. +

+ +

Locally Stored Data

+

The App stores the following data locally on your device:

+
    +
  • Game progress and high scores
  • +
  • Settings preferences (sound, music, grid size)
  • +
  • Premium purchase status
  • +
+

This data is not transmitted to our servers unless you use the online leaderboard feature.

+ +

How We Use Your Information

+

We use collected data to:

+
    +
  • Display advertisements (unless you purchase "Remove Ads")
  • +
  • Process in-app purchases
  • +
  • Maintain online leaderboards
  • +
  • Improve the App experience
  • +
+ +

Third-Party Services

+

The App uses the following third-party services that may collect information:

+
    +
  • Google AdMob — Advertising
  • +
  • Google Play Services — Android platform and billing
  • +
  • Apple StoreKit — iOS platform and billing
  • +
+ +

Children's Privacy

+

+ The App is intended for general audiences and does not knowingly collect personal information + from children under 13. If you believe we have collected data from a child under 13, please + contact us immediately. +

+ +

Data Retention

+
    +
  • Advertising data is managed by Google per their retention policies
  • +
  • Leaderboard data is retained indefinitely but can be deleted upon request
  • +
  • Local data is stored on your device until you uninstall the App
  • +
+ +

Your Rights

+

You may:

+
    +
  • + Opt out of personalized ads via your device settings (Android: Settings → Google → Ads; + iOS: Settings → Privacy → Tracking) +
  • +
  • Request deletion of your leaderboard data by contacting us
  • +
  • Remove local data by uninstalling the App
  • +
+ +

Changes to This Policy

+

+ We may update this Privacy Policy from time to time. We will notify you of any changes by + posting the new Privacy Policy on this page and updating the "Last Updated" date. +

+ +

Contact Us

+

If you have any questions about this Privacy Policy, please contact us:

+

+ Such Software LLC
+ Email: apps@such.software
+ Website: https://such.software +

+ +

Consent

+

By using Bauhaus Echo, you consent to this Privacy Policy.

+
+
+ +
+ ); +} diff --git a/apps/web/src/app/products/custom-websites/page.tsx b/apps/web/src/app/products/custom-websites/page.tsx new file mode 100644 index 0000000..1e422b8 --- /dev/null +++ b/apps/web/src/app/products/custom-websites/page.tsx @@ -0,0 +1,92 @@ +import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; +import { Card } from "@repo/ui/components/card"; +import { Button } from "@repo/ui/components/button"; +import Link from "next/link"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Custom Websites | Such Software", + description: "Real-time platforms and interactive web experiences. See our work on rcryptocurrency.com and moonplace.io.", + alternates: { canonical: "/products/custom-websites" }, +}; + +export default function CustomWebsitesPage() { + return ( +
+
+
+ + ← Back to Products + + +

+ Custom Websites +

+ +
+

+ Real-time platforms, collaborative tools, and high-end brand experiences. + We build performant web applications that handle scale. +

+
+ +

Featured Projects

+ + +
+ +

Real-time Platforms

+

+ Socket.io and WebRTC integration for collaborative tools, dashboards, + and live data visualization. +

+
+ +

Brand Motion

+

+ Framer Motion and Three.js powered interfaces that tell your brand's + story through motion and depth. +

+
+
+ +
+ + + +
+
+ +
+ ); +} diff --git a/apps/web/src/app/products/page.tsx b/apps/web/src/app/products/page.tsx new file mode 100644 index 0000000..e182d9b --- /dev/null +++ b/apps/web/src/app/products/page.tsx @@ -0,0 +1,91 @@ +import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; +import { Card } from "@repo/ui/components/card"; +import Link from "next/link"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Products | Such Software", + description: "Tools and applications built by Such Software. Webshops, custom websites, Smirk Wallet, and Bauhaus Echo.", + alternates: { canonical: "/products" }, + openGraph: { + title: "Products | Such Software", + description: "Tools and applications built by Such Software.", + type: "website", + }, +}; + +const products = [ + { + slug: "webshops", + title: "Webshops", + description: "Headless Medusa commerce with revenue-share pricing. No upfront costs.", + color: "emerald", + }, + { + slug: "custom-websites", + title: "Custom Websites", + description: "Real-time platforms and interactive experiences. See rcryptocurrency.com and moonplace.io.", + color: "purple", + }, + { + slug: "smirk-wallet", + title: "Smirk Wallet", + description: "Non-custodial browser wallet for social tipping. BTC, LTC, XMR, WOW, GRIN.", + color: "amber", + }, + { + slug: "bauhaus-echo", + title: "Bauhaus Echo", + description: "Visual memory puzzle game inspired by Bauhaus design. Android, iOS, Web.", + color: "blue", + }, +]; + +const colorClasses: Record = { + emerald: "border-emerald-500/30 hover:border-emerald-500/60", + purple: "border-purple-500/30 hover:border-purple-500/60", + amber: "border-amber-500/30 hover:border-amber-500/60", + blue: "border-blue-500/30 hover:border-blue-500/60", +}; + +const titleColors: Record = { + emerald: "text-emerald-600 dark:text-emerald-400", + purple: "text-purple-600 dark:text-purple-400", + amber: "text-amber-600 dark:text-amber-400", + blue: "text-blue-600 dark:text-blue-400", +}; + +export default function ProductsPage() { + return ( +
+
+
+
+

+ Our Products +

+

+ Tools we have built, from commerce infrastructure to consumer apps. +

+
+ +
+ {products.map((product) => ( + + +

+ {product.title} +

+

+ {product.description} +

+
+ + ))} +
+
+ +
+ ); +} diff --git a/apps/web/src/app/products/smirk-wallet/page.tsx b/apps/web/src/app/products/smirk-wallet/page.tsx new file mode 100644 index 0000000..c69bbff --- /dev/null +++ b/apps/web/src/app/products/smirk-wallet/page.tsx @@ -0,0 +1,129 @@ +import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; +import { Card } from "@repo/ui/components/card"; +import { Button } from "@repo/ui/components/button"; +import Link from "next/link"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Smirk Wallet | Such Software", + description: "Non-custodial browser wallet for social tipping. Send BTC, LTC, XMR, WOW, and GRIN by Telegram or Discord username.", + alternates: { canonical: "/products/smirk-wallet" }, +}; + +const currencies = [ + { name: "Bitcoin", symbol: "BTC", type: "secp256k1" }, + { name: "Litecoin", symbol: "LTC", type: "secp256k1" }, + { name: "Monero", symbol: "XMR", type: "ed25519" }, + { name: "Wownero", symbol: "WOW", type: "ed25519" }, + { name: "Grin", symbol: "GRIN", type: "secp256k1" }, +]; + +export default function SmirkWalletPage() { + return ( +
+
+
+ + ← Back to Products + + +

+ Smirk Wallet +

+ +
+

+ Non-custodial multi-currency wallet for social tipping. + Tip anyone on Telegram or Discord by username. Your keys never leave your browser. +

+
+ + + +

Features

+
+ +

Non-Custodial

+

+ Your private keys are generated locally and encrypted with your password. + We never see your spend keys. Your funds are always yours. +

+
+ +

Social Tipping

+

+ Link your Telegram or Discord account. Anyone with Smirk can send you + crypto by username. No wallet address needed. +

+
+ +

Encrypted Tips

+

+ Tips are encrypted with the recipient's public key. Only they can claim. + Senders can reclaim unclaimed tips (no lost funds). +

+
+ +

One Seed, Five Chains

+

+ A single 12-word seed phrase derives addresses for all supported currencies. + Restore your entire wallet with one backup. +

+
+
+ +

Supported Currencies

+
+ + + + + + + + + + {currencies.map((c) => ( + + + + + + ))} + +
CurrencySymbolKey Type
{c.name}{c.symbol}{c.type}
+
+ +
+

Why These Coins?

+

+ BTC is the most widely used. LTC is fast and cheap (MWEB support coming). + XMR is the gold standard for privacy. WOW has a great community. + GRIN is lightweight, private, and has the fairest emission schedule of any coin. +

+
+ + +
+ +
+ ); +} diff --git a/apps/web/src/app/products/webshops/page.tsx b/apps/web/src/app/products/webshops/page.tsx new file mode 100644 index 0000000..1cabee5 --- /dev/null +++ b/apps/web/src/app/products/webshops/page.tsx @@ -0,0 +1,84 @@ +import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; +import { Card } from "@repo/ui/components/card"; +import { Button } from "@repo/ui/components/button"; +import Link from "next/link"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Webshops | Such Software", + description: "Headless Medusa commerce engines with revenue-share pricing. No upfront costs, aligned incentives.", + alternates: { canonical: "/products/webshops" }, +}; + +export default function WebshopsPage() { + return ( +
+
+
+ + ← Back to Products + + +

+ Webshops +

+ +
+

+ We build headless commerce platforms on Medusa v2 with a revenue-share model. + No massive setup fees, no monthly retainers. We only win when you make sales. +

+
+ +
+ +

Zero Upfront Cost

+

+ We invest our development time and infrastructure. You focus on your brand and products. + We take a small percentage of sales once you are live. +

+
+ +

Own Your Data

+

+ Unlike Shopify, you own your customer data, product catalog, and order history. + No platform lock-in, ever. +

+
+ +

Flexible Architecture

+

+ Subscriptions, bundles, B2B pricing, multi-warehouse inventory. + Model your exact business logic without platform constraints. +

+
+ +

Performance First

+

+ Next.js storefronts optimized for Core Web Vitals. 100/100 Lighthouse scores, + fast load times, high conversion rates. +

+
+
+ +
+

Tech Stack

+
    +
  • Backend: Medusa v2 (Node.js, PostgreSQL)
  • +
  • Frontend: Next.js 15, React 18, Tailwind CSS
  • +
  • Payments: Stripe, PayPal, crypto (optional)
  • +
  • Hosting: Vercel, Railway, or your infrastructure
  • +
+
+ +
+ + + +
+
+ +
+ ); +} diff --git a/apps/web/src/app/services/page.tsx b/apps/web/src/app/services/page.tsx index 3c47432..7d5e522 100644 --- a/apps/web/src/app/services/page.tsx +++ b/apps/web/src/app/services/page.tsx @@ -1,6 +1,7 @@ import { DataGrid } from "@repo/ui/procedural/data-grid"; import { Button } from "@repo/ui/components/button"; import { Header } from "@/components/layout/header"; +import { MobileNav } from "@/components/layout/mobile-nav"; import Link from "next/link"; import { Card } from "@repo/ui/components/card"; import type { Metadata } from "next"; @@ -150,7 +151,7 @@ export default function ServicesPage() {
- + ); } \ No newline at end of file diff --git a/apps/web/src/components/layout/header.tsx b/apps/web/src/components/layout/header.tsx index 47c9f4f..523d6df 100644 --- a/apps/web/src/components/layout/header.tsx +++ b/apps/web/src/components/layout/header.tsx @@ -20,12 +20,24 @@ export function Header() {