diff --git a/modules/rcal/landing.ts b/modules/rcal/landing.ts index 055ad54..1d78965 100644 --- a/modules/rcal/landing.ts +++ b/modules/rcal/landing.ts @@ -1,30 +1,22 @@ /** * rCal landing page — relational calendar. - * Ported from rcal-online Next.js page.tsx (318 lines). */ export function renderLanding(): string { return `
- - Relational Calendar - -

- Time is shared. Your calendar should be too. -

+ rCal +

Time is shared. Your calendar should be too.

A collaborative calendar for communities, cooperatives, and coordinated groups.

- rCal rethinks the calendar as a shared, spatial, and cyclical tool. + rCal rethinks the calendar as a shared, spatial, and cyclical tool. See events across time and place, overlay lunar cycles, zoom from a single hour to a whole decade, and keep everyone on the same page — without the back-and-forth.

- - Try the Demo - + Try the Demo Learn More

@@ -38,31 +30,23 @@ export function renderLanding(): string {

-
-
- 🤝 -
+
+
🤝

Shared by Default

One calendar for the whole group. Everyone sees the same context — no more fragmented schedules.

-
-
- 🗺 -
+
+
🗺

Spatiotemporal

Events have a where, not just a when. See your schedule on a map and a timeline simultaneously.

-
-
- 🌙 -
+
+
🌙

Natural Cycles

Lunar phases, eclipses, and solstices built in. Reconnect your planning to the rhythms of the natural world.

-
-
- 🔭 -
+
+
🔭

Multi-Scale Zoom

Ten levels of time — from a 30-second moment to a cosmic era. See today or plan a decade ahead.

@@ -73,44 +57,40 @@ export function renderLanding(): string {
- - Why rCal? - -

- Calendars were never meant to be personal silos -

+ Why rCal? +

Calendars were never meant to be personal silos

- Mainstream calendars treat time as private property. rCal treats it as a commons — + Mainstream calendars treat time as private property. rCal treats it as a commons — something groups navigate together. Here’s what makes it different.

-
-
📍
+
+
📍

Where + When, Together

Every event lives on both a timeline and a map. rCal’s split view lets you see where everyone is meeting and when — with nine spatial zoom levels from planet to street address.

-
-
🔗
+
+
🔗

Coupled Zoom

Lock temporal and spatial zoom together: zoom out in time and the map zooms out to match. Planning a week? See the city. Planning a decade? See the continent.

-
-
📡
+
+
📡

Multi-Source Sync

Import from Google, Outlook, Apple, CalDAV, ICS feeds, and Obsidian. Layer multiple sources with per-source color coding and visibility controls.

-
-
🌑
+
+
🌑

Lunar Overlay

Eight moon phases rendered on every calendar view with illumination percentages and eclipse detection. Plan gatherings, gardens, and ceremonies around natural cycles.

-
-
🧩
+
+
🧩

r* Ecosystem Embeds

rTrips, rMaps, rNetwork, rCart, and rNotes can all embed a calendar view through the context API. One calendar, surfaced everywhere it’s needed.

-
-
🏠
+
+
🏠

Self-Hosted & Sovereign

Open source and Dockerized. Your events live on your infrastructure — not in a corporate cloud. Full data sovereignty with rIDs authentication.

@@ -121,12 +101,8 @@ export function renderLanding(): string {
- - Temporal Navigation - -

- Ten levels of time -

+ Temporal Navigation +

Ten levels of time

Most calendars show you a month. rCal lets you zoom from a single moment to a cosmic era — each level revealing a different kind of pattern. @@ -211,12 +187,8 @@ export function renderLanding(): string {

- - Four Views - -

- One calendar, four perspectives -

+ Four Views +

One calendar, four perspectives

Switch between views with keyboard shortcuts (1–4) to see your events from the angle that matters most right now.

@@ -276,52 +248,48 @@ export function renderLanding(): string {
- - Ecosystem - -

- Part of the r* stack -

+ Ecosystem +

Part of the r* stack

rCal connects to the full suite of community tools. Any r* app can display or create calendar events through the shared context API.

-
+
🗺

rTrips

Trip itineraries auto-populate with calendar events for departure, accommodation, and activities.

-
+
📍

rMaps

Location-tagged events appear on shared community maps with time-filtered layers.

-
+
👥

rNetwork

See when your community members are available and schedule group meetings.

-
+
🛒

rCart

Product launches, market days, and delivery windows sync to your calendar.

-
+
📝

rNotes

Meeting notes link back to calendar events. Transcriptions attach to the moment they happened.

-
+
🌐

rSpace

@@ -335,19 +303,14 @@ export function renderLanding(): string {
-

- See time differently -

+

See time differently

Try the spatiotemporal calendar with lunar overlays, multi-source sync, and community sharing. No account needed for the demo.

diff --git a/modules/rcal/mod.ts b/modules/rcal/mod.ts index fb627b0..3570782 100644 --- a/modules/rcal/mod.ts +++ b/modules/rcal/mod.ts @@ -1086,7 +1086,7 @@ export const calModule: RSpaceModule = { scoping: { defaultScope: 'global', userConfigurable: true }, docSchemas: [{ pattern: '{space}:cal:events', description: 'Calendar events and sources', init: calendarSchema.init }], routes, - standaloneDomain: "rcal.online", + standaloneDomain: "rspace.online", landingPage: renderLanding, seedTemplate: seedDemoIfEmpty, async onInit(ctx) { diff --git a/modules/rpubs/landing.ts b/modules/rpubs/landing.ts index f33808e..1bf8993 100644 --- a/modules/rpubs/landing.ts +++ b/modules/rpubs/landing.ts @@ -227,7 +227,7 @@ export function renderLanding(): string { 3

- Order is placed with the nearest print shop via rCart + Order is placed with the nearest print shop via rCart

@@ -443,7 +443,7 @@ export function renderLanding(): string { Fund a Title - + Browse on rCart diff --git a/server/shell.ts b/server/shell.ts index d6ec5c2..6b2e6e1 100644 --- a/server/shell.ts +++ b/server/shell.ts @@ -359,6 +359,7 @@ export function renderShell(opts: ShellOptions): string { navigator.serviceWorker.register("/sw.js?v=5").then((reg) => { function showUpdateBanner() { if (!isStandalone) return; // Only show update prompt in installed PWA + if (sessionStorage.getItem('rspace_update_dismissed')) return; // dismissed this session const b = document.getElementById('pwa-update-banner'); if (!b || b.style.display !== 'none') return; // Hide install banner first if somehow both would show @@ -422,6 +423,7 @@ export function renderShell(opts: ShellOptions): string { document.getElementById('pwa-update-close')?.addEventListener('click', () => { document.getElementById('pwa-update-banner').style.display = 'none'; document.body.classList.remove('rspace-banner-visible'); + sessionStorage.setItem('rspace_update_dismissed', '1'); // don't re-show until next session }); // ── Header minimize toggle ── if (localStorage.getItem('rspace_headers_minimized') === '1') { @@ -515,19 +517,18 @@ export function renderShell(opts: ShellOptions): string { }); if (infoClose) infoClose.addEventListener('click', hideInfoPanel); - // Auto-show on first visit per rApp (checks localStorage, shows once then never again) + // Auto-show info panel ONCE globally (first rApp visit ever), then only via info button function autoShowIfFirstVisit(mid) { if (!mid || mid === 'rspace') return; // skip canvas try { - var key = 'rapp_info_seen_' + mid; - if (localStorage.getItem(key)) return; // already seen + if (localStorage.getItem('rapp_info_auto_shown')) return; // already shown once if (!localStorage.getItem('encryptid_session')) return; // not logged in - localStorage.setItem(key, '1'); + localStorage.setItem('rapp_info_auto_shown', '1'); setTimeout(function() { showInfoPanel(mid); }, 800); } catch(e) {} } - // Reset when switching tabs — auto-show for newly visited rApps + // Hide info panel when switching tabs (but don't auto-show for new tabs) document.addEventListener('layer-view-mode', hideInfoPanel); const tb = document.querySelector('rstack-tab-bar'); if (tb) { @@ -535,13 +536,10 @@ export function renderShell(opts: ShellOptions): string { hideInfoPanel(); // Reset cached module so next open loads fresh content for new tab infoPanel.dataset.loadedModule = ''; - // Auto-show info panel if this is the user's first visit to this rApp - var switchedModuleId = e.detail && e.detail.moduleId; - if (switchedModuleId) autoShowIfFirstVisit(switchedModuleId); }); } - // Auto-show on initial page load + // Auto-show on initial page load (only fires once globally) autoShowIfFirstVisit('${escapeAttr(moduleId)}'); // Expose for tour integration