diff --git a/frontend/components/AppSwitcher.tsx b/frontend/components/AppSwitcher.tsx index 65a115d..24f2dcc 100644 --- a/frontend/components/AppSwitcher.tsx +++ b/frontend/components/AppSwitcher.tsx @@ -17,6 +17,8 @@ const MODULES: AppModule[] = [ { id: 'space', name: 'rSpace', badge: 'rS', color: 'bg-teal-300', emoji: '🎨', description: 'Real-time collaborative canvas', domain: 'rspace.online' }, { id: 'notes', name: 'rNotes', badge: 'rN', color: 'bg-amber-300', emoji: 'πŸ“', description: 'Group note-taking & knowledge capture', domain: 'rnotes.online' }, { id: 'pubs', name: 'rPubs', badge: 'rP', color: 'bg-rose-300', emoji: 'πŸ“–', description: 'Collaborative publishing platform', domain: 'rpubs.online' }, + { id: 'tube', name: 'rTube', badge: 'rTu', color: 'bg-pink-300', emoji: '🎬', description: 'Community video platform', domain: 'rtube.online' }, + { id: 'swag', name: 'rSwag', badge: 'rSw', color: 'bg-red-200', emoji: 'πŸ‘•', description: 'Community merch & swag store', domain: 'rswag.online' }, // Planning { id: 'cal', name: 'rCal', badge: 'rC', color: 'bg-sky-300', emoji: 'πŸ“…', description: 'Collaborative scheduling & events', domain: 'rcal.online' }, { id: 'trips', name: 'rTrips', badge: 'rT', color: 'bg-emerald-300', emoji: '✈️', description: 'Group travel planning in real time', domain: 'rtrips.online' }, @@ -34,13 +36,12 @@ const MODULES: AppModule[] = [ { id: 'wallet', name: 'rWallet', badge: 'rW', color: 'bg-yellow-300', emoji: 'πŸ’°', description: 'Multi-chain crypto wallet', domain: 'rwallet.online' }, { id: 'cart', name: 'rCart', badge: 'rCt', color: 'bg-orange-300', emoji: 'πŸ›’', description: 'Group commerce & shared shopping', domain: 'rcart.online' }, { id: 'auctions', name: 'rAuctions', badge: 'rA', color: 'bg-red-300', emoji: 'πŸ”¨', description: 'Live auction platform', domain: 'rauctions.online' }, - { id: 'swag', name: 'rSwag', badge: 'rSw', color: 'bg-red-200', emoji: 'πŸ‘•', description: 'Community merch & swag store', domain: 'rswag.online' }, - // Social & Media - { id: 'photos', name: 'rPhotos', badge: 'rPh', color: 'bg-pink-200', emoji: 'πŸ“Έ', description: 'Shared community photo albums', domain: 'rphotos.online' }, - { id: 'tube', name: 'rTube', badge: 'rTu', color: 'bg-pink-300', emoji: '🎬', description: 'Group video platform', domain: 'rtube.online' }, + // Sharing + { id: 'photos', name: 'rPhotos', badge: 'rPh', color: 'bg-pink-200', emoji: 'πŸ“Έ', description: 'Community photo commons', domain: 'rphotos.online' }, { id: 'network', name: 'rNetwork', badge: 'rNe', color: 'bg-blue-300', emoji: 'πŸ•ΈοΈ', description: 'Community network & social graph', domain: 'rnetwork.online' }, - { id: 'socials', name: 'rSocials', badge: 'rSo', color: 'bg-sky-200', emoji: 'πŸ“’', description: 'Social media management', domain: 'rsocials.online' }, { id: 'files', name: 'rFiles', badge: 'rFi', color: 'bg-cyan-300', emoji: 'πŸ“', description: 'Collaborative file storage', domain: 'rfiles.online' }, + { id: 'socials', name: 'rSocials', badge: 'rSo', color: 'bg-sky-200', emoji: 'πŸ“’', description: 'Social media management', domain: 'rsocials.online' }, + // Observing { id: 'data', name: 'rData', badge: 'rD', color: 'bg-purple-300', emoji: 'πŸ“Š', description: 'Analytics & insights dashboard', domain: 'rdata.online' }, // Work & Productivity { id: 'work', name: 'rWork', badge: 'rWo', color: 'bg-slate-300', emoji: 'πŸ“‹', description: 'Project & task management', domain: 'rwork.online' }, @@ -53,6 +54,8 @@ const MODULE_CATEGORIES: Record = { space: 'Creating', notes: 'Creating', pubs: 'Creating', + tube: 'Creating', + swag: 'Creating', cal: 'Planning', trips: 'Planning', maps: 'Planning', @@ -66,13 +69,11 @@ const MODULE_CATEGORIES: Record = { wallet: 'Funding & Commerce', cart: 'Funding & Commerce', auctions: 'Funding & Commerce', - swag: 'Funding & Commerce', - photos: 'Social & Media', - tube: 'Social & Media', - network: 'Social & Media', - socials: 'Social & Media', - files: 'Social & Media', - data: 'Social & Media', + photos: 'Sharing', + network: 'Sharing', + files: 'Sharing', + socials: 'Sharing', + data: 'Observing', work: 'Work & Productivity', ids: 'Identity & Infrastructure', stack: 'Identity & Infrastructure', @@ -84,7 +85,8 @@ const CATEGORY_ORDER = [ 'Communicating', 'Deciding', 'Funding & Commerce', - 'Social & Media', + 'Sharing', + 'Observing', 'Work & Productivity', 'Identity & Infrastructure', ]; diff --git a/frontend/components/EcosystemFooter.tsx b/frontend/components/EcosystemFooter.tsx index ac513c6..4228ed1 100644 --- a/frontend/components/EcosystemFooter.tsx +++ b/frontend/components/EcosystemFooter.tsx @@ -1,30 +1,39 @@ 'use client'; const FOOTER_LINKS = [ + // Creating { name: 'rSpace', href: 'https://rspace.online' }, { name: 'rNotes', href: 'https://rnotes.online' }, { name: 'rPubs', href: 'https://rpubs.online' }, + { name: 'rTube', href: 'https://rtube.online' }, + { name: 'rSwag', href: 'https://rswag.online' }, + // Planning { name: 'rCal', href: 'https://rcal.online' }, { name: 'rTrips', href: 'https://rtrips.online' }, { name: 'rMaps', href: 'https://rmaps.online' }, + // Communicating { name: 'rChats', href: 'https://rchats.online' }, { name: 'rInbox', href: 'https://rinbox.online' }, { name: 'rMail', href: 'https://rmail.online' }, { name: 'rForum', href: 'https://rforum.online' }, + // Deciding { name: 'rChoices', href: 'https://rchoices.online' }, { name: 'rVote', href: 'https://rvote.online' }, + // Funding & Commerce { name: 'rFunds', href: 'https://rfunds.online' }, { name: 'rWallet', href: 'https://rwallet.online' }, { name: 'rCart', href: 'https://rcart.online' }, { name: 'rAuctions', href: 'https://rauctions.online' }, - { name: 'rSwag', href: 'https://rswag.online' }, + // Sharing { name: 'rPhotos', href: 'https://rphotos.online' }, - { name: 'rTube', href: 'https://rtube.online' }, { name: 'rNetwork', href: 'https://rnetwork.online' }, - { name: 'rSocials', href: 'https://rsocials.online' }, { name: 'rFiles', href: 'https://rfiles.online' }, + { name: 'rSocials', href: 'https://rsocials.online' }, + // Observing { name: 'rData', href: 'https://rdata.online' }, + // Work & Productivity { name: 'rWork', href: 'https://rwork.online' }, + // Identity & Infrastructure { name: 'rIDs', href: 'https://ridentity.online' }, { name: 'rStack', href: 'https://rstack.online' }, ]; diff --git a/landing/.dockerignore b/landing/.dockerignore new file mode 100644 index 0000000..ea94948 --- /dev/null +++ b/landing/.dockerignore @@ -0,0 +1,21 @@ +node_modules +.git +.gitignore +*.md +.env* +Dockerfile +docker-compose*.yml +.dockerignore +backlog +.next +out +.cache +dist +build +coverage +.github +.vscode +.idea +__pycache__ +*.pyc +.pytest_cache diff --git a/landing/Dockerfile b/landing/Dockerfile new file mode 100644 index 0000000..e11a8e9 --- /dev/null +++ b/landing/Dockerfile @@ -0,0 +1,4 @@ +FROM nginx:alpine +COPY index.html /usr/share/nginx/html/index.html +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 diff --git a/landing/docker-compose.yml b/landing/docker-compose.yml new file mode 100644 index 0000000..b437cfc --- /dev/null +++ b/landing/docker-compose.yml @@ -0,0 +1,20 @@ +services: + rswag: + build: . + restart: unless-stopped + labels: + - "traefik.enable=true" + - "traefik.http.routers.rswag.rule=Host(`rswag.online`) || Host(`www.rswag.online`) || HostRegexp(`{subdomain:[a-z0-9-]+}.rswag.online`)" + - "traefik.http.services.rswag.loadbalancer.server.port=80" + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:80/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 15s + networks: + - traefik-public + +networks: + traefik-public: + external: true diff --git a/landing/index.html b/landing/index.html new file mode 100644 index 0000000..b07352f --- /dev/null +++ b/landing/index.html @@ -0,0 +1,828 @@ + + + + + + + rSwag β€” Community Merch & Swag + + + + + + + + + + +
+ Part of the r* Ecosystem +

Community Merch & Swag

+

+ Design and sell custom merchandise for your community. + T-shirts, stickers, mugs — all integrated with r* spaces. +

+

+ rSwag makes it easy for communities to create, sell, and distribute branded merchandise. + From custom t-shirt designs to sticker packs and mugs, everything is print-on-demand + with no upfront inventory. Revenue flows directly to community treasuries through rFunds. +

+ +
+ + +
+
+

Wear your community

+

+ Merch that builds belonging and funds community projects. +

+
+
+
🎨
+

Custom Designs

+

Upload artwork, use the built-in design editor, or generate designs with AI. Create product mockups and preview them before publishing to your storefront.

+
+
+
🚚
+

Print on Demand

+

No inventory, no upfront costs. Products are printed and shipped when ordered. Support for t-shirts, hoodies, mugs, stickers, tote bags, and more.

+
+
+
🏪
+

Community Storefronts

+

Each r* space gets its own branded storefront. Members can browse, buy, and even submit design proposals. Revenue goes straight to the community treasury.

+
+
+
+
+ + +
+
+

How it works

+
+
+
1
+
+

Design your merch

+

Upload logos and artwork or create designs in the editor. Apply them to products, preview mockups, and set pricing with community-controlled margins.

+
+
+
+
2
+
+

Open your storefront

+

Publish products to your community's branded store. Share links, embed product cards in rSpace, and let members browse and purchase.

+
+
+
+
3
+
+

Ship and earn

+

Orders are fulfilled automatically through print-on-demand partners. Revenue flows to the community treasury via rFunds. Track sales in rData.

+
+
+
+
+
+ + + + + + + + diff --git a/landing/nginx.conf b/landing/nginx.conf new file mode 100644 index 0000000..28dfc83 --- /dev/null +++ b/landing/nginx.conf @@ -0,0 +1,21 @@ +server { + listen 80; + server_name rswag.online www.rswag.online; + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + # Cache static assets + location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2?)$ { + expires 7d; + add_header Cache-Control "public, immutable"; + } + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; +}