@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.
Files changed (152) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +177 -0
  3. package/dist/admin/api.d.ts +19 -0
  4. package/dist/admin/api.js +108 -0
  5. package/dist/admin/components.d.ts +36 -0
  6. package/dist/admin/components.js +22 -0
  7. package/dist/admin/history.d.ts +17 -0
  8. package/dist/admin/history.js +103 -0
  9. package/dist/admin/icons.d.ts +15 -0
  10. package/dist/admin/icons.js +18 -0
  11. package/dist/admin/index.d.ts +13 -0
  12. package/dist/admin/index.js +12 -0
  13. package/dist/admin/permissions.d.ts +4 -0
  14. package/dist/admin/permissions.js +45 -0
  15. package/dist/admin/plugin.d.ts +4 -0
  16. package/dist/admin/plugin.js +180 -0
  17. package/dist/admin/primitives/ConfirmDialog.d.ts +14 -0
  18. package/dist/admin/primitives/ConfirmDialog.js +7 -0
  19. package/dist/admin/primitives/DataTable.d.ts +14 -0
  20. package/dist/admin/primitives/DataTable.js +7 -0
  21. package/dist/admin/primitives/DiffViewer.d.ts +11 -0
  22. package/dist/admin/primitives/DiffViewer.js +8 -0
  23. package/dist/admin/primitives/FormFieldRow.d.ts +23 -0
  24. package/dist/admin/primitives/FormFieldRow.js +16 -0
  25. package/dist/admin/primitives/JsonCodeEditor.d.ts +10 -0
  26. package/dist/admin/primitives/JsonCodeEditor.js +42 -0
  27. package/dist/admin/primitives/Pagination.d.ts +8 -0
  28. package/dist/admin/primitives/Pagination.js +8 -0
  29. package/dist/admin/primitives/Toolbar.d.ts +23 -0
  30. package/dist/admin/primitives/Toolbar.js +10 -0
  31. package/dist/admin/primitives/alerts.d.ts +21 -0
  32. package/dist/admin/primitives/alerts.js +44 -0
  33. package/dist/admin/sectionIds.d.ts +20 -0
  34. package/dist/admin/sectionIds.js +33 -0
  35. package/dist/admin/sections/CollectionsSection.d.ts +2 -0
  36. package/dist/admin/sections/CollectionsSection.js +125 -0
  37. package/dist/admin/sections/ContractVerifySection.d.ts +11 -0
  38. package/dist/admin/sections/ContractVerifySection.js +98 -0
  39. package/dist/admin/sections/CustomDataSection.d.ts +2 -0
  40. package/dist/admin/sections/CustomDataSection.js +256 -0
  41. package/dist/admin/sections/DataOpsSection.d.ts +26 -0
  42. package/dist/admin/sections/DataOpsSection.js +245 -0
  43. package/dist/admin/sections/HistorySection.d.ts +2 -0
  44. package/dist/admin/sections/HistorySection.js +26 -0
  45. package/dist/admin/sections/MonetizationSection.d.ts +2 -0
  46. package/dist/admin/sections/MonetizationSection.js +140 -0
  47. package/dist/admin/sections/NavigationSection.d.ts +13 -0
  48. package/dist/admin/sections/NavigationSection.js +195 -0
  49. package/dist/admin/sections/PagesSection.d.ts +2 -0
  50. package/dist/admin/sections/PagesSection.js +157 -0
  51. package/dist/admin/sections/SchemaDesignerSection.d.ts +2 -0
  52. package/dist/admin/sections/SchemaDesignerSection.js +167 -0
  53. package/dist/admin/sections/SiteSettingsSection.d.ts +12 -0
  54. package/dist/admin/sections/SiteSettingsSection.js +122 -0
  55. package/dist/admin/sections/TippingSection.d.ts +2 -0
  56. package/dist/admin/sections/TippingSection.js +178 -0
  57. package/dist/admin/sections/media/MediaDetail.d.ts +12 -0
  58. package/dist/admin/sections/media/MediaDetail.js +74 -0
  59. package/dist/admin/sections/media/MediaGrid.d.ts +14 -0
  60. package/dist/admin/sections/media/MediaGrid.js +22 -0
  61. package/dist/admin/sections/media/MediaSection.d.ts +2 -0
  62. package/dist/admin/sections/media/MediaSection.js +97 -0
  63. package/dist/admin/sections/media/MediaUploader.d.ts +7 -0
  64. package/dist/admin/sections/media/MediaUploader.js +72 -0
  65. package/dist/admin/sections/media/types.d.ts +33 -0
  66. package/dist/admin/sections/media/types.js +1 -0
  67. package/dist/admin/styles.css +533 -0
  68. package/dist/admin/types.d.ts +85 -0
  69. package/dist/admin/types.js +1 -0
  70. package/dist/index.d.ts +4 -0
  71. package/dist/index.js +3 -0
  72. package/dist/react/CmsContent.d.ts +20 -0
  73. package/dist/react/CmsContent.js +31 -0
  74. package/dist/react/entries.d.ts +9 -0
  75. package/dist/react/entries.js +25 -0
  76. package/dist/react/fetch.d.ts +11 -0
  77. package/dist/react/fetch.js +32 -0
  78. package/dist/react/index.d.ts +10 -0
  79. package/dist/react/index.js +9 -0
  80. package/dist/react/metadata.d.ts +44 -0
  81. package/dist/react/metadata.js +142 -0
  82. package/dist/react/sanitize.d.ts +17 -0
  83. package/dist/react/sanitize.js +326 -0
  84. package/dist/react/server.d.ts +14 -0
  85. package/dist/react/server.js +13 -0
  86. package/dist/react/sitemap.d.ts +28 -0
  87. package/dist/react/sitemap.js +91 -0
  88. package/dist/react/slugs.d.ts +27 -0
  89. package/dist/react/slugs.js +52 -0
  90. package/dist/react/types.d.ts +85 -0
  91. package/dist/react/types.js +1 -0
  92. package/dist/react/visitor.d.ts +7 -0
  93. package/dist/react/visitor.js +18 -0
  94. package/dist/site-templates/BlogTemplates.d.ts +95 -0
  95. package/dist/site-templates/BlogTemplates.js +64 -0
  96. package/dist/site-templates/ContactPageTemplate.d.ts +14 -0
  97. package/dist/site-templates/ContactPageTemplate.js +5 -0
  98. package/dist/site-templates/DashboardOverviewTemplate.d.ts +29 -0
  99. package/dist/site-templates/DashboardOverviewTemplate.js +17 -0
  100. package/dist/site-templates/DashboardShell.d.ts +28 -0
  101. package/dist/site-templates/DashboardShell.js +10 -0
  102. package/dist/site-templates/DocsSidebar.d.ts +14 -0
  103. package/dist/site-templates/DocsSidebar.js +13 -0
  104. package/dist/site-templates/DocsTemplates.d.ts +60 -0
  105. package/dist/site-templates/DocsTemplates.js +47 -0
  106. package/dist/site-templates/HomePageTemplate.d.ts +15 -0
  107. package/dist/site-templates/HomePageTemplate.js +10 -0
  108. package/dist/site-templates/LegalPageTemplate.d.ts +12 -0
  109. package/dist/site-templates/LegalPageTemplate.js +6 -0
  110. package/dist/site-templates/MarkdownContent.d.ts +7 -0
  111. package/dist/site-templates/MarkdownContent.js +24 -0
  112. package/dist/site-templates/NotFoundTemplate.d.ts +9 -0
  113. package/dist/site-templates/NotFoundTemplate.js +5 -0
  114. package/dist/site-templates/SiteFooter.d.ts +13 -0
  115. package/dist/site-templates/SiteFooter.js +4 -0
  116. package/dist/site-templates/SiteLayout.d.ts +14 -0
  117. package/dist/site-templates/SiteLayout.js +6 -0
  118. package/dist/site-templates/TopNav.d.ts +10 -0
  119. package/dist/site-templates/TopNav.js +8 -0
  120. package/dist/site-templates/blogControls.d.ts +19 -0
  121. package/dist/site-templates/blogControls.js +37 -0
  122. package/dist/site-templates/codeBlock.d.ts +9 -0
  123. package/dist/site-templates/codeBlock.js +31 -0
  124. package/dist/site-templates/content-styles.css +410 -0
  125. package/dist/site-templates/contentIndex.d.ts +65 -0
  126. package/dist/site-templates/contentIndex.js +181 -0
  127. package/dist/site-templates/contentUi.d.ts +14 -0
  128. package/dist/site-templates/contentUi.js +24 -0
  129. package/dist/site-templates/docs-styles.css +259 -0
  130. package/dist/site-templates/docsNavigation.d.ts +18 -0
  131. package/dist/site-templates/docsNavigation.js +50 -0
  132. package/dist/site-templates/index.d.ts +28 -0
  133. package/dist/site-templates/index.js +25 -0
  134. package/dist/site-templates/monetization-styles.css +154 -0
  135. package/dist/site-templates/paywallControls.d.ts +22 -0
  136. package/dist/site-templates/paywallControls.js +9 -0
  137. package/dist/site-templates/routing.d.ts +12 -0
  138. package/dist/site-templates/routing.js +36 -0
  139. package/dist/site-templates/solanaAtaSetup.d.ts +11 -0
  140. package/dist/site-templates/solanaAtaSetup.js +38 -0
  141. package/dist/site-templates/solanaMicropayments.d.ts +65 -0
  142. package/dist/site-templates/solanaMicropayments.js +115 -0
  143. package/dist/site-templates/styles.css +332 -0
  144. package/dist/site-templates/tipControls.d.ts +24 -0
  145. package/dist/site-templates/tipControls.js +43 -0
  146. package/dist/site-templates/tocExtractor.d.ts +16 -0
  147. package/dist/site-templates/tocExtractor.js +58 -0
  148. package/dist/site-templates/tocScrollSpy.d.ts +16 -0
  149. package/dist/site-templates/tocScrollSpy.js +37 -0
  150. package/dist/templates.d.ts +8 -0
  151. package/dist/templates.js +20 -0
  152. 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;