Added (all now linked from their live locations): - home_root/.claude/settings.json. The statusLine command now uses $HOME instead of a Linux-only absolute path. - home_root/.claude/bin/ratecheck and home_root/.claude/skills/australis-design. - home_config/zsh/claude-config-dir.zsh and home_root/.local/bin/claude-config-dir-init, the per-repo Claude Code login helper and its seeding script. - home_root/.gitconfig and home_config/git/ignore. - home_root/.zshenv, with the cargo env line guarded so boxes without rust start clean. link-dotfiles --check reports drift without changing anything: tracked files whose live copy is no longer a link (stow dry-run conflicts) and links into this repo that dangle. Exits 1 on drift. Verified against a clean baseline and two planted drifts, a detached .nanorc and a dangling link. .mailmap maps every earlier identity to Vuong Hoang: the repo-local 'Your Name' placeholder config (now removed), host-generated emails, and aider suffixes. CLAUDE.md: the symlink warning now lists every linked file and points at --check. README: documents what is and isn't tracked under .claude, the edit rule, and --check.
89 lines
2.4 KiB
React
89 lines
2.4 KiB
React
// Terminal — bottom panel, prompt + scrollback.
|
|
|
|
const Terminal = ({ lines, onCommand }) => {
|
|
const [input, setInput] = React.useState('');
|
|
const scrollRef = React.useRef(null);
|
|
|
|
React.useEffect(() => {
|
|
if (scrollRef.current) {
|
|
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
}
|
|
}, [lines]);
|
|
|
|
const submit = (e) => {
|
|
e.preventDefault();
|
|
if (!input.trim()) return;
|
|
onCommand(input);
|
|
setInput('');
|
|
};
|
|
|
|
return (
|
|
<div style={tmStyles.root}>
|
|
<div style={tmStyles.head}>
|
|
<Icon name="terminal" size={13} style={{ color:'#42dcd1' }}/>
|
|
<span style={tmStyles.title}>terminal · zsh</span>
|
|
<span style={tmStyles.spacer}/>
|
|
<span style={tmStyles.host}>aurora ~/projects/australis</span>
|
|
</div>
|
|
<div ref={scrollRef} style={tmStyles.body}>
|
|
{lines.map((ln, i) => (
|
|
<div key={i} style={tmStyles.line}
|
|
dangerouslySetInnerHTML={{ __html: ln }}/>
|
|
))}
|
|
<form onSubmit={submit} style={tmStyles.promptRow}>
|
|
<span style={tmStyles.prompt}>➜</span>
|
|
<input
|
|
value={input}
|
|
onChange={e => setInput(e.target.value)}
|
|
placeholder="try: build, deploy, theme, help"
|
|
style={tmStyles.input}
|
|
autoFocus
|
|
/>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const tmStyles = {
|
|
root: {
|
|
height: 220, flex: '0 0 220px',
|
|
background: '#1b1e28',
|
|
borderTop: '1px solid #373b46',
|
|
display: 'flex', flexDirection: 'column',
|
|
},
|
|
head: {
|
|
display: 'flex', alignItems: 'center', gap: 8,
|
|
padding: '6px 14px',
|
|
background: '#222531',
|
|
borderBottom: '1px solid #373b46',
|
|
fontFamily: 'var(--font-mono)', fontSize: 11,
|
|
color: 'var(--fg-3)',
|
|
letterSpacing: '0.04em',
|
|
},
|
|
title: { color: 'var(--fg-2)' },
|
|
spacer: { flex: 1 },
|
|
host: { color: 'var(--fg-3)' },
|
|
body: {
|
|
flex: 1, overflowY: 'auto',
|
|
padding: '10px 18px 14px',
|
|
fontFamily: 'var(--font-mono)', fontSize: 13,
|
|
lineHeight: 1.65,
|
|
color: 'var(--fg-1)',
|
|
},
|
|
line: { whiteSpace: 'pre-wrap' },
|
|
promptRow: {
|
|
display: 'flex', alignItems: 'center', gap: 8,
|
|
marginTop: 2,
|
|
},
|
|
prompt: { color: '#42dcd1' },
|
|
input: {
|
|
flex: 1, background: 'transparent', border: 0, outline: 'none',
|
|
fontFamily: 'var(--font-mono)', fontSize: 13,
|
|
color: 'var(--fg-0)',
|
|
caretColor: '#42dcd1',
|
|
},
|
|
};
|
|
|
|
window.Terminal = Terminal;
|