feat(copy): wrote some basic copy for the statis pages, landing, prices, products
Some checks failed
Backend CI/CD / build_and_deploy (push) Has been cancelled
Frontend CI/CD / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-05-04 22:08:42 -04:00
parent b7379cf823
commit feef8cbafd
17 changed files with 1583 additions and 147 deletions

View File

@@ -1,35 +1,50 @@
<script setup>
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import LandingSiteMenu from '@/features/landing/components/LandingSiteMenu.vue';
import { usePublicPageMeta } from '@/features/landing/publicPageMeta.js';
const { t } = useI18n();
usePublicPageMeta({
title: 'Socialize | Social media approval workflow',
description: 'Socialize helps teams manage social media content review, revisions, approval decisions, and publication handoff in one workflow.',
title: computed(() => t('public.landing.meta.title')),
description: computed(() => t('public.landing.meta.description')),
path: '/',
});
const pillarKeys = ['singleSource', 'collaboration', 'ownership'];
const focusMetricKeys = ['clients', 'campaigns', 'contentItems'];
const proofKeys = ['reviews', 'handoff', 'traceability'];
const mockupRowKeys = ['reel', 'launch', 'newsletter'];
const pillars = computed(() => [
{
eyebrow: 'Single source of truth',
title: 'Comments, revisions, decisions, and due dates stay attached to one content item.',
},
{
eyebrow: 'Built for agencies',
title: 'Coordinate internal teams, providers, and client approvers without chasing email threads.',
},
{
eyebrow: 'Google Drive first',
title: 'Keep Drive as the asset owner when clients require it, while centralizing workflow in Socialize.',
},
...pillarKeys.map(key => ({
eyebrow: t(`public.landing.pillars.${key}.eyebrow`),
title: t(`public.landing.pillars.${key}.title`),
})),
]);
const workflow = computed(() => [
'Create a content item with copy, targets, due dates, and review notes.',
'Attach Google Drive assets and register revisions as feedback comes in.',
'Request internal review, then client approval, with a clear audit trail.',
'Mark the item ready for publishing handoff once approvals are complete.',
]);
const focusMetrics = computed(() =>
focusMetricKeys.map(key => ({
label: t(`public.landing.focus.${key}.label`),
description: t(`public.landing.focus.${key}.description`),
}))
);
const proofPoints = computed(() =>
proofKeys.map(key => ({
label: t(`public.landing.proof.${key}.label`),
value: t(`public.landing.proof.${key}.value`),
}))
);
const mockupRows = computed(() =>
mockupRowKeys.map(key => ({
title: t(`public.landing.mockup.${key}.title`),
meta: t(`public.landing.mockup.${key}.meta`),
status: t(`public.landing.mockup.${key}.status`),
}))
);
</script>
<template>
@@ -42,32 +57,51 @@
class="hero-card"
>
<div class="hero-copy">
<div class="eyebrow">Social media approval workflow</div>
<h1>Replace Drive links, scattered comments, and manual follow-up with one review system.</h1>
<p>
Socialize is being rebuilt as an agency workflow product for content review, revision tracking,
client approval, and publication readiness.
</p>
<div class="eyebrow">{{ t('public.landing.hero.eyebrow') }}</div>
<h1>{{ t('public.landing.hero.title') }}</h1>
<p>{{ t('public.landing.hero.description') }}</p>
<div class="proof-row">
<div
v-for="proof in proofPoints"
:key="proof.label"
>
<strong>{{ proof.value }}</strong>
<span>{{ proof.label }}</span>
</div>
</div>
<div class="hero-actions">
<router-link to="/login">
<button class="primary">Open the app</button>
</router-link>
<router-link to="/register">
<button class="secondary">Create an internal account</button>
<button class="primary">{{ t('public.landing.hero.primaryAction') }}</button>
</router-link>
</div>
<span class="cta-note">{{ t('public.landing.hero.ctaNote') }}</span>
</div>
<div class="hero-panel">
<div class="hero-panel-title">Version 1 workflow</div>
<ol class="workflow-list">
<li
v-for="step in workflow"
:key="step"
<div
class="workflow-preview"
aria-hidden="true"
>
<div class="preview-bar">
<span>{{ t('public.landing.mockup.title') }}</span>
<strong>{{ t('public.landing.mockup.badge') }}</strong>
</div>
<div class="preview-list">
<div
v-for="row in mockupRows"
:key="row.title"
class="preview-row"
>
{{ step }}
</li>
</ol>
<div>
<strong>{{ row.title }}</strong>
<span>{{ row.meta }}</span>
</div>
<em>{{ row.status }}</em>
</div>
</div>
<div class="approval-card">
<span>{{ t('public.landing.mockup.approvalLabel') }}</span>
<strong>{{ t('public.landing.mockup.approvalValue') }}</strong>
</div>
</div>
</section>
@@ -84,37 +118,37 @@
<section class="focus-card">
<div>
<div class="eyebrow">Current build focus</div>
<h2>Phase 1 into Phase 2: retire the creator product surface and install the workflow domain shell.</h2>
<div class="eyebrow">{{ t('public.landing.focus.eyebrow') }}</div>
<h2>{{ t('public.landing.focus.title') }}</h2>
<router-link
class="inline-cta"
to="/register"
>
{{ t('public.landing.hero.primaryAction') }}
</router-link>
</div>
<div class="focus-metrics">
<div>
<strong>Clients</strong>
<span>Brands and businesses under one workspace</span>
</div>
<div>
<strong>Campaigns</strong>
<span>Grouped work tied to timelines, approvals, and delivery goals</span>
</div>
<div>
<strong>Content items</strong>
<span>Reviewable units with assets, copy, and approvals</span>
<div
v-for="metric in focusMetrics"
:key="metric.label"
>
<strong>{{ metric.label }}</strong>
<span>{{ metric.description }}</span>
</div>
</div>
</section>
<section
id="pricing"
class="pricing-card"
>
<section class="final-cta">
<div>
<div class="eyebrow">Pricing</div>
<h2>Workspace pricing for teams that manage content approvals with clients.</h2>
<div class="eyebrow">{{ t('public.landing.finalCta.eyebrow') }}</div>
<h2>{{ t('public.landing.finalCta.title') }}</h2>
<p>{{ t('public.landing.finalCta.description') }}</p>
</div>
<router-link to="/login">
<button class="secondary pricing-action">Open the app</button>
<router-link to="/register">
<button class="primary">{{ t('public.landing.hero.primaryAction') }}</button>
</router-link>
</section>
</main>
</div>
</template>
@@ -129,7 +163,7 @@
}
.hero-card {
@apply grid gap-6 rounded-[2rem] p-6 md:grid-cols-[1.4fr_0.9fr] md:p-10;
@apply grid gap-8 overflow-hidden rounded-[2rem] p-6 md:grid-cols-[1fr_0.88fr] md:p-10;
background: linear-gradient(145deg, #172033 0%, #25324b 65%, #314766 100%);
color: #fffaf2;
box-shadow: 0 30px 80px rgba(23, 32, 51, 0.18);
@@ -157,23 +191,91 @@
@apply flex flex-col gap-3 sm:flex-row;
}
.hero-panel {
@apply rounded-[1.5rem] p-6;
background: rgba(255, 250, 242, 0.08);
border: 1px solid rgba(255, 250, 242, 0.12);
.hero-actions .primary,
.final-cta .primary {
@apply min-h-12 px-7 text-base;
box-shadow: 0 18px 40px rgba(255, 138, 61, 0.28);
}
.hero-panel-title {
@apply mb-4 text-sm font-bold uppercase tracking-[0.22em];
.cta-note {
@apply text-sm font-semibold;
color: rgba(255, 250, 242, 0.72);
}
.proof-row {
@apply grid max-w-2xl gap-3 sm:grid-cols-3;
}
.proof-row div {
@apply rounded-[1rem] border p-4;
background: rgba(255, 250, 242, 0.08);
border-color: rgba(255, 250, 242, 0.12);
}
.proof-row strong {
@apply block text-2xl font-black;
color: #7dd3c7;
}
.workflow-list {
@apply flex list-decimal flex-col gap-4 pl-5;
.proof-row span {
@apply mt-1 block text-xs font-bold uppercase leading-5 tracking-[0.12em];
color: rgba(255, 250, 242, 0.72);
}
.workflow-list li {
@apply text-sm leading-6 md:text-base;
.workflow-preview {
@apply flex flex-col gap-4 rounded-[1.5rem] p-4;
background: rgba(255, 250, 242, 0.1);
border: 1px solid rgba(255, 250, 242, 0.14);
}
.preview-bar {
@apply flex items-center justify-between gap-3 rounded-[1rem] bg-white/90 px-4 py-3;
color: #172033;
}
.preview-bar span,
.approval-card span {
@apply text-xs font-black uppercase tracking-[0.18em];
color: #0f766e;
}
.preview-bar strong {
@apply rounded-full px-3 py-1 text-xs font-black;
background: rgba(255, 138, 61, 0.14);
color: #b45309;
}
.preview-list {
@apply flex flex-col gap-3;
}
.preview-row {
@apply flex items-center justify-between gap-4 rounded-[1rem] bg-white/90 p-4;
color: #172033;
}
.preview-row strong {
@apply block text-sm font-black;
}
.preview-row span {
@apply mt-1 block text-xs font-semibold;
color: #44516a;
}
.preview-row em {
@apply rounded-full px-3 py-1 text-xs font-black not-italic;
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
}
.approval-card {
@apply rounded-[1rem] bg-white/95 p-5;
color: #172033;
}
.approval-card strong {
@apply mt-2 block text-2xl font-black leading-tight;
}
.pillars-grid {
@@ -203,6 +305,16 @@
color: #172033;
}
.inline-cta {
@apply mt-5 inline-flex h-11 items-center rounded-full px-5 text-sm font-black no-underline transition-colors;
background: #172033;
color: #fffaf2;
}
.inline-cta:hover {
background: #0f766e;
}
.focus-metrics {
@apply grid gap-4 md:grid-cols-3;
}
@@ -222,19 +334,20 @@
color: #3f4d63;
}
.pricing-card {
@apply flex flex-col gap-5 rounded-[1.75rem] p-6 md:flex-row md:items-center md:justify-between md:p-8;
background: rgba(255, 255, 255, 0.84);
border: 1px solid rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
.final-cta {
@apply flex flex-col gap-6 rounded-[2rem] p-6 md:flex-row md:items-center md:justify-between md:p-10;
background: #172033;
color: #fffaf2;
box-shadow: 0 30px 80px rgba(23, 32, 51, 0.18);
}
.pricing-card h2 {
@apply mt-3 max-w-3xl text-2xl font-black leading-tight md:text-3xl;
color: #172033;
.final-cta h2 {
@apply mt-3 max-w-3xl text-3xl font-black leading-tight md:text-5xl;
}
.pricing-action {
@apply w-full sm:w-auto;
.final-cta p {
@apply mt-4 max-w-2xl text-base leading-7;
color: rgba(255, 250, 242, 0.78);
}
</style>