Initial commit: NexusOS project + desktop theme baseline
Captures the known-good state after theme consolidation and consistency reconciliation: - NexusOS GTK/xfwm4/icon theme assets (assets/themes, management/Mint-Y-Nexus) - Tightened right-click menus, visible separators, no menu icons - assets/themes/install-theme.sh: idempotent restore of all wiring (symlinks, xfconf xsettings+xfwm4, GTK 3/4 settings.ini) - .gitignore excludes venv/ollama/models/runtime/db Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
export function Markdown({ content }) {
|
||||
if (!content) return null;
|
||||
|
||||
const blocks = [];
|
||||
const codeBlockRe = /```(\w*)\n?([\s\S]*?)```/g;
|
||||
let last = 0;
|
||||
let match;
|
||||
|
||||
while ((match = codeBlockRe.exec(content)) !== null) {
|
||||
if (match.index > last) {
|
||||
blocks.push({ type: "text", value: content.slice(last, match.index) });
|
||||
}
|
||||
blocks.push({ type: "code", lang: match[1], value: match[2] });
|
||||
last = match.index + match[0].length;
|
||||
}
|
||||
if (last < content.length) {
|
||||
blocks.push({ type: "text", value: content.slice(last) });
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ lineHeight: "1.6" }}>
|
||||
{blocks.map((block, i) =>
|
||||
block.type === "code" ? (
|
||||
<pre key={i} style={{
|
||||
background: "#0d0d0d",
|
||||
border: "1px solid #2a2a2a",
|
||||
borderRadius: "6px",
|
||||
padding: "0.75rem 1rem",
|
||||
overflowX: "auto",
|
||||
fontSize: "0.85rem",
|
||||
lineHeight: "1.5",
|
||||
margin: "0.5rem 0",
|
||||
fontFamily: "monospace",
|
||||
}}>
|
||||
<code>{block.value.trimEnd()}</code>
|
||||
</pre>
|
||||
) : (
|
||||
<TextBlock key={i} text={block.value} />
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TextBlock({ text }) {
|
||||
const lines = text.split("\n");
|
||||
const elements = [];
|
||||
let i = 0;
|
||||
|
||||
while (i < lines.length) {
|
||||
const line = lines[i];
|
||||
|
||||
// Heading
|
||||
const hMatch = line.match(/^(#{1,3})\s+(.+)/);
|
||||
if (hMatch) {
|
||||
const level = hMatch[1].length;
|
||||
const sizes = { 1: "1.2rem", 2: "1.05rem", 3: "0.95rem" };
|
||||
elements.push(
|
||||
<div key={i} style={{ fontWeight: "700", fontSize: sizes[level], margin: "0.6rem 0 0.2rem", color: "#fff" }}>
|
||||
{inlineMarkdown(hMatch[2])}
|
||||
</div>
|
||||
);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Unordered list
|
||||
if (/^[-*]\s+/.test(line)) {
|
||||
const items = [];
|
||||
while (i < lines.length && /^[-*]\s+/.test(lines[i])) {
|
||||
items.push(<li key={i}>{inlineMarkdown(lines[i].replace(/^[-*]\s+/, ""))}</li>);
|
||||
i++;
|
||||
}
|
||||
elements.push(<ul key={`ul-${i}`} style={{ paddingLeft: "1.25rem", margin: "0.25rem 0" }}>{items}</ul>);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ordered list
|
||||
if (/^\d+\.\s+/.test(line)) {
|
||||
const items = [];
|
||||
while (i < lines.length && /^\d+\.\s+/.test(lines[i])) {
|
||||
items.push(<li key={i}>{inlineMarkdown(lines[i].replace(/^\d+\.\s+/, ""))}</li>);
|
||||
i++;
|
||||
}
|
||||
elements.push(<ol key={`ol-${i}`} style={{ paddingLeft: "1.25rem", margin: "0.25rem 0" }}>{items}</ol>);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Horizontal rule
|
||||
if (/^---+$/.test(line.trim())) {
|
||||
elements.push(<hr key={i} style={{ border: "none", borderTop: "1px solid #333", margin: "0.5rem 0" }} />);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Empty line → small gap
|
||||
if (line.trim() === "") {
|
||||
elements.push(<div key={i} style={{ height: "0.4rem" }} />);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Regular paragraph line
|
||||
elements.push(<div key={i}>{inlineMarkdown(line)}</div>);
|
||||
i++;
|
||||
}
|
||||
|
||||
return <>{elements}</>;
|
||||
}
|
||||
|
||||
function inlineMarkdown(text) {
|
||||
const parts = [];
|
||||
const re = /(\*\*(.+?)\*\*|\*(.+?)\*|`([^`]+)`)/g;
|
||||
let last = 0;
|
||||
let m;
|
||||
|
||||
while ((m = re.exec(text)) !== null) {
|
||||
if (m.index > last) parts.push(text.slice(last, m.index));
|
||||
|
||||
if (m[2] !== undefined) {
|
||||
parts.push(<strong key={m.index}>{m[2]}</strong>);
|
||||
} else if (m[3] !== undefined) {
|
||||
parts.push(<em key={m.index}>{m[3]}</em>);
|
||||
} else if (m[4] !== undefined) {
|
||||
parts.push(
|
||||
<code key={m.index} style={{
|
||||
background: "#1e1e1e",
|
||||
border: "1px solid #333",
|
||||
borderRadius: "3px",
|
||||
padding: "0.1rem 0.35rem",
|
||||
fontSize: "0.85em",
|
||||
fontFamily: "monospace",
|
||||
}}>
|
||||
{m[4]}
|
||||
</code>
|
||||
);
|
||||
}
|
||||
last = m.index + m[0].length;
|
||||
}
|
||||
|
||||
if (last < text.length) parts.push(text.slice(last));
|
||||
return parts.length === 1 && typeof parts[0] === "string" ? parts[0] : parts;
|
||||
}
|
||||
Reference in New Issue
Block a user