Add Obsidian Toolbox — 4 syntax generators under /tools
Inside-LMS toolbox for registered students: callout-CSS, YAML-frontmatter, theme CSS-variables, Style Settings generators. Auth inherited from (student) route group; no public surface, no email gate. - Pure generators in src/lib/tools/* with Vitest (33 tests) - Shared YAML-safe scalar quoter (_shared/yaml.ts) used by frontmatter + style-settings: unquoted user input was silently breaking YAML (tags '#x' -> null, color default '#7C3AED' -> null, 'a: b' -> parse error) - hex validation in callout (no NaN), date input constrained, clipboard + analytics calls guarded - Prisma ToolUsage model + migration; logToolUsage Server Action (auth-first, 10-min dedup window per user/tool) - Tool index /tools + ToolCard (explicit lucide map, no import *) + header link Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
import { Copy, Check } from "lucide-react";
|
||||
import { logToolUsage } from "@/lib/actions/tool-usage";
|
||||
import type { ToolId } from "@/lib/tools/_shared/types";
|
||||
|
||||
export function CopyButton({ text, tool }: { text: string; tool: ToolId }) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
async function onCopy() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
} catch {
|
||||
return; // буфер недоступен (нет разрешения / insecure context) — молча
|
||||
}
|
||||
setCopied(true);
|
||||
logToolUsage({ tool }).catch(() => {}); // аналитика — best-effort, не роняем UI
|
||||
setTimeout(() => setCopied(false), 1500);
|
||||
}
|
||||
return (
|
||||
<button type="button" onClick={onCopy} className="btn-aubade btn-aubade-accent inline-flex items-center gap-2 text-sm">
|
||||
{copied ? <Check size={16} /> : <Copy size={16} />}
|
||||
{copied ? "Скопировано" : "Скопировать"}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user