openvibers/openvibe.vip Commits
Home: a taste and a door on phones (#121)
Changes
@@@ -88,3 +88,26 @@ code { background: rgba(255, 255, 255, .06); padding: 1px 5px; border-radius: 4p.vip-faq details[open] { padding-bottom: 12px; }.vip-faq summary { padding: 8px 0; margin: 0; }.vip-faq p { margin: 4px 0 0; color: var(--vip-muted); }++++/* The home on phones (2026-10-29): a taste and a door. The creators are a two-column list of names (each opens its++ page), the figures are one row, and the explainers fold under their headings. */++.vip-fold { border: 1px solid var(--border, #1f2d47); border-radius: 16px; background: var(--bg-secondary, #101828); }++.vip-fold > summary { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 56px; padding: 0 18px; cursor: pointer; list-style: none; }++.vip-fold > summary::-webkit-details-marker { display: none; }++.vip-fold > summary h2 { margin: 0; }++.vip-fold > summary span { color: var(--text-muted, #7386a3); font-weight: 600; font-size: .86rem; text-align: right; }++.vip-fold > summary:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: -2px; border-radius: 16px; }++.vip-fold .sc-sec { max-width: none; margin: 0; padding: 0 18px 18px; }++@media (max-width: 599px) {++ .creator-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }++ .creator-list > li { margin: 0; min-width: 0; }++ .creator-list a { min-height: 48px; padding: 8px 10px; gap: 8px; }++ .creator-list .vip-avatar { width: 28px; height: 28px; }++ .creator-list .vip-creator-text .muted { display: none; }++ .creator-list .vip-creator-text b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }++ .vip-stats { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); grid-template-columns: none; gap: 8px; }++ .vip-stats > div { padding: 10px 12px; }++ .vip-stats dt { font-size: 1.05rem; }++ .vip-stats dd { font-size: .76rem; line-height: 1.35; }++ .vip-fold > summary span { display: none; }++}@@@ -100,12 +100,14 @@ function home({ creators, live = [], networkUrl = 'https://openvibe.network' })title: 'Memberships across', accent: 'OpenVibe',lede: "Back the creators you watch with a monthly membership. Join once and it's recognised across OpenVibe: a badge by your name in chat, members-only posts, a members' room, whatever the plan lists.",actions: creators.length-- ? [{ label: 'Find a creator', href: '#creators', primary: true }, { label: 'Offer a plan', href: '#for-creators' }, { label: 'Your memberships', href: '/me' }]++ // Two, so they sit side by side on a phone; your memberships are in the app bar.++ ? [{ label: 'Find a creator', href: '#creators', primary: true }, { label: 'Offer a plan', href: '#for-creators' }]: [{ label: 'Offer a plan', href: '/dashboard', primary: true }, { label: 'Your memberships', href: '/me' }],note: 'Payments, renewals, cancellations and refunds are handled by OpenVibe.Billing.',html: `<dl class="vip-stats">${stats.join('')}</dl>`,}) + liveSection + `<section class="sc-sec" id="creators" aria-labelledby="creators-h"><h2 id="creators-h">Creators with a membership</h2><p class="sc-lede">Each page lists the creator's plan, what it includes and its price before you join.</p>${list}<p class="muted creators-cta">Are you a creator? <a href="/dashboard">Offer a plan</a>.</p></section>`++ + '<section class="sc-sec" aria-labelledby="how-h"><details class="vip-fold"><summary><h2 id="how-h">How a membership works</h2><span>perks, joining, the terms you keep</span></summary>'+ showcase.features({title: 'What a plan can include',lede: 'A creator builds each plan from perks; the plan lists exactly which, and each OpenVibe site that honours a perk recognises it.',@@@ -116,15 +118,14 @@ function home({ creators, live = [], networkUrl = 'https://openvibe.network' }){ icon: 'ov:community', title: 'Roles and emotes', text: 'A role in the community, emotes to use in chat.' },],}) + showcase.steps({-- title: 'How a membership works',items: [{ title: "Pick a creator's plan", text: 'Each creator page lists their plan, what it includes and its price.' },{ title: 'Join through OpenVibe.Billing', text: 'Pay from your Vibes credit or another way Billing offers; renew automatically or not, your choice.' },{ title: 'Keep the terms you joined under', text: 'Plans are versioned: the version you joined stays yours while your membership lasts, and every version stays public in the terms history.' },],-- }) + showcase.steps({-- id: 'for-creators',-- title: 'Offer a membership',++ }) + '</details></section>'++ + '<section class="sc-sec" id="for-creators" aria-labelledby="offer-h"><details class="vip-fold"><summary><h2 id="offer-h">Offer a membership</h2><span>your plan, and selling one to your software</span></summary>'++ + showcase.steps({lede: 'Streaming on OpenVibe.Live already? Your channel subscription is your plan here, ready to describe and price.',items: [{ title: 'Open your dashboard', href: '/dashboard', text: 'Sign in with your OpenVibe account; your plan and its members are all on one page.' },@@@ -156,7 +157,7 @@ if (e.active) unlockPro(); // expired, unknown or unreachable all answer no`,# {"active":true,"status":"active","expires_at":"…",…}`,},],-- }) + `++ }) + `</details></section><section class="sc-sec" id="questions" aria-labelledby="questions-h"><h2 id="questions-h">Questions</h2><div class="vip-faq">${HOME_FAQ.map((f) => `<details><summary>${esc(f.q)}</summary><p>${esc(f.a)}</p></details>`).join('')}</div></section>`;}
@@ -88,3 +88,26 @@ code { background: rgba(255, 255, 255, .06); padding: 1px 5px; border-radius: 4p
@@ -88,3 +88,26 @@ code { background: rgba(255, 255, 255, .06); padding: 1px 5px; border-radius: 4p
.vip-faq details[open] { padding-bottom: 12px; }
.vip-faq details[open] { padding-bottom: 12px; }
.vip-faq summary { padding: 8px 0; margin: 0; }
.vip-faq summary { padding: 8px 0; margin: 0; }
.vip-faq p { margin: 4px 0 0; color: var(--vip-muted); }
.vip-faq p { margin: 4px 0 0; color: var(--vip-muted); }
+
+/* The home on phones (2026-10-29): a taste and a door. The creators are a two-column list of names (each opens its
+ page), the figures are one row, and the explainers fold under their headings. */
+.vip-fold { border: 1px solid var(--border, #1f2d47); border-radius: 16px; background: var(--bg-secondary, #101828); }
+.vip-fold > summary { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 56px; padding: 0 18px; cursor: pointer; list-style: none; }
+.vip-fold > summary::-webkit-details-marker { display: none; }
+.vip-fold > summary h2 { margin: 0; }
+.vip-fold > summary span { color: var(--text-muted, #7386a3); font-weight: 600; font-size: .86rem; text-align: right; }
+.vip-fold > summary:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: -2px; border-radius: 16px; }
+.vip-fold .sc-sec { max-width: none; margin: 0; padding: 0 18px 18px; }
+@media (max-width: 599px) {
+ .creator-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
+ .creator-list > li { margin: 0; min-width: 0; }
+ .creator-list a { min-height: 48px; padding: 8px 10px; gap: 8px; }
+ .creator-list .vip-avatar { width: 28px; height: 28px; }
+ .creator-list .vip-creator-text .muted { display: none; }
+ .creator-list .vip-creator-text b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+ .vip-stats { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); grid-template-columns: none; gap: 8px; }
+ .vip-stats > div { padding: 10px 12px; }
+ .vip-stats dt { font-size: 1.05rem; }
+ .vip-stats dd { font-size: .76rem; line-height: 1.35; }
+ .vip-fold > summary span { display: none; }
+}
@@ -100,12 +100,14 @@ function home({ creators, live = [], networkUrl = 'https://openvibe.network' })
@@ -100,12 +100,14 @@ function home({ creators, live = [], networkUrl = 'https://openvibe.network' })
title: 'Memberships across', accent: 'OpenVibe',
title: 'Memberships across', accent: 'OpenVibe',
lede: "Back the creators you watch with a monthly membership. Join once and it's recognised across OpenVibe: a badge by your name in chat, members-only posts, a members' room, whatever the plan lists.",
lede: "Back the creators you watch with a monthly membership. Join once and it's recognised across OpenVibe: a badge by your name in chat, members-only posts, a members' room, whatever the plan lists.",
actions: creators.length
actions: creators.length
- ? [{ label: 'Find a creator', href: '#creators', primary: true }, { label: 'Offer a plan', href: '#for-creators' }, { label: 'Your memberships', href: '/me' }]
+ // Two, so they sit side by side on a phone; your memberships are in the app bar.
+ ? [{ label: 'Find a creator', href: '#creators', primary: true }, { label: 'Offer a plan', href: '#for-creators' }]
: [{ label: 'Offer a plan', href: '/dashboard', primary: true }, { label: 'Your memberships', href: '/me' }],
: [{ label: 'Offer a plan', href: '/dashboard', primary: true }, { label: 'Your memberships', href: '/me' }],
note: 'Payments, renewals, cancellations and refunds are handled by OpenVibe.Billing.',
note: 'Payments, renewals, cancellations and refunds are handled by OpenVibe.Billing.',
html: `<dl class="vip-stats">${stats.join('')}</dl>`,
html: `<dl class="vip-stats">${stats.join('')}</dl>`,
}) + liveSection + `
}) + liveSection + `
<section class="sc-sec" id="creators" aria-labelledby="creators-h"><h2 id="creators-h">Creators with a membership</h2><p class="sc-lede">Each page lists the creator's plan, what it includes and its price before you join.</p>${list}<p class="muted creators-cta">Are you a creator? <a href="/dashboard">Offer a plan</a>.</p></section>`
<section class="sc-sec" id="creators" aria-labelledby="creators-h"><h2 id="creators-h">Creators with a membership</h2><p class="sc-lede">Each page lists the creator's plan, what it includes and its price before you join.</p>${list}<p class="muted creators-cta">Are you a creator? <a href="/dashboard">Offer a plan</a>.</p></section>`
+ + '<section class="sc-sec" aria-labelledby="how-h"><details class="vip-fold"><summary><h2 id="how-h">How a membership works</h2><span>perks, joining, the terms you keep</span></summary>'
+ showcase.features({
+ showcase.features({
title: 'What a plan can include',
title: 'What a plan can include',
lede: 'A creator builds each plan from perks; the plan lists exactly which, and each OpenVibe site that honours a perk recognises it.',
lede: 'A creator builds each plan from perks; the plan lists exactly which, and each OpenVibe site that honours a perk recognises it.',
@@ -116,15 +118,14 @@ function home({ creators, live = [], networkUrl = 'https://openvibe.network' })
@@ -116,15 +118,14 @@ function home({ creators, live = [], networkUrl = 'https://openvibe.network' })
{ icon: 'ov:community', title: 'Roles and emotes', text: 'A role in the community, emotes to use in chat.' },
{ icon: 'ov:community', title: 'Roles and emotes', text: 'A role in the community, emotes to use in chat.' },
],
],
}) + showcase.steps({
}) + showcase.steps({
- title: 'How a membership works',
items: [
items: [
{ title: "Pick a creator's plan", text: 'Each creator page lists their plan, what it includes and its price.' },
{ title: "Pick a creator's plan", text: 'Each creator page lists their plan, what it includes and its price.' },
{ title: 'Join through OpenVibe.Billing', text: 'Pay from your Vibes credit or another way Billing offers; renew automatically or not, your choice.' },
{ title: 'Join through OpenVibe.Billing', text: 'Pay from your Vibes credit or another way Billing offers; renew automatically or not, your choice.' },
{ title: 'Keep the terms you joined under', text: 'Plans are versioned: the version you joined stays yours while your membership lasts, and every version stays public in the terms history.' },
{ title: 'Keep the terms you joined under', text: 'Plans are versioned: the version you joined stays yours while your membership lasts, and every version stays public in the terms history.' },
],
],
- }) + showcase.steps({
- id: 'for-creators',
- title: 'Offer a membership',
+ }) + '</details></section>'
+ + '<section class="sc-sec" id="for-creators" aria-labelledby="offer-h"><details class="vip-fold"><summary><h2 id="offer-h">Offer a membership</h2><span>your plan, and selling one to your software</span></summary>'
+ + showcase.steps({
lede: 'Streaming on OpenVibe.Live already? Your channel subscription is your plan here, ready to describe and price.',
lede: 'Streaming on OpenVibe.Live already? Your channel subscription is your plan here, ready to describe and price.',
items: [
items: [
{ title: 'Open your dashboard', href: '/dashboard', text: 'Sign in with your OpenVibe account; your plan and its members are all on one page.' },
{ title: 'Open your dashboard', href: '/dashboard', text: 'Sign in with your OpenVibe account; your plan and its members are all on one page.' },
@@ -156,7 +157,7 @@ if (e.active) unlockPro(); // expired, unknown or unreachable all answer no`,
@@ -156,7 +157,7 @@ if (e.active) unlockPro(); // expired, unknown or unreachable all answer no`,
# {"active":true,"status":"active","expires_at":"…",…}`,
# {"active":true,"status":"active","expires_at":"…",…}`,
},
},
],
],
- }) + `
+ }) + `</details></section>
<section class="sc-sec" id="questions" aria-labelledby="questions-h"><h2 id="questions-h">Questions</h2><div class="vip-faq">${HOME_FAQ.map((f) => `<details><summary>${esc(f.q)}</summary><p>${esc(f.a)}</p></details>`).join('')}</div></section>`;
<section class="sc-sec" id="questions" aria-labelledby="questions-h"><h2 id="questions-h">Questions</h2><div class="vip-faq">${HOME_FAQ.map((f) => `<details><summary>${esc(f.q)}</summary><p>${esc(f.a)}</p></details>`).join('')}</div></section>`;
}
}