Import source: cshare-app/src/pages/DocsPage
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
import { useState } from 'react';
|
||||
import { LinkIcon, UploadIcon, ShieldIcon, ClockIcon, ChartIcon } from '../components/Icons';
|
||||
|
||||
const NAV = [
|
||||
{ id: 'quickstart', label: 'Quick Start' },
|
||||
{ id: 'uploading', label: 'Uploading Files' },
|
||||
{ id: 'sharing', label: 'Share Links' },
|
||||
{ id: 'expiry', label: 'Link Expiry' },
|
||||
{ id: 'analytics', label: 'Analytics' },
|
||||
{ id: 'api', label: 'API Reference' },
|
||||
{ id: 'faq', label: 'FAQ' },
|
||||
];
|
||||
|
||||
const Code = ({ children }) => (
|
||||
<code style={{
|
||||
display: 'block',
|
||||
background: 'var(--bg-surface)',
|
||||
border: '1px solid var(--border-subtle)',
|
||||
borderRadius: 'var(--radius-md)',
|
||||
padding: '16px 20px',
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '0.875rem',
|
||||
color: 'var(--accent)',
|
||||
lineHeight: 1.7,
|
||||
overflowX: 'auto',
|
||||
whiteSpace: 'pre',
|
||||
}}>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
|
||||
const Inline = ({ children }) => (
|
||||
<code style={{ background: 'var(--bg-surface)', border: '1px solid var(--border-subtle)', borderRadius: '4px', padding: '2px 6px', fontFamily: 'monospace', fontSize: '0.8125rem', color: 'var(--accent)' }}>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
|
||||
const Section = ({ id, title, icon, children }) => (
|
||||
<section id={id} style={{ marginBottom: '56px', scrollMarginTop: '80px' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '20px', paddingBottom: '16px', borderBottom: '1px solid var(--border-subtle)' }}>
|
||||
{icon && <span style={{ color: 'var(--accent)' }}>{icon}</span>}
|
||||
<h2 style={{ fontFamily: 'var(--font-heading)', fontWeight: 700, fontSize: '1.375rem', letterSpacing: '-0.02em' }}>{title}</h2>
|
||||
</div>
|
||||
{children}
|
||||
</section>
|
||||
);
|
||||
|
||||
const P = ({ children }) => (
|
||||
<p style={{ color: 'var(--text-secondary)', lineHeight: 1.8, marginBottom: '16px', fontSize: '0.9375rem' }}>{children}</p>
|
||||
);
|
||||
|
||||
const H3 = ({ children }) => (
|
||||
<h3 style={{ fontFamily: 'var(--font-heading)', fontWeight: 600, fontSize: '1rem', marginBottom: '10px', marginTop: '24px', color: 'var(--text-primary)' }}>{children}</h3>
|
||||
);
|
||||
|
||||
export default function DocsPage() {
|
||||
const [active, setActive] = useState('quickstart');
|
||||
|
||||
const scrollTo = (id) => {
|
||||
setActive(id);
|
||||
document.getElementById(id)?.scrollIntoView({ behavior: 'smooth' });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="page-enter" style={{ minHeight: '100vh', maxWidth: '1100px', margin: '0 auto', padding: '48px 24px' }}>
|
||||
<div style={{ marginBottom: '40px' }}>
|
||||
<div style={{ display: 'inline-flex', alignItems: 'center', gap: '8px', marginBottom: '16px' }}>
|
||||
<span style={{ color: 'var(--accent)', fontFamily: 'var(--font-heading)', fontWeight: 700 }}>//</span>
|
||||
<span style={{ color: 'var(--text-muted)', fontFamily: 'var(--font-heading)', fontWeight: 600, fontSize: '0.75rem', letterSpacing: '0.12em', textTransform: 'uppercase' }}>Documentation</span>
|
||||
</div>
|
||||
<h1 className="heading-lg" style={{ marginBottom: '12px' }}>CShare Docs</h1>
|
||||
<p style={{ color: 'var(--text-secondary)', fontSize: '1.0625rem' }}>Everything you need to upload, share, and track files.</p>
|
||||
</div>
|
||||
|
||||
<div className="docs-layout" style={{ display: 'grid', gridTemplateColumns: '220px 1fr', gap: '48px', alignItems: 'start' }}>
|
||||
{/* Sidebar */}
|
||||
<div className="docs-sidebar" style={{ position: 'sticky', top: '88px' }}>
|
||||
<div className="card" style={{ padding: '16px' }}>
|
||||
<div style={{ fontSize: '0.6875rem', fontFamily: 'var(--font-heading)', fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--text-muted)', padding: '4px 8px', marginBottom: '8px' }}>
|
||||
On this page
|
||||
</div>
|
||||
{NAV.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => scrollTo(item.id)}
|
||||
style={{
|
||||
display: 'block', width: '100%', textAlign: 'left',
|
||||
padding: '8px 12px', borderRadius: 'var(--radius-sm)',
|
||||
fontFamily: 'var(--font-body)', fontSize: '0.875rem', fontWeight: active === item.id ? 600 : 400,
|
||||
color: active === item.id ? 'var(--accent)' : 'var(--text-secondary)',
|
||||
background: active === item.id ? 'var(--accent-muted)' : 'transparent',
|
||||
border: 'none', cursor: 'pointer',
|
||||
transition: 'all var(--transition-fast)',
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div>
|
||||
<Section id="quickstart" title="Quick Start" icon={<LinkIcon size={20} />}>
|
||||
<P>Get from zero to a shared link in under 30 seconds.</P>
|
||||
<H3>1. Go to the upload page</H3>
|
||||
<P>Navigate to <Inline>/upload</Inline> or click <strong>Start Sharing</strong> from the landing page.</P>
|
||||
<H3>2. Drop your file</H3>
|
||||
<P>Drag a file into the drop zone or click to browse. Files up to 500 MB are supported on the Pro plan, 100 MB on Free.</P>
|
||||
<H3>3. Copy your link</H3>
|
||||
<P>Once the upload completes, click <strong>Share</strong> to generate a time-limited link, then copy it to your clipboard.</P>
|
||||
</Section>
|
||||
|
||||
<Section id="uploading" title="Uploading Files" icon={<UploadIcon size={20} />}>
|
||||
<P>CShare accepts any file type. There are no format restrictions — PDF, ZIP, PNG, video, executables, design files — everything works.</P>
|
||||
<H3>Size limits</H3>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px', marginBottom: '16px' }}>
|
||||
{[['Free', '100 MB per file'], ['Pro', '500 MB per file'], ['Team', '500 MB per file'], ['Enterprise', 'Custom']].map(([plan, limit]) => (
|
||||
<div key={plan} className="card" style={{ padding: '14px 18px' }}>
|
||||
<div style={{ fontSize: '0.75rem', color: 'var(--text-muted)', fontFamily: 'var(--font-heading)', fontWeight: 600, letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: '4px' }}>{plan}</div>
|
||||
<div style={{ fontFamily: 'var(--font-heading)', fontWeight: 700, color: 'var(--text-primary)' }}>{limit}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<H3>Multi-file uploads</H3>
|
||||
<P>You can select multiple files at once. Each gets its own independent share link and expiry. Use <strong>Share All</strong> to generate links for all files in one click.</P>
|
||||
</Section>
|
||||
|
||||
<Section id="sharing" title="Share Links" icon={<LinkIcon size={20} />}>
|
||||
<P>Every uploaded file gets a unique, unguessable link in the format:</P>
|
||||
<Code>https://cshare.app/preview/{'<random-id>'}</Code>
|
||||
<P style={{ marginTop: '16px' }}>Links do not require the recipient to have a CShare account. Anyone with the link can view and download the file until it expires.</P>
|
||||
<H3>Password protection <span style={{ fontSize: '0.75rem', color: 'var(--accent)', background: 'var(--accent-muted)', padding: '2px 8px', borderRadius: '999px', marginLeft: '8px' }}>Pro</span></H3>
|
||||
<P>On Pro and Team plans, you can set an optional password on any link. Recipients will be prompted to enter it before downloading.</P>
|
||||
</Section>
|
||||
|
||||
<Section id="expiry" title="Link Expiry" icon={<ClockIcon size={20} />}>
|
||||
<P>All links expire automatically. Once expired, the file is permanently deleted and the link returns a 404.</P>
|
||||
<H3>Default expiry windows</H3>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px', marginBottom: '16px' }}>
|
||||
{[['Free', '7 days (fixed)'], ['Pro', '1 hour → 90 days (your choice)'], ['Team', '1 hour → 90 days (your choice)']].map(([plan, window]) => (
|
||||
<div key={plan} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px 16px', background: 'var(--bg-surface)', border: '1px solid var(--border-subtle)', borderRadius: 'var(--radius-md)', fontSize: '0.875rem' }}>
|
||||
<span style={{ fontFamily: 'var(--font-heading)', fontWeight: 600 }}>{plan}</span>
|
||||
<span style={{ color: 'var(--text-secondary)' }}>{window}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<P>Expiry is enforced server-side at request time — no client-side tricks.</P>
|
||||
</Section>
|
||||
|
||||
<Section id="analytics" title="Analytics" icon={<ChartIcon size={20} />}>
|
||||
<P>The dashboard tracks views (link opens) and downloads per file in real time.</P>
|
||||
<H3>What counts as a view</H3>
|
||||
<P>A view is recorded each time the share page is loaded. Refreshes by the same session are deduplicated.</P>
|
||||
<H3>What counts as a download</H3>
|
||||
<P>A download is recorded when the file transfer completes successfully on the recipient's end.</P>
|
||||
</Section>
|
||||
|
||||
<Section id="api" title="API Reference" icon={<LinkIcon size={20} />}>
|
||||
<P>The REST API is available on Pro and Team plans. Authenticate with a bearer token from your account settings.</P>
|
||||
<H3>Upload a file</H3>
|
||||
<Code>{`POST /api/v1/files/upload
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
{
|
||||
"file": <binary>,
|
||||
"expiresIn": 86400 // seconds (optional, default 30 days)
|
||||
}`}</Code>
|
||||
<H3>List your files</H3>
|
||||
<Code>{`GET /api/v1/files
|
||||
Authorization: Bearer <token>
|
||||
|
||||
// Response
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"id": "a7k2m9x",
|
||||
"name": "report.pdf",
|
||||
"size": 2458624,
|
||||
"link": "https://cshare.app/preview/a7k2m9x",
|
||||
"expires_at": "2026-06-25T10:30:00Z",
|
||||
"views": 142,
|
||||
"downloads": 38
|
||||
}
|
||||
]
|
||||
}`}</Code>
|
||||
<H3>Delete a file</H3>
|
||||
<Code>{`DELETE /api/v1/files/:id
|
||||
Authorization: Bearer <token>
|
||||
|
||||
// 204 No Content on success`}</Code>
|
||||
</Section>
|
||||
|
||||
<Section id="faq" title="FAQ" icon={<ShieldIcon size={20} />}>
|
||||
{[
|
||||
['Is my data encrypted?', 'Yes. Files are encrypted in transit (TLS 1.3) and at rest (AES-256). Only someone with the link can access the file.'],
|
||||
['Can I delete a file before it expires?', 'Yes. From your dashboard, click the delete icon next to any file to remove it and invalidate its link immediately.'],
|
||||
['What happens if I exceed my upload limit on Free?', "You'll see an error message. Upgrade to Pro for unlimited uploads."],
|
||||
['Do you store files after expiry?', 'No. Expired files are permanently deleted from storage within minutes of expiry. There is no recovery path.'],
|
||||
].map(([q, a]) => (
|
||||
<div key={q} style={{ marginBottom: '20px', padding: '20px', background: 'var(--bg-surface)', border: '1px solid var(--border-subtle)', borderRadius: 'var(--radius-md)' }}>
|
||||
<div style={{ fontFamily: 'var(--font-heading)', fontWeight: 600, marginBottom: '8px' }}>{q}</div>
|
||||
<p style={{ color: 'var(--text-secondary)', fontSize: '0.875rem', lineHeight: 1.7, margin: 0 }}>{a}</p>
|
||||
</div>
|
||||
))}
|
||||
</Section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user