"use client";
import { useCopyToClipboard } from "../hooks/useCopyToClipboard";
const CODE = `import TUIkit
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
VStack {
Text("Hello, TUIkit!")
.bold()
.foregroundColor(.cyan)
Button("Press me") {
// handle action
}
}
}
}
}`;
/** A Swift code block with copy-to-clipboard and minimal syntax highlighting. */
export default function CodePreview() {
const { copied, copy } = useCopyToClipboard();
return (
{/* Header bar */}
{/* Code content */}
);
}
/** Syntax highlight color palette — One Dark inspired. */
const HIGHLIGHT = {
comment: "#6a737d",
decorator: "#d19a66",
string: "#98c379",
modifier: "#61afef",
keyword: "#c678dd",
type: "#e5c07b",
} as const;
/** Minimal Swift syntax highlighter — no external dependency. */
function Highlight({ code }: { code: string }) {
const lines = code.split("\n");
return (
<>
{lines.map((line, lineIndex) => (
{tokenizeLine(line)}
{lineIndex < lines.length - 1 && "\n"}
))}
>
);
}
function tokenizeLine(line: string) {
// Comments take precedence
const commentMatch = line.match(/^(.*?)(\/\/.*)$/);
if (commentMatch) {
const [, before, comment] = commentMatch;
return (
<>
{tokenizeSegment(before)}
{comment}
>
);
}
return tokenizeSegment(line);
}
function tokenizeSegment(segment: string) {
// Build a combined regex for all token types
const combined =
/(@\w+)|("(?:[^"\\]|\\.)*")|(\.\w+)\(|\b(struct|var|some|func|import|let|return|if|else|for|in|while|switch|case|default|class|protocol|enum|init|self|true|false|nil|private|public|internal)\b|\b(App|Scene|WindowGroup|VStack|HStack|Text|Button|View|String|Int|Bool|Never)\b/g;
const parts: React.ReactNode[] = [];
let lastIndex = 0;
let match: RegExpExecArray | null;
// Reset pattern state
combined.lastIndex = 0;
while ((match = combined.exec(segment)) !== null) {
// Add text before match
if (match.index > lastIndex) {
parts.push(segment.slice(lastIndex, match.index));
}
if (match[1]) {
// Decorator (@main, @State)
parts.push(
{match[1]}
);
} else if (match[2]) {
// String literal
parts.push(
{match[2]}
);
} else if (match[3]) {
// Modifier (.bold, .foregroundColor) — add dot+name, then the ( back
parts.push(
{match[3]}
);
parts.push("(");
} else if (match[4]) {
// Keyword
parts.push(
{match[4]}
);
} else if (match[5]) {
// Type
parts.push(
{match[5]}
);
}
lastIndex = combined.lastIndex;
}
// Remaining text
if (lastIndex < segment.length) {
parts.push(segment.slice(lastIndex));
}
return <>{parts}>;
}