322 lines
15 KiB
JavaScript
322 lines
15 KiB
JavaScript
import React from 'react'
|
|
import { usePage } from '@inertiajs/react'
|
|
import DocsCallout from '../../components/docs/DocsCallout'
|
|
import DocsSection from '../../components/docs/DocsSection'
|
|
import DocsSidebarNav from '../../components/docs/DocsSidebarNav'
|
|
import DocsStepList from '../../components/docs/DocsStepList'
|
|
import QuickstartChecklist from '../../components/docs/QuickstartChecklist'
|
|
import QuickstartNextSteps from '../../components/docs/QuickstartNextSteps'
|
|
import SeoHead from '../../components/seo/SeoHead'
|
|
import {
|
|
COMPARISON_CARDS,
|
|
COMMON_MISTAKES,
|
|
CREATE_STEPS,
|
|
CREDIT_TERMS,
|
|
FIRST_WEEK_BEST_PRACTICES,
|
|
GOOD_FIT,
|
|
NEXT_STEPS,
|
|
NOT_NEEDED_YET,
|
|
PUBLISH_STEPS,
|
|
QUICK_CHECKLIST,
|
|
ROLE_CARDS,
|
|
SECTION_ITEMS,
|
|
SETUP_TASKS,
|
|
} from './groupQuickstartContent'
|
|
|
|
function HeroStat({ label, value, note }) {
|
|
return (
|
|
<div className="rounded-[22px] border border-white/10 bg-black/20 p-4">
|
|
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">{label}</div>
|
|
<div className="mt-2 text-lg font-semibold text-white">{value}</div>
|
|
<p className="mt-2 text-sm leading-6 text-slate-400">{note}</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function ComparisonCard({ card }) {
|
|
return (
|
|
<article className="rounded-[28px] border border-white/10 bg-black/20 p-5">
|
|
<div className="flex h-11 w-11 items-center justify-center rounded-2xl border border-white/10 bg-white/[0.04] text-sky-200">
|
|
<i className={card.icon} />
|
|
</div>
|
|
<h3 className="mt-4 text-xl font-semibold text-white">{card.title}</h3>
|
|
<ul className="mt-4 space-y-2">
|
|
{card.bullets.map((item) => (
|
|
<li key={item} className="flex gap-3 text-sm leading-6 text-slate-300">
|
|
<span className="mt-1.5 h-2 w-2 shrink-0 rounded-full bg-sky-300" />
|
|
<span>{item}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</article>
|
|
)
|
|
}
|
|
|
|
function SimpleListCard({ title, eyebrow, items, tone = 'sky' }) {
|
|
const toneClass = tone === 'emerald'
|
|
? 'border-emerald-300/15 bg-emerald-400/10 text-emerald-50'
|
|
: 'border-white/10 bg-black/20 text-white'
|
|
|
|
return (
|
|
<div className={`rounded-[28px] border p-5 ${toneClass}`}>
|
|
<p className="text-[11px] font-semibold uppercase tracking-[0.18em] opacity-80">{eyebrow}</p>
|
|
<h3 className="mt-2 text-xl font-semibold">{title}</h3>
|
|
<ul className="mt-4 space-y-3">
|
|
{items.map((item) => (
|
|
<li key={item} className="flex gap-3 text-sm leading-6 opacity-95">
|
|
<span className="mt-1 flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-white/10 bg-white/[0.06] text-[10px]">
|
|
<i className="fa-solid fa-check" />
|
|
</span>
|
|
<span>{item}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function RoleCard({ role }) {
|
|
return (
|
|
<article className="rounded-[26px] border border-white/10 bg-black/20 p-5">
|
|
<div className="inline-flex rounded-full border border-sky-300/20 bg-sky-300/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-sky-100">
|
|
{role.role}
|
|
</div>
|
|
<p className="mt-4 text-sm leading-7 text-slate-300">{role.summary}</p>
|
|
<p className="mt-3 text-sm font-medium text-slate-200">{role.note}</p>
|
|
</article>
|
|
)
|
|
}
|
|
|
|
function CompactGrid({ items }) {
|
|
return (
|
|
<div className="grid gap-3 md:grid-cols-2">
|
|
{items.map((item) => (
|
|
<div key={item} className="rounded-[22px] border border-white/10 bg-black/20 p-4 text-sm leading-6 text-slate-300">
|
|
{item}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function CreditCard({ item }) {
|
|
return (
|
|
<div className="rounded-[24px] border border-white/10 bg-black/20 p-4">
|
|
<div className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">{item.label}</div>
|
|
<div className="mt-2 text-base font-semibold text-white">{item.value}</div>
|
|
<p className="mt-2 text-sm leading-6 text-slate-300">{item.note}</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default function GroupQuickstartPage() {
|
|
const { props } = usePage()
|
|
const links = props.links || {}
|
|
const nextSteps = NEXT_STEPS.map((item) => ({
|
|
...item,
|
|
href: links[item.linkKey] || '#',
|
|
}))
|
|
|
|
const jsonLd = [
|
|
{
|
|
'@context': 'https://schema.org',
|
|
'@type': 'Article',
|
|
headline: props.title,
|
|
description: props.description,
|
|
url: props.seo?.canonical,
|
|
author: {
|
|
'@type': 'Organization',
|
|
name: 'Skinbase',
|
|
},
|
|
about: ['Groups', 'Quickstart', 'Collaborative publishing', 'Contributor credit'],
|
|
},
|
|
]
|
|
|
|
return (
|
|
<main className="min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(14,165,233,0.18),_transparent_24%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8">
|
|
<SeoHead seo={props.seo || {}} title={props.title} description={props.description} jsonLd={jsonLd} />
|
|
|
|
<div className="mx-auto max-w-[1380px]">
|
|
<section id="introduction" className="rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.74)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.18),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10">
|
|
<div className="grid gap-8 xl:grid-cols-[minmax(0,1fr)_340px]">
|
|
<div>
|
|
<p className="text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80">Groups quickstart</p>
|
|
<h1 className="mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl">Get started with Groups fast and publish together without losing individual credit.</h1>
|
|
<p className="mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg">This quickstart is the fast path from curiosity to first success. It shows what a Group is, when to use one, how to invite the right people, and how to publish your first Group artwork with contributor credit handled properly.</p>
|
|
<div className="mt-6 flex flex-wrap gap-3">
|
|
<a href={links.create_group} className="rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18">Create a Group</a>
|
|
<a href={links.group_studio} className="rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]">Open Group Studio</a>
|
|
<a href={links.full_documentation} className="rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]">Read full Groups documentation</a>
|
|
</div>
|
|
{links.faq ? (
|
|
<div className="mt-4">
|
|
<a href={links.faq} className="text-sm font-semibold text-sky-200 underline underline-offset-4">
|
|
Need quick answers instead of the full guide? Open the Groups FAQ.
|
|
</a>
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
|
|
<div className="grid gap-3 sm:grid-cols-3 xl:grid-cols-1">
|
|
<HeroStat label="What a Group is" value="A shared team identity" note="Use it when a studio, crew, or project needs one public home instead of scattered personal uploads." />
|
|
<HeroStat label="What stays visible" value="Real contributor credit" note="Published by, uploaded by, primary author, and contributor roles can still reflect the real people behind the work." />
|
|
<HeroStat label="First win" value="Create, invite, publish" note="The goal of this page is simple: get you to a clean first Group publish without confusion." />
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div className="mt-8 grid gap-6 lg:grid-cols-[220px_minmax(0,1fr)]">
|
|
<DocsSidebarNav sections={SECTION_ITEMS} />
|
|
|
|
<div className="space-y-6">
|
|
<DocsSection
|
|
id="what-is-a-group"
|
|
eyebrow="Start here"
|
|
title="What is a Group?"
|
|
summary="A Group is a shared creative identity for multiple people. It lets a team publish together under one name while still showing who uploaded, authored, and contributed to the work."
|
|
>
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
{COMPARISON_CARDS.map((card) => <ComparisonCard key={card.title} card={card} />)}
|
|
</div>
|
|
|
|
<div className="mt-6">
|
|
<DocsCallout tone="note" title="The key idea to keep in your head">
|
|
Group and personal publishing can coexist. A Group gives the team a shared identity, but it should not erase the people behind the work.
|
|
</DocsCallout>
|
|
</div>
|
|
</DocsSection>
|
|
|
|
<DocsSection
|
|
id="when-to-use"
|
|
eyebrow="Decision"
|
|
title="When should you use a Group?"
|
|
summary="Use a Group when collaboration is real enough to need shared identity, shared workflow, or shared publishing. Skip it for now if it only adds overhead."
|
|
>
|
|
<div className="grid gap-4 lg:grid-cols-2">
|
|
<SimpleListCard title="Use a Group when..." eyebrow="Good fit" items={GOOD_FIT} tone="emerald" />
|
|
<SimpleListCard title="You can wait when..." eyebrow="Not necessary yet" items={NOT_NEEDED_YET} />
|
|
</div>
|
|
</DocsSection>
|
|
|
|
<DocsSection
|
|
id="create-first-group"
|
|
eyebrow="Build the foundation"
|
|
title="Create your first Group"
|
|
summary="The fastest clean start is a simple start. Get the identity created first, then improve it as the Group becomes active."
|
|
>
|
|
<DocsStepList items={CREATE_STEPS} />
|
|
|
|
<div className="mt-6">
|
|
<DocsCallout tone="tip" title="Start simple">
|
|
You do not need perfect branding or a complex team structure on day one. You need a clear name, a usable page, and the right first members.
|
|
</DocsCallout>
|
|
</div>
|
|
</DocsSection>
|
|
|
|
<DocsSection
|
|
id="setup-properly"
|
|
eyebrow="Right after creation"
|
|
title="Set up your Group properly"
|
|
summary="The first few setup moves decide whether the Group feels trustworthy and active or unfinished and confusing."
|
|
>
|
|
<CompactGrid items={SETUP_TASKS} />
|
|
</DocsSection>
|
|
|
|
<DocsSection
|
|
id="invite-and-roles"
|
|
eyebrow="Team setup"
|
|
title="Invite members and choose roles"
|
|
summary="Keep the role model clear. Most teams should stay simple at first: very few Owners, very few Admins, Editors for trusted content operators, and Contributors for most collaborators."
|
|
>
|
|
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
|
{ROLE_CARDS.map((role) => <RoleCard key={role.role} role={role} />)}
|
|
</div>
|
|
|
|
<div className="mt-6 grid gap-4 md:grid-cols-2">
|
|
<DocsCallout tone="practice" title="Recommended first move">
|
|
Invite your first members, assign only the roles they need right now, and avoid advanced permission tuning until the team has real workflow pressure.
|
|
</DocsCallout>
|
|
<DocsCallout tone="note" title="Advanced overrides can wait">
|
|
If you need permission overrides later, you can add them later. The quickstart path is deliberately simpler than the full feature set.
|
|
</DocsCallout>
|
|
</div>
|
|
</DocsSection>
|
|
|
|
<DocsSection
|
|
id="publish-first-artwork"
|
|
eyebrow="First success"
|
|
title="Publish your first artwork as a Group"
|
|
summary="This is where new teams get tripped up most often. The artwork should appear under the Group publicly, but the people behind it should still be represented correctly."
|
|
>
|
|
<DocsStepList items={PUBLISH_STEPS} />
|
|
|
|
<div className="mt-6">
|
|
<DocsCallout tone="warning" title="Always check publishing context before the final click">
|
|
Confirm whether you are publishing as your personal profile or as the Group. That one check prevents a lot of cleanup later.
|
|
</DocsCallout>
|
|
</div>
|
|
</DocsSection>
|
|
|
|
<DocsSection
|
|
id="contributor-credit"
|
|
eyebrow="Credit"
|
|
title="Understand contributor credit"
|
|
summary="Groups are for shared identity, not for hiding who did the actual work. Before the first public publish, make sure the credit record reflects reality."
|
|
>
|
|
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
|
{CREDIT_TERMS.map((item) => <CreditCard key={item.label} item={item} />)}
|
|
</div>
|
|
|
|
<div className="mt-6">
|
|
<DocsCallout tone="practice" title="Best practice">
|
|
Review contributor credit before every first release, first Group artwork, or first major collaborative drop. Do not leave attribution as an afterthought.
|
|
</DocsCallout>
|
|
</div>
|
|
</DocsSection>
|
|
|
|
<DocsSection
|
|
id="first-week-best-practices"
|
|
eyebrow="First week"
|
|
title="First-week best practices"
|
|
summary="The first week should make the Group feel intentional, active, and easy to understand."
|
|
>
|
|
<CompactGrid items={FIRST_WEEK_BEST_PRACTICES} />
|
|
</DocsSection>
|
|
|
|
<DocsSection
|
|
id="common-mistakes"
|
|
eyebrow="Avoid these"
|
|
title="Common mistakes to avoid"
|
|
summary="These are the fastest ways to make a new Group feel confusing or unreliable."
|
|
>
|
|
<div className="grid gap-3 md:grid-cols-2">
|
|
{COMMON_MISTAKES.map((item) => (
|
|
<div key={item} className="rounded-[24px] border border-amber-300/15 bg-amber-400/10 p-4 text-sm leading-6 text-amber-50/95">
|
|
{item}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</DocsSection>
|
|
|
|
<section id="quick-checklist" className="scroll-mt-24">
|
|
<QuickstartChecklist
|
|
title="Use this before your first Group publish"
|
|
summary="This is the lightweight completion list you want to be able to say yes to before the Group starts publishing publicly."
|
|
items={QUICK_CHECKLIST}
|
|
/>
|
|
</section>
|
|
|
|
<DocsSection
|
|
id="next-steps"
|
|
eyebrow="Keep going"
|
|
title="Next steps"
|
|
summary="Once the first Group exists and the first publish is clear, move into the next surface that helps your team actually operate."
|
|
>
|
|
<QuickstartNextSteps items={nextSteps} />
|
|
</DocsSection>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
)
|
|
} |