commit af6e72256997fb05a9609f62c051a3e8a4e46d94 Author: nobswebdev Date: Sat Aug 29 01:45:24 2026 +0200 init diff --git a/README.md b/README.md new file mode 100644 index 0000000..1f3a534 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# NullCart Promo Website + +Static promo landing page for [NullCart](https://git.nobswebdev.com/nobswebdev/nullcart) — HTML and CSS only, zero JavaScript. + +## Structure + +``` +index.html +css/styles.css +assets/ + logo.png # header wordmark (200×50) + favicon.png # browser tab icon + gallery/ + storefront.svg ← replace with .png when you have screenshots + checkout.svg + order.svg + cms.svg +``` + +## Configuration + +Update these values in `index.html` (search for `CONFIG` comment at top, then find/replace URLs): + +| Placeholder | Default | +|-------------|---------| +| Repository (HTTPS) | `https://git.nobswebdev.com/nobswebdev/nullcart` | +| Repository (onion) | `http://4f5t7o2vgo4sdaliwax3isyxzfuxvbvkuwk4smfowutrvx2uneu4egyd.onion/nobswebdev/nullcart` | +| Live demo (HTTPS) | `https://demo.nullcart.net/` | +| Live demo (onion) | `http://3jh2ltksxtsmjidik3st6dawfdcheo2cyv2vth2365af75zdxnwqqsyd.onion/` | +| Email | `contact@nullcart.net` | +| SimpleX | `https://simplex.chat/contact#YOUR_HANDLE` | + +## Deploy to shared hosting (e.g. Servers Guru) + +1. Upload all files to your site's document root (`httpdocs` / `public_html` in Plesk). +2. Ensure `index.html` is at the root. +3. Enable Let's Encrypt SSL in your hosting panel. +4. Visit your domain. + +No build step, no server-side runtime required. + +## Deploy elsewhere + +- **nginx:** serve the folder as static files; optional strict CSP header: + ``` + Content-Security-Policy: default-src 'none'; style-src 'self'; img-src 'self'; base-uri 'self' + ``` +- **Cloudflare Pages / static host:** upload or push files, set publish directory to project root. +- **Tor mirror:** same static files behind a hidden service (optional). + +## Screenshot checklist + +When your NullCart instance is running, capture and replace gallery placeholders: + +1. **Storefront** — product catalog / home page +2. **Checkout** — cart checkout with XMR QR code +3. **Order page** — order status with encrypted chat visible +4. **CMS** — orders list or wallet dashboard + +Save as `assets/gallery/storefront.png` (etc.) and update `src` in `index.html`, or keep `.svg` placeholders until ready. + +## Local preview + +```bash +cd nullcart_promo_website +python3 -m http.server 8080 +``` + +Open http://localhost:8080 diff --git a/assets/favicon.png b/assets/favicon.png new file mode 100644 index 0000000..cf8a27d Binary files /dev/null and b/assets/favicon.png differ diff --git a/assets/gallery/checkout.png b/assets/gallery/checkout.png new file mode 100644 index 0000000..871f3b2 Binary files /dev/null and b/assets/gallery/checkout.png differ diff --git a/assets/gallery/cms.png b/assets/gallery/cms.png new file mode 100644 index 0000000..be48020 Binary files /dev/null and b/assets/gallery/cms.png differ diff --git a/assets/gallery/order.png b/assets/gallery/order.png new file mode 100644 index 0000000..afb6236 Binary files /dev/null and b/assets/gallery/order.png differ diff --git a/assets/gallery/storefront.png b/assets/gallery/storefront.png new file mode 100644 index 0000000..ee8fb64 Binary files /dev/null and b/assets/gallery/storefront.png differ diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..c2bdf45 Binary files /dev/null and b/assets/logo.png differ diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000..1f25bf1 --- /dev/null +++ b/css/styles.css @@ -0,0 +1,794 @@ + +:root { + --brand: #f78f1e; + --brand-deep: #d96f12; + --brand-light: #ffc87a; + --accent: #009ada; + --accent-light: #4db8e8; + --bg: #000000; + --surface: #0d0d0d; + --surface-raised: #141414; + --border: #262626; + --text: #f0f0f0; + --muted: #8b9298; + --max-width: 72rem; + --header-height: 5rem; + --radius: 0.5rem; + --radius-lg: 0.75rem; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } +} + +body { + margin: 0; + font-family: system-ui, -apple-system, "Segoe UI", sans-serif; + font-size: 1rem; + line-height: 1.6; + color: var(--text); + background-color: var(--bg); + -webkit-font-smoothing: antialiased; +} + +img, +svg { + display: block; + max-width: 100%; +} + +a { + color: var(--accent); + text-decoration: none; +} + +a:hover { + color: var(--accent-light); +} + +:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.container { + width: min(100% - 2rem, var(--max-width)); + margin-inline: auto; +} + + +.site-notice { + padding-block: 0.375rem; + text-align: center; + font-size: 0.75rem; + color: var(--muted); + background: var(--surface); + border-bottom: 1px solid var(--border); +} + +.site-notice p { + margin: 0; +} + +.site-header { + position: sticky; + top: 0; + z-index: 100; + min-height: var(--header-height); + background: rgba(0, 0, 0, 0.92); + border-bottom: 1px solid var(--border); + backdrop-filter: blur(8px); +} + +.site-header__inner { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 1rem; + min-height: var(--header-height); + padding-block: 0.75rem; +} + +.logo { + display: flex; + align-items: center; + flex-shrink: 0; +} + +.logo:hover { + opacity: 0.92; +} + +.logo__img { + display: block; + width: 200px; + height: 50px; + max-width: none; + object-fit: contain; +} + +.site-nav { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.5rem 1.25rem; +} + +.site-nav a { + color: var(--muted); + font-size: 0.9375rem; +} + +.site-nav a:hover { + color: var(--text); +} + + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.625rem 1.25rem; + border: 1px solid transparent; + border-radius: var(--radius); + font-size: 0.9375rem; + font-weight: 600; + line-height: 1.4; + cursor: pointer; + transition: background 0.15s, border-color 0.15s, color 0.15s; +} + +.btn--primary { + color: #fff; + background: var(--brand); + border-color: var(--brand); +} + +.btn--primary:hover { + color: #fff; + background: var(--brand-deep); + border-color: var(--brand-deep); +} + +.btn--ghost { + color: var(--text); + background: transparent; + border-color: var(--border); +} + +.btn--ghost:hover { + color: var(--text); + border-color: var(--muted); + background: var(--surface); +} + + +.hero { + position: relative; + padding-block: clamp(3rem, 8vw, 6rem); + overflow: hidden; +} + +.hero::before { + content: ""; + position: absolute; + inset: 0; + background: + radial-gradient(ellipse 80% 60% at 50% -20%, rgba(247, 143, 30, 0.18), transparent), + radial-gradient(ellipse 50% 40% at 100% 50%, rgba(0, 154, 218, 0.1), transparent); + pointer-events: none; +} + +.hero__watermark { + position: absolute; + right: 12%; + top: 50%; + transform: translateY(-50%); + width: min(18rem, 40vw); + height: auto; + opacity: 0.06; + pointer-events: none; +} + +.hero__content { + position: relative; + max-width: 42rem; +} + +.hero__badge { + display: inline-block; + margin: 0 0 0.75rem; + padding: 0.375rem 0.75rem; + border: 1px solid rgba(247, 143, 30, 0.5); + border-radius: 999px; + background: rgba(247, 143, 30, 0.12); + color: var(--brand-light); + font-size: 0.8125rem; + font-weight: 600; + letter-spacing: 0.02em; + text-transform: uppercase; +} + +.hero h1 { + margin: 0 0 1.25rem; + font-size: clamp(2rem, 5vw, 3rem); + font-weight: 700; + line-height: 1.15; + letter-spacing: -0.03em; +} + +.hero__highlights { + display: flex; + flex-wrap: wrap; + gap: 0.5rem 0.75rem; + margin: 0 0 1.25rem; + padding: 0; + list-style: none; +} + +.hero__highlights li { + padding: 0.375rem 0.75rem; + border: 1px solid var(--border); + border-radius: var(--radius); + background: var(--surface); + font-size: 0.875rem; + font-weight: 500; + color: var(--text); +} + +.hero__highlights li:nth-child(odd) { + border-color: rgba(247, 143, 30, 0.35); +} + +.hero__highlights li:nth-child(even) { + border-color: rgba(0, 154, 218, 0.35); +} + +.hero__sub { + margin: 0 0 2rem; + font-size: clamp(1rem, 2vw, 1.125rem); + color: var(--muted); + line-height: 1.7; +} + +.hero__actions { + display: flex; + flex-wrap: wrap; + align-items: flex-end; + gap: 1rem 1.25rem; +} + +.link-group { + display: flex; + flex-direction: column; + gap: 0.375rem; +} + +.link-group__label { + font-size: 0.75rem; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--muted); +} + +.repo-links { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} + +.repo-links--center { + justify-content: center; +} + + +.section { + padding-block: clamp(3rem, 6vw, 5rem); +} + +.section--border { + border-top: 1px solid var(--border); +} + +.section__title { + margin: 0 0 0.5rem; + font-size: clamp(1.5rem, 3vw, 2rem); + font-weight: 700; + letter-spacing: -0.02em; +} + +.section__lead { + margin: 0 0 2rem; + max-width: 36rem; + color: var(--muted); +} + + +.about p { + margin: 0 0 1rem; + max-width: 42rem; + color: var(--muted); +} + +.about p:last-child { + margin-bottom: 0; +} + + +.pillars { + display: flex; + flex-wrap: wrap; + gap: 0.625rem; + margin: 0; + padding: 0; + list-style: none; +} + +.privacy-features { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(11.5rem, 1fr)); + gap: 0.625rem; +} + +.pillar { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.5rem 0.875rem; + border: 1px solid var(--border); + border-radius: 999px; + background: var(--surface); + font-size: 0.8125rem; + font-weight: 500; + color: var(--text); + white-space: nowrap; +} + +.pillar__dot { + width: 0.375rem; + height: 0.375rem; + border-radius: 50%; + flex-shrink: 0; +} + +.pillar:nth-child(odd) .pillar__dot { + background: var(--brand); +} + +.pillar:nth-child(even) .pillar__dot { + background: var(--accent); +} + + +.features-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.25rem; +} + +@media (max-width: 48rem) { + .features-grid { + grid-template-columns: 1fr; + } +} + +.feature-card { + padding: 1.5rem; + border: 1px solid var(--border); + border-radius: var(--radius-lg); + background: var(--surface); +} + +.feature-card--lead { + border-color: rgba(247, 143, 30, 0.4); + background: linear-gradient(135deg, rgba(247, 143, 30, 0.08), rgba(0, 154, 218, 0.05), var(--surface)); +} + +.feature-card__icon { + width: 2rem; + height: 2rem; + margin-bottom: 1rem; + color: var(--accent); +} + +.feature-card--lead .feature-card__icon { + color: var(--brand); +} + +.feature-card h3 { + margin: 0 0 0.5rem; + font-size: 1.125rem; + font-weight: 600; +} + +.feature-card__lead { + margin: 0 0 1rem; + font-size: 0.9375rem; + color: var(--muted); +} + +.feature-card ul { + margin: 0; + padding-left: 1.125rem; + font-size: 0.9375rem; + color: var(--muted); +} + +.feature-card li + li { + margin-top: 0.375rem; +} + + +.steps { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1.25rem; + margin: 0; + padding: 0; + list-style: none; + counter-reset: step; +} + +@media (max-width: 48rem) { + .steps { + grid-template-columns: 1fr; + } +} + +.step { + padding: 1.5rem; + border: 1px solid var(--border); + border-radius: var(--radius-lg); + background: var(--surface); +} + +.step::before { + counter-increment: step; + content: counter(step); + display: flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + margin-bottom: 1rem; + border-radius: 50%; + background: var(--brand); + color: #fff; + font-size: 0.875rem; + font-weight: 700; +} + +.step h3 { + margin: 0 0 0.5rem; + font-size: 1rem; + font-weight: 600; +} + +.step p { + margin: 0; + font-size: 0.9375rem; + color: var(--muted); +} + + +.roadmap { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1.25rem; + margin: 0; + padding: 0; + list-style: none; +} + +@media (max-width: 48rem) { + .roadmap { + grid-template-columns: 1fr; + } +} + +.roadmap__item { + padding: 1.5rem; + border: 1px solid var(--border); + border-radius: var(--radius-lg); + background: var(--surface); +} + +.roadmap__item h3 { + margin: 0 0 0.5rem; + font-size: 1rem; + font-weight: 600; + color: var(--brand); +} + +.roadmap__item p { + margin: 0; + font-size: 0.9375rem; + color: var(--muted); +} + + +.gallery { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.25rem; +} + +@media (max-width: 40rem) { + .gallery { + grid-template-columns: 1fr; + } +} + +.gallery__item { + margin: 0; +} + +.gallery__link { + display: block; + color: inherit; + cursor: zoom-in; +} + +.gallery__link:hover { + color: inherit; +} + +.gallery__link:hover .gallery__frame { + border-color: var(--accent); +} + +.gallery__frame { + aspect-ratio: 16 / 10; + border: 1px solid var(--border); + border-radius: var(--radius-lg); + background: var(--surface-raised); + overflow: hidden; +} + +.gallery__frame img { + width: 100%; + height: 100%; + object-fit: contain; +} + +.gallery__caption { + margin-top: 0.625rem; + font-size: 0.875rem; + color: var(--muted); + text-align: center; +} + +body:has(.lightbox:target) { + overflow: hidden; +} + +.lightbox { + display: none; + position: fixed; + inset: 0; + z-index: 200; + align-items: center; + justify-content: center; + padding: 1.5rem; +} + +.lightbox:target { + display: flex; +} + +.lightbox__backdrop { + position: absolute; + inset: 0; + background: rgba(0, 0, 0, 0.92); +} + +.lightbox__img { + position: relative; + z-index: 1; + max-width: min(95vw, 75rem); + max-height: 90vh; + width: auto; + height: auto; + object-fit: contain; + border: 1px solid var(--border); + border-radius: var(--radius-lg); +} + +.lightbox__close { + position: absolute; + top: 1rem; + right: 1rem; + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + width: 2.5rem; + height: 2.5rem; + font-size: 1.75rem; + line-height: 1; + color: var(--text); + background: var(--surface-raised); + border: 1px solid var(--border); + border-radius: var(--radius); +} + +.lightbox__close:hover { + color: var(--text); + border-color: var(--accent); +} + + +.cta-block { + text-align: center; + padding: 2.5rem 1.5rem; + border: 1px solid var(--border); + border-radius: var(--radius-lg); + background: var(--surface); +} + +.cta-block h2 { + margin: 0 0 0.5rem; + font-size: clamp(1.5rem, 3vw, 2rem); +} + +.cta-block p { + margin: 0 0 1.5rem; + color: var(--muted); +} + +.cta-block .repo-links { + margin-bottom: 1rem; +} + +.cta-block__note { + margin-top: 1rem; + margin-bottom: 0; + font-size: 0.875rem; +} + + +.contact-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.25rem; + max-width: 36rem; +} + +@media (max-width: 32rem) { + .contact-grid { + grid-template-columns: 1fr; + } +} + +.contact-card { + padding: 1.25rem 1.5rem; + border: 1px solid var(--border); + border-radius: var(--radius-lg); + background: var(--surface); +} + +.contact-card h3 { + margin: 0 0 0.375rem; + font-size: 0.875rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--muted); +} + +.contact-card a { + font-size: 1rem; + font-weight: 500; + word-break: break-all; +} + +.contact__note { + margin-top: 1.5rem; + font-size: 0.875rem; + color: var(--muted); +} + + +.site-footer { + padding-block: 2rem 2.5rem; + border-top: 1px solid var(--border); +} + +.site-footer__inner { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 1rem; +} + +.site-footer__nav { + display: flex; + flex-wrap: wrap; + gap: 0.5rem 1.25rem; +} + +.site-footer__nav a { + font-size: 0.875rem; + color: var(--muted); +} + +.site-footer__nav a:hover { + color: var(--text); +} + +.site-footer__copy { + margin: 0; + font-size: 0.8125rem; + color: var(--muted); +} + +.site-footer__disclaimer { + width: 100%; + margin: 1rem 0 0; + font-size: 0.75rem; + color: var(--muted); + opacity: 0.8; +} + +.site-footer__repo { + width: 100%; + margin: 0.75rem 0 0; + font-size: 0.8125rem; + line-height: 1.5; + word-break: break-all; +} + +.site-footer__links { + width: 100%; + margin-top: 0.75rem; +} + +.site-footer__links-row { + margin: 0 0 0.375rem; + font-size: 0.8125rem; + line-height: 1.6; + word-break: break-all; +} + +.site-footer__links-row:last-child { + margin-bottom: 0; +} + +.site-footer__links-label { + display: inline-block; + min-width: 5.5rem; + margin-right: 0.5rem; + font-weight: 600; + color: var(--muted); +} + +.site-footer__links a, +.site-footer__repo a { + color: var(--muted); +} + +.site-footer__links a:hover, +.site-footer__repo a:hover { + color: var(--accent-light); +} + +.site-footer__repo-sep { + margin-inline: 0.375rem; + color: var(--muted); + opacity: 0.6; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..3bc1e27 --- /dev/null +++ b/index.html @@ -0,0 +1,675 @@ + + + + + + + NullCart — Free self-hosted Monero shop + + + + + + +
+
+
+ +
+

Free & open source

+

Self-hosted Monero shop

+
    +
  • Non-custodial
  • +
  • No JS
  • +
  • No accounts
  • +
  • Clearnet & Tor onion
  • +
+

+ Complete crypto e-commerce solution, with no third parties + involved. Built with a mission to support the crypto economy. +

+
+ + + See features +
+
+
+
+ +
+
+

What is NullCart?

+

+ NullCart is an open-source, self-hosted shop for accepting Monero. + Run it on your server with a non-custodial wallet, and sell on + clearnet and Tor. +

+

+ Built for the Monero community — designed for a maximum privacy + experience and full control over funds and infrastructure. Lower the + barrier to selling with XMR and help grow the circular crypto + economy. +

+
+
+ +
+
+

Privacy features

+

+ Built for the Monero community — privacy at every layer of the buyer + experience. +

+
    +
  • + Free and open + source +
  • +
  • + No JS on + buyer shop +
  • +
  • + No buyer + accounts +
  • +
  • + Non-custodial + wallet +
  • +
  • + XMR-only + payments +
  • +
  • + Zero + third-party processors +
  • +
  • + Own wallet + integration +
  • +
  • + Encrypted + sensitive data +
  • +
  • + Auto order + data wipe +
  • +
  • + Self-hosted + clearnet + onion +
  • +
  • + SimpleX + merchant alerts +
  • +
+
+
+ +
+
+

Features

+

+ Everything you need to sell digital and physical goods with Monero. +

+
+
+ +

Privacy by design

+

+ Your buyers don't need accounts. Your shop doesn't hoard their + data. +

+
    +
  • + No JavaScript needed — the buyer shop runs without client-side + scripts +
  • +
  • Works perfectly in Tor Browser strictest security mode
  • +
  • + No sign-up, no profiles — orders opened with a private access + token +
  • +
+
+ +
+ +

Monero-native payments

+

+ Built-in Monero integration. Zero third-party payment services. +

+
    +
  • + Direct XMR payments to your own wallet — no custodial gateway +
  • +
  • + Per-order addresses with QR codes; live rates, fiat display +
  • +
  • You hold the seed — funds never touch a middleman
  • +
+
+ +
+ +

E-commerce features

+

+ A full storefront for digital and physical goods — catalog, + cart, checkout, and fulfillment. +

+
    +
  • + Product catalog, categories, and variants with image galleries +
  • +
  • Shopping cart, checkout, and discount codes
  • +
  • + Auto-deliver digital goods; quote and collect shipping for + physical orders +
  • +
  • + Order tracking, live payment status, and per-order buyer chat +
  • +
  • Custom branding — your logo, favicon, and shop name
  • +
  • + Prices shown in fiat, paid in Monero with live exchange rates +
  • +
+
+ +
+ +

Self-hosted and yours

+

+ Deploy on your VPS. Serve buyers on clearnet and Tor. +

+
    +
  • Step-by-step deployment guide in the repository
  • +
  • Docker Compose setup with HTTPS and onion address
  • +
  • + Merchant CMS for products, orders, wallet, and notifications +
  • +
  • SimpleX bot alerts you on new orders and messages
  • +
+
+
+
+
+ +
+
+

How it works

+

+ Three steps from zero to selling with Monero. +

+
    +
  1. +

    Deploy

    +

    + Clone the repo, configure your server, and go live on HTTPS and + Tor. +

    +
  2. +
  3. +

    Set up your shop

    +

    Add products in the CMS and upload your branding.

    +
  4. +
  5. +

    Sell

    +

    + Buyers pay in XMR; you fulfill orders, chat when needed, get + notified via SimpleX. +

    +
  6. +
+
+
+ + + +
+
+
+

Live demo

+

+ Try a running NullCart shop — browse products, cart, and checkout + flow. Test payments with stagenet Monero. +

+ +
+
+
+ +
+
+
+

Open source

+

Inspect the code, run it yourself, no vendor lock-in.

+ +

Deployment guide in the repo.

+
+
+
+ +
+
+

Roadmap

+

What's planned next for NullCart.

+
    +
  • +

    NullCart directory

    +

    + A central website that lists all instances, with an advanced + rating system and space for the community. +

    +
  • +
  • +

    More privacy coins

    +

    + Support for additional privacy-focused cryptocurrencies beyond + Monero. +

    +
  • +
  • +

    More e-commerce features

    +

    Expanded storefront, checkout, and merchant tools.

    +
  • +
+
+
+ +
+
+

Contact

+

+ Questions, feedback, or collaboration — reach out. +

+
+
+

Email

+ nobswebdev@pm.me +
+
+

SimpleX

+ Contact via SimpleX +
+
+
+
+
+ + + +