@cedros/data-react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +177 -0
- package/dist/admin/api.d.ts +19 -0
- package/dist/admin/api.js +108 -0
- package/dist/admin/components.d.ts +36 -0
- package/dist/admin/components.js +22 -0
- package/dist/admin/history.d.ts +17 -0
- package/dist/admin/history.js +103 -0
- package/dist/admin/icons.d.ts +15 -0
- package/dist/admin/icons.js +18 -0
- package/dist/admin/index.d.ts +13 -0
- package/dist/admin/index.js +12 -0
- package/dist/admin/permissions.d.ts +4 -0
- package/dist/admin/permissions.js +45 -0
- package/dist/admin/plugin.d.ts +4 -0
- package/dist/admin/plugin.js +180 -0
- package/dist/admin/primitives/ConfirmDialog.d.ts +14 -0
- package/dist/admin/primitives/ConfirmDialog.js +7 -0
- package/dist/admin/primitives/DataTable.d.ts +14 -0
- package/dist/admin/primitives/DataTable.js +7 -0
- package/dist/admin/primitives/DiffViewer.d.ts +11 -0
- package/dist/admin/primitives/DiffViewer.js +8 -0
- package/dist/admin/primitives/FormFieldRow.d.ts +23 -0
- package/dist/admin/primitives/FormFieldRow.js +16 -0
- package/dist/admin/primitives/JsonCodeEditor.d.ts +10 -0
- package/dist/admin/primitives/JsonCodeEditor.js +42 -0
- package/dist/admin/primitives/Pagination.d.ts +8 -0
- package/dist/admin/primitives/Pagination.js +8 -0
- package/dist/admin/primitives/Toolbar.d.ts +23 -0
- package/dist/admin/primitives/Toolbar.js +10 -0
- package/dist/admin/primitives/alerts.d.ts +21 -0
- package/dist/admin/primitives/alerts.js +44 -0
- package/dist/admin/sectionIds.d.ts +20 -0
- package/dist/admin/sectionIds.js +33 -0
- package/dist/admin/sections/CollectionsSection.d.ts +2 -0
- package/dist/admin/sections/CollectionsSection.js +125 -0
- package/dist/admin/sections/ContractVerifySection.d.ts +11 -0
- package/dist/admin/sections/ContractVerifySection.js +98 -0
- package/dist/admin/sections/CustomDataSection.d.ts +2 -0
- package/dist/admin/sections/CustomDataSection.js +256 -0
- package/dist/admin/sections/DataOpsSection.d.ts +26 -0
- package/dist/admin/sections/DataOpsSection.js +245 -0
- package/dist/admin/sections/HistorySection.d.ts +2 -0
- package/dist/admin/sections/HistorySection.js +26 -0
- package/dist/admin/sections/MonetizationSection.d.ts +2 -0
- package/dist/admin/sections/MonetizationSection.js +140 -0
- package/dist/admin/sections/NavigationSection.d.ts +13 -0
- package/dist/admin/sections/NavigationSection.js +195 -0
- package/dist/admin/sections/PagesSection.d.ts +2 -0
- package/dist/admin/sections/PagesSection.js +157 -0
- package/dist/admin/sections/SchemaDesignerSection.d.ts +2 -0
- package/dist/admin/sections/SchemaDesignerSection.js +167 -0
- package/dist/admin/sections/SiteSettingsSection.d.ts +12 -0
- package/dist/admin/sections/SiteSettingsSection.js +122 -0
- package/dist/admin/sections/TippingSection.d.ts +2 -0
- package/dist/admin/sections/TippingSection.js +178 -0
- package/dist/admin/sections/media/MediaDetail.d.ts +12 -0
- package/dist/admin/sections/media/MediaDetail.js +74 -0
- package/dist/admin/sections/media/MediaGrid.d.ts +14 -0
- package/dist/admin/sections/media/MediaGrid.js +22 -0
- package/dist/admin/sections/media/MediaSection.d.ts +2 -0
- package/dist/admin/sections/media/MediaSection.js +97 -0
- package/dist/admin/sections/media/MediaUploader.d.ts +7 -0
- package/dist/admin/sections/media/MediaUploader.js +72 -0
- package/dist/admin/sections/media/types.d.ts +33 -0
- package/dist/admin/sections/media/types.js +1 -0
- package/dist/admin/styles.css +533 -0
- package/dist/admin/types.d.ts +85 -0
- package/dist/admin/types.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/react/CmsContent.d.ts +20 -0
- package/dist/react/CmsContent.js +31 -0
- package/dist/react/entries.d.ts +9 -0
- package/dist/react/entries.js +25 -0
- package/dist/react/fetch.d.ts +11 -0
- package/dist/react/fetch.js +32 -0
- package/dist/react/index.d.ts +10 -0
- package/dist/react/index.js +9 -0
- package/dist/react/metadata.d.ts +44 -0
- package/dist/react/metadata.js +142 -0
- package/dist/react/sanitize.d.ts +17 -0
- package/dist/react/sanitize.js +326 -0
- package/dist/react/server.d.ts +14 -0
- package/dist/react/server.js +13 -0
- package/dist/react/sitemap.d.ts +28 -0
- package/dist/react/sitemap.js +91 -0
- package/dist/react/slugs.d.ts +27 -0
- package/dist/react/slugs.js +52 -0
- package/dist/react/types.d.ts +85 -0
- package/dist/react/types.js +1 -0
- package/dist/react/visitor.d.ts +7 -0
- package/dist/react/visitor.js +18 -0
- package/dist/site-templates/BlogTemplates.d.ts +95 -0
- package/dist/site-templates/BlogTemplates.js +64 -0
- package/dist/site-templates/ContactPageTemplate.d.ts +14 -0
- package/dist/site-templates/ContactPageTemplate.js +5 -0
- package/dist/site-templates/DashboardOverviewTemplate.d.ts +29 -0
- package/dist/site-templates/DashboardOverviewTemplate.js +17 -0
- package/dist/site-templates/DashboardShell.d.ts +28 -0
- package/dist/site-templates/DashboardShell.js +10 -0
- package/dist/site-templates/DocsSidebar.d.ts +14 -0
- package/dist/site-templates/DocsSidebar.js +13 -0
- package/dist/site-templates/DocsTemplates.d.ts +60 -0
- package/dist/site-templates/DocsTemplates.js +47 -0
- package/dist/site-templates/HomePageTemplate.d.ts +15 -0
- package/dist/site-templates/HomePageTemplate.js +10 -0
- package/dist/site-templates/LegalPageTemplate.d.ts +12 -0
- package/dist/site-templates/LegalPageTemplate.js +6 -0
- package/dist/site-templates/MarkdownContent.d.ts +7 -0
- package/dist/site-templates/MarkdownContent.js +24 -0
- package/dist/site-templates/NotFoundTemplate.d.ts +9 -0
- package/dist/site-templates/NotFoundTemplate.js +5 -0
- package/dist/site-templates/SiteFooter.d.ts +13 -0
- package/dist/site-templates/SiteFooter.js +4 -0
- package/dist/site-templates/SiteLayout.d.ts +14 -0
- package/dist/site-templates/SiteLayout.js +6 -0
- package/dist/site-templates/TopNav.d.ts +10 -0
- package/dist/site-templates/TopNav.js +8 -0
- package/dist/site-templates/blogControls.d.ts +19 -0
- package/dist/site-templates/blogControls.js +37 -0
- package/dist/site-templates/codeBlock.d.ts +9 -0
- package/dist/site-templates/codeBlock.js +31 -0
- package/dist/site-templates/content-styles.css +410 -0
- package/dist/site-templates/contentIndex.d.ts +65 -0
- package/dist/site-templates/contentIndex.js +181 -0
- package/dist/site-templates/contentUi.d.ts +14 -0
- package/dist/site-templates/contentUi.js +24 -0
- package/dist/site-templates/docs-styles.css +259 -0
- package/dist/site-templates/docsNavigation.d.ts +18 -0
- package/dist/site-templates/docsNavigation.js +50 -0
- package/dist/site-templates/index.d.ts +28 -0
- package/dist/site-templates/index.js +25 -0
- package/dist/site-templates/monetization-styles.css +154 -0
- package/dist/site-templates/paywallControls.d.ts +22 -0
- package/dist/site-templates/paywallControls.js +9 -0
- package/dist/site-templates/routing.d.ts +12 -0
- package/dist/site-templates/routing.js +36 -0
- package/dist/site-templates/solanaAtaSetup.d.ts +11 -0
- package/dist/site-templates/solanaAtaSetup.js +38 -0
- package/dist/site-templates/solanaMicropayments.d.ts +65 -0
- package/dist/site-templates/solanaMicropayments.js +115 -0
- package/dist/site-templates/styles.css +332 -0
- package/dist/site-templates/tipControls.d.ts +24 -0
- package/dist/site-templates/tipControls.js +43 -0
- package/dist/site-templates/tocExtractor.d.ts +16 -0
- package/dist/site-templates/tocExtractor.js +58 -0
- package/dist/site-templates/tocScrollSpy.d.ts +16 -0
- package/dist/site-templates/tocScrollSpy.js +37 -0
- package/dist/templates.d.ts +8 -0
- package/dist/templates.js +20 -0
- package/package.json +58 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { TipCurrency, TipPayClient } from "./tipControls.js";
|
|
2
|
+
/** Minimal Phantom/Solflare wallet interface — avoids external @types dep. */
|
|
3
|
+
interface SolanaWallet {
|
|
4
|
+
isConnected: boolean;
|
|
5
|
+
publicKey: {
|
|
6
|
+
toBuffer(): Uint8Array;
|
|
7
|
+
toString(): string;
|
|
8
|
+
} | null;
|
|
9
|
+
connect(): Promise<{
|
|
10
|
+
publicKey: {
|
|
11
|
+
toString(): string;
|
|
12
|
+
};
|
|
13
|
+
}>;
|
|
14
|
+
signAndSendTransaction(tx: unknown): Promise<{
|
|
15
|
+
signature: string;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
declare global {
|
|
19
|
+
interface Window {
|
|
20
|
+
solana?: SolanaWallet;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Returns true when a Solana wallet extension is detected in the browser. */
|
|
24
|
+
export declare function detectSolanaWallet(): boolean;
|
|
25
|
+
export declare const SOL_CURRENCY: TipCurrency;
|
|
26
|
+
export declare const USDC_CURRENCY: TipCurrency;
|
|
27
|
+
export interface SolanaMicropaymentsProps {
|
|
28
|
+
/** Solana wallet address that receives tips. */
|
|
29
|
+
recipient: string;
|
|
30
|
+
/** Preset tip amounts in SOL (used when `currencies` is not provided). */
|
|
31
|
+
presets?: number[];
|
|
32
|
+
/** Solana RPC endpoint. Defaults to mainnet-beta. */
|
|
33
|
+
rpcEndpoint?: string;
|
|
34
|
+
/** Label above the tip widget. */
|
|
35
|
+
label?: string;
|
|
36
|
+
/** Description text below the label. */
|
|
37
|
+
description?: string;
|
|
38
|
+
/** Available tip currencies. Defaults to SOL-only. */
|
|
39
|
+
currencies?: TipCurrency[];
|
|
40
|
+
/** Per-currency preset amounts. Overrides `presets` when provided. */
|
|
41
|
+
currencyPresets?: Record<string, number[]>;
|
|
42
|
+
/** When set, forces SOL-only tipping to this address (per-author tips). */
|
|
43
|
+
recipientOverride?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates a TipPayClient that sends SOL or SPL token transfers via
|
|
47
|
+
* the connected Solana wallet extension (Phantom, Solflare, etc.).
|
|
48
|
+
*
|
|
49
|
+
* Branches on `currency.mint`:
|
|
50
|
+
* - No mint → native SOL transfer via SystemProgram
|
|
51
|
+
* - Has mint → SPL token transfer via @solana/spl-token
|
|
52
|
+
*
|
|
53
|
+
* @param rpcEndpoint - Optional RPC URL, defaults to mainnet-beta
|
|
54
|
+
* @returns TipPayClient implementation
|
|
55
|
+
*/
|
|
56
|
+
export declare function createSolanaTipClient(rpcEndpoint?: string): TipPayClient;
|
|
57
|
+
/**
|
|
58
|
+
* Renders a TipWidget for Solana tips (SOL and/or SPL tokens).
|
|
59
|
+
*
|
|
60
|
+
* - Auto-detects wallet presence via `useEffect`; renders nothing when absent.
|
|
61
|
+
* - When `recipientOverride` is set, forces SOL-only tipping to override address.
|
|
62
|
+
* - Lazily creates the pay client on first render.
|
|
63
|
+
*/
|
|
64
|
+
export declare function SolanaMicropayments({ recipient, presets, rpcEndpoint, label, description, currencies, currencyPresets, recipientOverride, }: SolanaMicropaymentsProps): React.JSX.Element | null;
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { TipWidget } from "./tipControls.js";
|
|
5
|
+
/** Returns true when a Solana wallet extension is detected in the browser. */
|
|
6
|
+
export function detectSolanaWallet() {
|
|
7
|
+
return typeof window !== "undefined" && !!window.solana;
|
|
8
|
+
}
|
|
9
|
+
export const SOL_CURRENCY = {
|
|
10
|
+
symbol: "SOL",
|
|
11
|
+
decimals: 9,
|
|
12
|
+
logo: "",
|
|
13
|
+
};
|
|
14
|
+
export const USDC_CURRENCY = {
|
|
15
|
+
symbol: "USDC",
|
|
16
|
+
decimals: 6,
|
|
17
|
+
logo: "",
|
|
18
|
+
mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
19
|
+
};
|
|
20
|
+
const DEFAULT_RPC = "https://api.mainnet-beta.solana.com";
|
|
21
|
+
/**
|
|
22
|
+
* Creates a TipPayClient that sends SOL or SPL token transfers via
|
|
23
|
+
* the connected Solana wallet extension (Phantom, Solflare, etc.).
|
|
24
|
+
*
|
|
25
|
+
* Branches on `currency.mint`:
|
|
26
|
+
* - No mint → native SOL transfer via SystemProgram
|
|
27
|
+
* - Has mint → SPL token transfer via @solana/spl-token
|
|
28
|
+
*
|
|
29
|
+
* @param rpcEndpoint - Optional RPC URL, defaults to mainnet-beta
|
|
30
|
+
* @returns TipPayClient implementation
|
|
31
|
+
*/
|
|
32
|
+
export function createSolanaTipClient(rpcEndpoint = DEFAULT_RPC) {
|
|
33
|
+
return {
|
|
34
|
+
async sendTip(params) {
|
|
35
|
+
const wallet = window.solana;
|
|
36
|
+
if (!wallet)
|
|
37
|
+
throw new Error("No Solana wallet detected");
|
|
38
|
+
if (!wallet.isConnected) {
|
|
39
|
+
await wallet.connect();
|
|
40
|
+
}
|
|
41
|
+
if (!wallet.publicKey)
|
|
42
|
+
throw new Error("Wallet not connected");
|
|
43
|
+
if (params.currency.mint) {
|
|
44
|
+
await sendSplTransfer(wallet, rpcEndpoint, params);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
await sendSolTransfer(wallet, rpcEndpoint, params);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async function sendSolTransfer(wallet, rpcEndpoint, { amount, recipient }) {
|
|
53
|
+
const { Connection, PublicKey, SystemProgram, Transaction } = await import("@solana/web3.js");
|
|
54
|
+
const connection = new Connection(rpcEndpoint, "confirmed");
|
|
55
|
+
const lamports = Math.round(amount * 1e9);
|
|
56
|
+
const tx = new Transaction().add(SystemProgram.transfer({
|
|
57
|
+
fromPubkey: new PublicKey(wallet.publicKey.toString()),
|
|
58
|
+
toPubkey: new PublicKey(recipient),
|
|
59
|
+
lamports,
|
|
60
|
+
}));
|
|
61
|
+
tx.feePayer = new PublicKey(wallet.publicKey.toString());
|
|
62
|
+
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
|
|
63
|
+
const { signature } = await wallet.signAndSendTransaction(tx);
|
|
64
|
+
await connection.confirmTransaction(signature, "confirmed");
|
|
65
|
+
}
|
|
66
|
+
async function sendSplTransfer(wallet, rpcEndpoint, { amount, recipient, currency }) {
|
|
67
|
+
const { Connection, PublicKey, Transaction } = await import("@solana/web3.js");
|
|
68
|
+
const { getAssociatedTokenAddress, createTransferInstruction } = await import("@solana/spl-token");
|
|
69
|
+
const connection = new Connection(rpcEndpoint, "confirmed");
|
|
70
|
+
const mintPubkey = new PublicKey(currency.mint);
|
|
71
|
+
const senderPubkey = new PublicKey(wallet.publicKey.toString());
|
|
72
|
+
const recipientPubkey = new PublicKey(recipient);
|
|
73
|
+
const senderAta = await getAssociatedTokenAddress(mintPubkey, senderPubkey);
|
|
74
|
+
const recipientAta = await getAssociatedTokenAddress(mintPubkey, recipientPubkey);
|
|
75
|
+
// Verify recipient ATA exists — admin must pre-create it
|
|
76
|
+
const recipientInfo = await connection.getAccountInfo(recipientAta);
|
|
77
|
+
if (!recipientInfo) {
|
|
78
|
+
throw new Error(`Recipient does not have a ${currency.symbol} token account. ` +
|
|
79
|
+
`The site admin must create it before accepting ${currency.symbol} tips.`);
|
|
80
|
+
}
|
|
81
|
+
const tokenAmount = Math.round(amount * 10 ** currency.decimals);
|
|
82
|
+
const tx = new Transaction().add(createTransferInstruction(senderAta, recipientAta, senderPubkey, tokenAmount));
|
|
83
|
+
tx.feePayer = senderPubkey;
|
|
84
|
+
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
|
|
85
|
+
const { signature } = await wallet.signAndSendTransaction(tx);
|
|
86
|
+
await connection.confirmTransaction(signature, "confirmed");
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Renders a TipWidget for Solana tips (SOL and/or SPL tokens).
|
|
90
|
+
*
|
|
91
|
+
* - Auto-detects wallet presence via `useEffect`; renders nothing when absent.
|
|
92
|
+
* - When `recipientOverride` is set, forces SOL-only tipping to override address.
|
|
93
|
+
* - Lazily creates the pay client on first render.
|
|
94
|
+
*/
|
|
95
|
+
export function SolanaMicropayments({ recipient, presets = [0.01, 0.05, 0.1], rpcEndpoint, label = "Tip with SOL", description, currencies, currencyPresets, recipientOverride, }) {
|
|
96
|
+
const [hasWallet, setHasWallet] = useState(false);
|
|
97
|
+
const [client, setClient] = useState(null);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (detectSolanaWallet()) {
|
|
100
|
+
setHasWallet(true);
|
|
101
|
+
setClient(createSolanaTipClient(rpcEndpoint));
|
|
102
|
+
}
|
|
103
|
+
}, [rpcEndpoint]);
|
|
104
|
+
if (!hasWallet || !client)
|
|
105
|
+
return null;
|
|
106
|
+
// Per-author override: force SOL-only
|
|
107
|
+
const effectiveRecipient = recipientOverride ?? recipient;
|
|
108
|
+
const effectiveCurrencies = recipientOverride
|
|
109
|
+
? [SOL_CURRENCY]
|
|
110
|
+
: (currencies ?? [SOL_CURRENCY]);
|
|
111
|
+
const effectivePresets = recipientOverride
|
|
112
|
+
? { SOL: presets }
|
|
113
|
+
: (currencyPresets ?? { SOL: presets });
|
|
114
|
+
return (_jsx(TipWidget, { recipient: effectiveRecipient, currencies: effectiveCurrencies, presets: effectivePresets, payClient: client, label: recipientOverride ? "Tip the author" : label, description: description }));
|
|
115
|
+
}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
@import "./content-styles.css";
|
|
2
|
+
|
|
3
|
+
.cedros-site {
|
|
4
|
+
--cds-bg: var(--cedros-background, #ffffff);
|
|
5
|
+
--cds-fg: var(--cedros-foreground, #0f172a);
|
|
6
|
+
--cds-muted: var(--cedros-muted-foreground, #64748b);
|
|
7
|
+
--cds-muted-bg: var(--cedros-muted, #f1f5f9);
|
|
8
|
+
--cds-border: var(--cedros-border, #e2e8f0);
|
|
9
|
+
--cds-link: var(--cedros-link, #2563eb);
|
|
10
|
+
--cds-primary: var(--cedros-primary, #0f172a);
|
|
11
|
+
--cds-primary-fg: var(--cedros-primary-foreground, #f8fafc);
|
|
12
|
+
--cds-radius: var(--cedros-radius, 0.5rem);
|
|
13
|
+
--cds-shadow: 0 1px 2px rgb(0 0 0 / 0.05);
|
|
14
|
+
color: var(--cds-fg);
|
|
15
|
+
background: var(--cds-bg);
|
|
16
|
+
min-height: 100%;
|
|
17
|
+
font-family:
|
|
18
|
+
ui-sans-serif,
|
|
19
|
+
system-ui,
|
|
20
|
+
-apple-system,
|
|
21
|
+
BlinkMacSystemFont,
|
|
22
|
+
"Segoe UI",
|
|
23
|
+
Roboto,
|
|
24
|
+
"Helvetica Neue",
|
|
25
|
+
Arial,
|
|
26
|
+
sans-serif;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.cedros-dark .cedros-site {
|
|
30
|
+
--cds-bg: hsl(222.2, 84%, 4.9%);
|
|
31
|
+
--cds-fg: hsl(210, 40%, 98%);
|
|
32
|
+
--cds-muted: hsl(215, 20.2%, 65.1%);
|
|
33
|
+
--cds-muted-bg: hsl(217.2, 32.6%, 17.5%);
|
|
34
|
+
--cds-border: hsl(217.2, 32.6%, 17.5%);
|
|
35
|
+
--cds-link: hsl(217.2, 91.2%, 59.8%);
|
|
36
|
+
--cds-primary: hsl(210, 40%, 98%);
|
|
37
|
+
--cds-primary-fg: hsl(222.2, 47.4%, 11.2%);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.cedros-site__container {
|
|
41
|
+
width: min(1080px, 100%);
|
|
42
|
+
margin: 0 auto;
|
|
43
|
+
padding: 0 1rem;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.cedros-site__header {
|
|
47
|
+
border-bottom: 1px solid var(--cds-border);
|
|
48
|
+
background: color-mix(in srgb, var(--cds-bg) 90%, var(--cds-muted-bg) 10%);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.cedros-site__header-inner {
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
gap: 1rem;
|
|
55
|
+
min-height: 4rem;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.cedros-site__brand {
|
|
59
|
+
font-size: 1rem;
|
|
60
|
+
font-weight: 700;
|
|
61
|
+
text-decoration: none;
|
|
62
|
+
color: var(--cds-fg);
|
|
63
|
+
letter-spacing: -0.02em;
|
|
64
|
+
flex-shrink: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.cedros-site__nav {
|
|
68
|
+
display: flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
flex-wrap: wrap;
|
|
71
|
+
gap: 0.5rem;
|
|
72
|
+
margin-left: auto;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.cedros-site__nav-link {
|
|
76
|
+
display: inline-flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
border: 1px solid transparent;
|
|
79
|
+
border-radius: calc(var(--cds-radius) - 2px);
|
|
80
|
+
padding: 0.45rem 0.65rem;
|
|
81
|
+
color: var(--cds-muted);
|
|
82
|
+
text-decoration: none;
|
|
83
|
+
font-size: 0.85rem;
|
|
84
|
+
transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.cedros-site__nav-link:hover {
|
|
88
|
+
color: var(--cds-fg);
|
|
89
|
+
background: var(--cds-muted-bg);
|
|
90
|
+
border-color: var(--cds-border);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.cedros-site__nav-link--active {
|
|
94
|
+
color: var(--cds-fg);
|
|
95
|
+
background: color-mix(in srgb, var(--cds-link) 9%, var(--cds-muted-bg) 91%);
|
|
96
|
+
border-color: color-mix(in srgb, var(--cds-link) 55%, var(--cds-border) 45%);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.cedros-site__nav-link--disabled {
|
|
100
|
+
pointer-events: none;
|
|
101
|
+
opacity: 0.5;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.cedros-site__header-right {
|
|
105
|
+
display: inline-flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap: 0.45rem;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.cedros-site__main {
|
|
111
|
+
padding: 1.5rem 0 2.4rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.cedros-site__footer {
|
|
115
|
+
border-top: 1px solid var(--cds-border);
|
|
116
|
+
background: color-mix(in srgb, var(--cds-bg) 90%, var(--cds-muted-bg) 10%);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.cedros-site__footer-inner {
|
|
120
|
+
min-height: 3.2rem;
|
|
121
|
+
display: flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
justify-content: flex-start;
|
|
124
|
+
gap: 0.9rem;
|
|
125
|
+
color: var(--cds-muted);
|
|
126
|
+
font-size: 0.8rem;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.cedros-site__footer-brand {
|
|
130
|
+
display: inline-flex;
|
|
131
|
+
align-items: center;
|
|
132
|
+
flex-wrap: wrap;
|
|
133
|
+
gap: 0.7rem;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.cedros-site__footer-links {
|
|
137
|
+
display: inline-flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
gap: 0.6rem;
|
|
140
|
+
margin-left: auto;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.cedros-site__footer-link {
|
|
144
|
+
text-decoration: none;
|
|
145
|
+
color: var(--cds-muted);
|
|
146
|
+
border-bottom: 1px solid transparent;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.cedros-site__footer-link:hover {
|
|
150
|
+
color: var(--cds-fg);
|
|
151
|
+
border-bottom-color: color-mix(in srgb, var(--cds-border) 80%, transparent);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.cedros-site__footer-right {
|
|
155
|
+
margin-left: auto;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.cedros-site__card {
|
|
159
|
+
border: 1px solid var(--cds-border);
|
|
160
|
+
border-radius: var(--cds-radius);
|
|
161
|
+
background: color-mix(in srgb, var(--cds-bg) 94%, var(--cds-muted-bg) 6%);
|
|
162
|
+
box-shadow: var(--cds-shadow);
|
|
163
|
+
padding: 1rem;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.cedros-site__title {
|
|
167
|
+
margin: 0;
|
|
168
|
+
font-size: clamp(1.4rem, 3vw, 2.2rem);
|
|
169
|
+
line-height: 1.1;
|
|
170
|
+
letter-spacing: -0.03em;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.cedros-site__subtitle {
|
|
174
|
+
margin: 0.8rem 0 0;
|
|
175
|
+
color: var(--cds-muted);
|
|
176
|
+
max-width: 72ch;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.cedros-site a {
|
|
180
|
+
color: var(--cds-link);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.cedros-site__pill {
|
|
184
|
+
display: inline-flex;
|
|
185
|
+
align-items: center;
|
|
186
|
+
border-radius: 999px;
|
|
187
|
+
border: 1px solid var(--cds-border);
|
|
188
|
+
background: var(--cds-muted-bg);
|
|
189
|
+
color: var(--cds-muted);
|
|
190
|
+
padding: 0.18rem 0.48rem;
|
|
191
|
+
font-size: 0.72rem;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.cedros-site-dashboard__layout {
|
|
195
|
+
display: grid;
|
|
196
|
+
grid-template-columns: minmax(220px, 250px) minmax(0, 1fr);
|
|
197
|
+
gap: 1rem;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.cedros-site-dashboard__sidebar {
|
|
201
|
+
display: grid;
|
|
202
|
+
align-content: start;
|
|
203
|
+
gap: 0.8rem;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.cedros-site-dashboard__profile {
|
|
207
|
+
display: grid;
|
|
208
|
+
gap: 0.3rem;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.cedros-site-dashboard__profile-name {
|
|
212
|
+
margin: 0;
|
|
213
|
+
font-size: 0.95rem;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.cedros-site-dashboard__profile-email {
|
|
217
|
+
margin: 0;
|
|
218
|
+
font-size: 0.78rem;
|
|
219
|
+
color: var(--cds-muted);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.cedros-site-dashboard__side-nav {
|
|
223
|
+
display: grid;
|
|
224
|
+
gap: 0.45rem;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.cedros-site-dashboard__side-link {
|
|
228
|
+
border: 1px solid var(--cds-border);
|
|
229
|
+
border-radius: calc(var(--cds-radius) - 1px);
|
|
230
|
+
background: color-mix(in srgb, var(--cds-bg) 94%, var(--cds-muted-bg) 6%);
|
|
231
|
+
color: var(--cds-fg);
|
|
232
|
+
text-decoration: none;
|
|
233
|
+
padding: 0.55rem 0.65rem;
|
|
234
|
+
display: grid;
|
|
235
|
+
gap: 0.2rem;
|
|
236
|
+
font-size: 0.82rem;
|
|
237
|
+
transition: border-color 130ms ease, background 130ms ease;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.cedros-site-dashboard__side-link:hover {
|
|
241
|
+
border-color: color-mix(in srgb, var(--cds-border) 60%, var(--cds-link) 40%);
|
|
242
|
+
background: color-mix(in srgb, var(--cds-muted-bg) 86%, transparent);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.cedros-site-dashboard__side-link--active {
|
|
246
|
+
border-color: color-mix(in srgb, var(--cds-link) 60%, var(--cds-border) 40%);
|
|
247
|
+
background: color-mix(in srgb, var(--cds-link) 10%, var(--cds-muted-bg) 90%);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.cedros-site-dashboard__side-description {
|
|
251
|
+
color: var(--cds-muted);
|
|
252
|
+
font-size: 0.72rem;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.cedros-site-dashboard__badge {
|
|
256
|
+
justify-self: start;
|
|
257
|
+
border: 1px solid var(--cds-border);
|
|
258
|
+
border-radius: 999px;
|
|
259
|
+
padding: 0.08rem 0.4rem;
|
|
260
|
+
font-size: 0.7rem;
|
|
261
|
+
color: var(--cds-muted);
|
|
262
|
+
background: color-mix(in srgb, var(--cds-muted-bg) 92%, transparent);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.cedros-site-dashboard__content {
|
|
266
|
+
min-width: 0;
|
|
267
|
+
display: grid;
|
|
268
|
+
gap: 0.8rem;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.cedros-site-dashboard__content-header {
|
|
272
|
+
display: flex;
|
|
273
|
+
align-items: flex-start;
|
|
274
|
+
justify-content: space-between;
|
|
275
|
+
gap: 0.8rem;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.cedros-site-dashboard__title {
|
|
279
|
+
font-size: clamp(1.2rem, 2.2vw, 1.75rem);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.cedros-site-dashboard__actions {
|
|
283
|
+
display: inline-flex;
|
|
284
|
+
align-items: center;
|
|
285
|
+
gap: 0.45rem;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.cedros-site-dashboard__panel {
|
|
289
|
+
min-width: 0;
|
|
290
|
+
display: grid;
|
|
291
|
+
gap: 0.9rem;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
@media (max-width: 900px) {
|
|
295
|
+
.cedros-site-dashboard__layout {
|
|
296
|
+
grid-template-columns: 1fr;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.cedros-site-dashboard__side-nav {
|
|
300
|
+
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
@media (max-width: 700px) {
|
|
305
|
+
.cedros-site__header-inner {
|
|
306
|
+
min-height: auto;
|
|
307
|
+
padding: 0.8rem 0;
|
|
308
|
+
flex-wrap: wrap;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.cedros-site__nav {
|
|
312
|
+
margin-left: 0;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.cedros-site__header-right {
|
|
316
|
+
margin-left: auto;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.cedros-site__footer-inner {
|
|
320
|
+
min-height: auto;
|
|
321
|
+
padding: 0.75rem 0;
|
|
322
|
+
flex-wrap: wrap;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.cedros-site__footer-links {
|
|
326
|
+
margin-left: 0;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.cedros-site__footer-right {
|
|
330
|
+
margin-left: 0;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface TipCurrency {
|
|
2
|
+
symbol: string;
|
|
3
|
+
decimals: number;
|
|
4
|
+
logo: string;
|
|
5
|
+
mint?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface TipParams {
|
|
8
|
+
currency: TipCurrency;
|
|
9
|
+
amount: number;
|
|
10
|
+
recipient: string;
|
|
11
|
+
}
|
|
12
|
+
/** Provided by @cedros/pay-react (or any compatible implementation). */
|
|
13
|
+
export interface TipPayClient {
|
|
14
|
+
sendTip(params: TipParams): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export interface TipWidgetProps {
|
|
17
|
+
recipient: string;
|
|
18
|
+
currencies: TipCurrency[];
|
|
19
|
+
presets?: Record<string, number[]>;
|
|
20
|
+
payClient: TipPayClient;
|
|
21
|
+
label?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function TipWidget({ recipient, currencies, presets, payClient, label, description }: TipWidgetProps): React.JSX.Element;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
4
|
+
export function TipWidget({ recipient, currencies, presets, payClient, label = "Leave a tip", description }) {
|
|
5
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
6
|
+
const [amount, setAmount] = useState("");
|
|
7
|
+
const [status, setStatus] = useState("idle");
|
|
8
|
+
const [errorMessage, setErrorMessage] = useState("");
|
|
9
|
+
const selectedCurrency = currencies[selectedIndex] ?? currencies[0];
|
|
10
|
+
const currentPresets = selectedCurrency ? presets?.[selectedCurrency.symbol] : undefined;
|
|
11
|
+
const handleSubmit = useCallback(async () => {
|
|
12
|
+
if (!selectedCurrency)
|
|
13
|
+
return;
|
|
14
|
+
const numericAmount = parseFloat(amount);
|
|
15
|
+
if (!numericAmount || numericAmount <= 0)
|
|
16
|
+
return;
|
|
17
|
+
setStatus("loading");
|
|
18
|
+
setErrorMessage("");
|
|
19
|
+
try {
|
|
20
|
+
await payClient.sendTip({ currency: selectedCurrency, amount: numericAmount, recipient });
|
|
21
|
+
setStatus("success");
|
|
22
|
+
setAmount("");
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
26
|
+
setStatus("error");
|
|
27
|
+
setErrorMessage(error.message);
|
|
28
|
+
}
|
|
29
|
+
}, [selectedCurrency, amount, payClient, recipient]);
|
|
30
|
+
if (!selectedCurrency)
|
|
31
|
+
return _jsx("div", { className: "cedros-site__tip-widget" });
|
|
32
|
+
return (_jsxs("div", { className: "cedros-site__tip-widget", children: [_jsx("h3", { className: "cedros-site__tip-title", children: label }), description && _jsx("p", { className: "cedros-site__tip-description", children: description }), currencies.length > 1 && (_jsx("select", { className: "cedros-site__tip-currency", value: selectedIndex, onChange: (e) => {
|
|
33
|
+
setSelectedIndex(Number(e.target.value));
|
|
34
|
+
setAmount("");
|
|
35
|
+
setStatus("idle");
|
|
36
|
+
}, children: currencies.map((c, i) => (_jsx("option", { value: i, children: c.symbol }, c.symbol))) })), currentPresets && currentPresets.length > 0 && (_jsx("div", { className: "cedros-site__tip-presets", children: currentPresets.map((presetAmount) => (_jsxs("button", { type: "button", className: "cedros-site__pill", onClick: () => {
|
|
37
|
+
setAmount(String(presetAmount));
|
|
38
|
+
setStatus("idle");
|
|
39
|
+
}, children: [presetAmount, " ", selectedCurrency.symbol] }, presetAmount))) })), _jsx("div", { className: "cedros-site__tip-amount", children: _jsx("input", { type: "number", min: "0", step: "any", placeholder: `Amount in ${selectedCurrency.symbol}`, value: amount, onChange: (e) => {
|
|
40
|
+
setAmount(e.target.value);
|
|
41
|
+
setStatus("idle");
|
|
42
|
+
} }) }), _jsx("button", { type: "button", className: "cedros-site__tip-submit", disabled: status === "loading" || !amount || parseFloat(amount) <= 0, onClick: () => void handleSubmit(), children: status === "loading" ? "Sending..." : "Send Tip" }), status === "success" && (_jsx("p", { className: "cedros-site__tip-status cedros-site__tip-status--success", children: "Tip sent successfully!" })), status === "error" && (_jsx("p", { className: "cedros-site__tip-status cedros-site__tip-status--error", children: errorMessage || "Failed to send tip." }))] }));
|
|
43
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface TocEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
depth: 2 | 3 | 4;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Extracts a table-of-contents from raw markdown.
|
|
8
|
+
*
|
|
9
|
+
* Walks top-level heading nodes (h2–h4), slugifies the text content to
|
|
10
|
+
* produce `id` values matching `rehype-slug` output, and returns entries
|
|
11
|
+
* compatible with the `DocArticleTemplate` `toc` prop.
|
|
12
|
+
*
|
|
13
|
+
* @param markdown - Raw markdown string
|
|
14
|
+
* @returns Array of TOC entries ordered by document position
|
|
15
|
+
*/
|
|
16
|
+
export declare function extractTocFromMarkdown(markdown: string): TocEntry[];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { unified } from "unified";
|
|
2
|
+
import remarkParse from "remark-parse";
|
|
3
|
+
/**
|
|
4
|
+
* Extracts a table-of-contents from raw markdown.
|
|
5
|
+
*
|
|
6
|
+
* Walks top-level heading nodes (h2–h4), slugifies the text content to
|
|
7
|
+
* produce `id` values matching `rehype-slug` output, and returns entries
|
|
8
|
+
* compatible with the `DocArticleTemplate` `toc` prop.
|
|
9
|
+
*
|
|
10
|
+
* @param markdown - Raw markdown string
|
|
11
|
+
* @returns Array of TOC entries ordered by document position
|
|
12
|
+
*/
|
|
13
|
+
export function extractTocFromMarkdown(markdown) {
|
|
14
|
+
if (!markdown || markdown.trim().length === 0)
|
|
15
|
+
return [];
|
|
16
|
+
const tree = unified().use(remarkParse).parse(markdown);
|
|
17
|
+
const entries = [];
|
|
18
|
+
for (const node of tree.children) {
|
|
19
|
+
if (node.type !== "heading")
|
|
20
|
+
continue;
|
|
21
|
+
const depth = node.depth;
|
|
22
|
+
if (depth < 2 || depth > 4)
|
|
23
|
+
continue;
|
|
24
|
+
const label = extractHeadingText(node);
|
|
25
|
+
if (!label)
|
|
26
|
+
continue;
|
|
27
|
+
entries.push({
|
|
28
|
+
id: slugify(label),
|
|
29
|
+
label,
|
|
30
|
+
depth: depth,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return entries;
|
|
34
|
+
}
|
|
35
|
+
/** Recursively extract plain text from a mdast node. */
|
|
36
|
+
function extractHeadingText(node) {
|
|
37
|
+
if (!node.children)
|
|
38
|
+
return "";
|
|
39
|
+
return node.children
|
|
40
|
+
.map((child) => {
|
|
41
|
+
if (child.type === "text")
|
|
42
|
+
return child.value ?? "";
|
|
43
|
+
if (child.type === "inlineCode")
|
|
44
|
+
return child.value ?? "";
|
|
45
|
+
if (child.children)
|
|
46
|
+
return extractHeadingText(child);
|
|
47
|
+
return "";
|
|
48
|
+
})
|
|
49
|
+
.join("");
|
|
50
|
+
}
|
|
51
|
+
/** Slugify matching rehype-slug behavior: lowercase, spaces→hyphens, strip punctuation. */
|
|
52
|
+
function slugify(text) {
|
|
53
|
+
return text
|
|
54
|
+
.toLowerCase()
|
|
55
|
+
.replace(/[^\w\s-]/g, "")
|
|
56
|
+
.replace(/\s+/g, "-")
|
|
57
|
+
.replace(/^-+|-+$/g, "");
|
|
58
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface TocScrollSpyProps {
|
|
2
|
+
/** TOC entries with their heading IDs. */
|
|
3
|
+
entries: Array<{
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
depth?: 2 | 3 | 4;
|
|
7
|
+
}>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Client-side scroll-spy TOC component.
|
|
11
|
+
*
|
|
12
|
+
* Uses IntersectionObserver to highlight the current section heading.
|
|
13
|
+
* Renders the same link structure as the static TOC in DocArticleTemplate
|
|
14
|
+
* but adds `cedros-site__toc-link--active` to the visible heading.
|
|
15
|
+
*/
|
|
16
|
+
export declare function TocScrollSpy({ entries }: TocScrollSpyProps): React.JSX.Element;
|