Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.

Commit 25c4ad0

Browse files
committed
docs: clean up the prompt headers and componentize them
1 parent 4c77f3a commit 25c4ad0

File tree

9 files changed

+365
-213
lines changed

9 files changed

+365
-213
lines changed
Lines changed: 38 additions & 213 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,40 @@
1-
import React, { useState, useEffect } from 'react';
2-
import { Container, Paper, Box, Button, Typography, Tabs, Tab, Link as MuiLink, Tooltip, IconButton, Snackbar, Grid, Accordion, AccordionSummary, AccordionDetails, Modal } from '@mui/material';
1+
import React, { useState } from 'react';
2+
import { Container, Paper, Box, Button, Typography, Link as MuiLink, Snackbar, IconButton, Grid, Accordion, AccordionSummary, AccordionDetails } from '@mui/material';
33
import { ThemeProvider } from '@mui/material/styles';
4-
import DescriptionIcon from '@mui/icons-material/Description';
5-
import LibraryBooksIcon from '@mui/icons-material/LibraryBooks';
6-
import BlockIcon from '@mui/icons-material/Block';
7-
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
8-
import DownloadIcon from '@mui/icons-material/Download';
94
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
105
import CloseIcon from '@mui/icons-material/Close';
116
import GitHubIcon from '@mui/icons-material/GitHub';
12-
import { BrowserRouter as Router, Routes, Route, Link, useLocation } from 'react-router-dom';
7+
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
138
import theme from './theme';
149
import ContextForm from './components/ContextForm';
1510
import ContextDocsForm from './components/ContextDocsForm';
1611
import ContextIgnoreForm from './components/ContextIgnoreForm';
12+
import PromptViewer from './components/PromptViewer';
13+
import NavTabs from './components/NavTabs';
14+
import SpecificationModal from './components/SpecificationModal';
15+
import ActionButtons from './components/ActionButtons';
16+
import { handleCopyToClipboard, handleDownload } from './utils/helpers';
17+
import usePrompts from './hooks/usePrompts';
18+
import useSnackbar from './hooks/useSnackbar';
1719
import './App.css';
1820

1921
// Conditional base path for GitHub Pages
2022
const BASE_PATH = process.env.NODE_ENV === 'production' ? '/codebase-context-spec' : '';
2123

22-
const PromptViewer: React.FC<{ title: string, content: string, onCopy: () => void }> = ({ title, content, onCopy }) => {
23-
return (
24-
<Box mb={2}>
25-
<Box display="flex" justifyContent="space-between" alignItems="center" mb={1}>
26-
<Typography variant="h6">{title}</Typography>
27-
<Button startIcon={<ContentCopyIcon />} onClick={onCopy}>
28-
Copy
29-
</Button>
30-
</Box>
31-
<Box className="code-preview" style={{ maxHeight: '300px', overflow: 'auto' }}>
32-
<pre style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>
33-
{content}
34-
</pre>
35-
</Box>
36-
</Box>
37-
);
38-
};
39-
40-
const SpecificationViewer: React.FC<{ content: string, onCopy: () => void }> = ({ content, onCopy }) => {
41-
return (
42-
<Box height="100%" display="flex" flexDirection="column">
43-
<Box display="flex" justifyContent="flex-end" mb={2}>
44-
<Button startIcon={<ContentCopyIcon />} onClick={onCopy}>
45-
Copy Specification
46-
</Button>
47-
</Box>
48-
<Box flexGrow={1} overflow="auto">
49-
<pre style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word', margin: 0 }}>
50-
{content}
51-
</pre>
52-
</Box>
53-
</Box>
54-
);
55-
};
56-
5724
const App: React.FC = () => {
5825
const [generatedContent, setGeneratedContent] = useState('');
59-
const [snackbarOpen, setSnackbarOpen] = useState(false);
60-
const [snackbarMessage, setSnackbarMessage] = useState('');
61-
const [codebaseContextContent, setCodebaseContextContent] = useState('');
62-
const [codingAssistantPromptContent, setCodingAssistantPromptContent] = useState('');
63-
const [generateContextPromptContent, setGenerateContextPromptContent] = useState('');
6426
const [specModalOpen, setSpecModalOpen] = useState(false);
6527

66-
useEffect(() => {
67-
const fetchPrompts = async () => {
68-
try {
69-
const [codebaseContext, codingAssistantPrompt, generateContextPrompt] = await Promise.all([
70-
fetch('https://raw.githubusercontent.com/Agentic-Insights/codebase-context-spec/main/CODEBASE-CONTEXT.md').then(res => res.text()),
71-
fetch('https://raw.githubusercontent.com/Agentic-Insights/codebase-context-spec/main/CODING-ASSISTANT-PROMPT.md').then(res => res.text()),
72-
fetch('https://raw.githubusercontent.com/Agentic-Insights/codebase-context-spec/main/GENERATE-CONTEXT-PROMPT.md').then(res => res.text())
73-
]);
74-
75-
setCodebaseContextContent(codebaseContext);
76-
setCodingAssistantPromptContent(codingAssistantPrompt);
77-
setGenerateContextPromptContent(generateContextPrompt);
78-
} catch (error) {
79-
console.error('Error fetching prompts:', error);
80-
setSnackbarMessage('Error fetching prompts');
81-
setSnackbarOpen(true);
82-
}
83-
};
84-
85-
fetchPrompts();
86-
}, []);
28+
const { snackbarOpen, snackbarMessage, showSnackbar, closeSnackbar } = useSnackbar();
29+
const { codebaseContext, generateContextPrompt, codingAssistantPrompt } = usePrompts(
30+
showSnackbar,
31+
(open: boolean) => open ? showSnackbar('') : closeSnackbar()
32+
);
8733

8834
const handleFormSubmit = (content: string) => {
8935
setGeneratedContent(content);
9036
};
9137

92-
const handleCopyToClipboard = (content: string) => {
93-
navigator.clipboard.writeText(content).then(() => {
94-
setSnackbarMessage('Copied to clipboard!');
95-
setSnackbarOpen(true);
96-
}, (err) => {
97-
console.error('Could not copy text: ', err);
98-
});
99-
};
100-
101-
const handleDownload = () => {
102-
const element = document.createElement('a');
103-
const file = new Blob([generatedContent], {type: 'text/plain'});
104-
element.href = URL.createObjectURL(file);
105-
element.download = 'generated_context.md';
106-
document.body.appendChild(element);
107-
element.click();
108-
document.body.removeChild(element);
109-
setSnackbarMessage('File downloaded!');
110-
setSnackbarOpen(true);
111-
};
112-
113-
const handleCloseSnackbar = (event?: React.SyntheticEvent | Event, reason?: string) => {
114-
if (reason === 'clickaway') {
115-
return;
116-
}
117-
setSnackbarOpen(false);
118-
};
119-
120-
const handleOpenSpecModal = () => {
121-
setSpecModalOpen(true);
122-
};
123-
124-
const handleCloseSpecModal = () => {
125-
setSpecModalOpen(false);
126-
};
127-
12838
return (
12939
<ThemeProvider theme={theme}>
13040
<Router basename={BASE_PATH}>
@@ -135,7 +45,7 @@ const App: React.FC = () => {
13545
Codebase Context Editor
13646
</Typography>
13747
<Box display="flex" alignItems="center">
138-
<Button variant="outlined" onClick={handleOpenSpecModal} sx={{ mr: 2 }}>
48+
<Button variant="outlined" onClick={() => setSpecModalOpen(true)} sx={{ mr: 2 }}>
13949
View Latest Specification
14050
</Button>
14151
<MuiLink href="https://github.com/Agentic-Insights/codebase-context-spec" target="_blank" rel="noopener noreferrer">
@@ -154,16 +64,20 @@ const App: React.FC = () => {
15464
<Grid container spacing={2}>
15565
<Grid item xs={12} md={6}>
15666
<PromptViewer
157-
title="CODING-ASSISTANT-PROMPT.md"
158-
content={codingAssistantPromptContent}
159-
onCopy={() => handleCopyToClipboard(codingAssistantPromptContent)}
67+
title="Generate Context Prompt"
68+
subtitle="GENERATE-CONTEXT-PROMPT.md"
69+
explanation={generateContextPrompt.explanation}
70+
content={generateContextPrompt.content}
71+
onCopy={() => handleCopyToClipboard(generateContextPrompt.content, showSnackbar, () => showSnackbar(''))}
16072
/>
16173
</Grid>
16274
<Grid item xs={12} md={6}>
16375
<PromptViewer
164-
title="GENERATE-CONTEXT-PROMPT.md"
165-
content={generateContextPromptContent}
166-
onCopy={() => handleCopyToClipboard(generateContextPromptContent)}
76+
title="Coding Assistant Prompt"
77+
subtitle="CODING-ASSISTANT-PROMPT.md"
78+
explanation={codingAssistantPrompt.explanation}
79+
content={codingAssistantPrompt.content}
80+
onCopy={() => handleCopyToClipboard(codingAssistantPrompt.content, showSnackbar, () => showSnackbar(''))}
16781
/>
16882
</Grid>
16983
</Grid>
@@ -177,66 +91,19 @@ const App: React.FC = () => {
17791
<Route path="/contextignore" element={<ContextIgnoreForm onSubmit={handleFormSubmit} />} />
17892
</Routes>
17993
</Box>
180-
<Box className="action-buttons">
181-
<Tooltip title="Copy to clipboard" arrow>
182-
<Button
183-
onClick={() => handleCopyToClipboard(generatedContent)}
184-
variant="contained"
185-
startIcon={<ContentCopyIcon />}
186-
disabled={!generatedContent}
187-
>
188-
Copy
189-
</Button>
190-
</Tooltip>
191-
<Tooltip title="Download file" arrow>
192-
<Button
193-
onClick={handleDownload}
194-
variant="contained"
195-
startIcon={<DownloadIcon />}
196-
disabled={!generatedContent}
197-
>
198-
Download
199-
</Button>
200-
</Tooltip>
201-
</Box>
94+
<ActionButtons
95+
generatedContent={generatedContent}
96+
onCopy={() => handleCopyToClipboard(generatedContent, showSnackbar, () => showSnackbar(''))}
97+
onDownload={() => handleDownload(generatedContent, 'generated_context.md', showSnackbar, () => showSnackbar(''))}
98+
/>
20299
</Paper>
203100

204-
<Modal
101+
<SpecificationModal
205102
open={specModalOpen}
206-
onClose={handleCloseSpecModal}
207-
aria-labelledby="spec-modal-title"
208-
>
209-
<Box
210-
sx={{
211-
position: 'absolute',
212-
top: '50%',
213-
left: '50%',
214-
transform: 'translate(-50%, -50%)',
215-
width: '80%',
216-
height: '80%',
217-
bgcolor: 'background.paper',
218-
boxShadow: 24,
219-
p: 4,
220-
display: 'flex',
221-
flexDirection: 'column',
222-
}}
223-
>
224-
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
225-
<Typography id="spec-modal-title" variant="h6" component="h2">
226-
Latest Specification (CODEBASE-CONTEXT.md)
227-
</Typography>
228-
<IconButton onClick={handleCloseSpecModal} size="small">
229-
<CloseIcon />
230-
</IconButton>
231-
</Box>
232-
<Box flexGrow={1} overflow="hidden">
233-
<SpecificationViewer
234-
content={codebaseContextContent}
235-
onCopy={() => handleCopyToClipboard(codebaseContextContent)}
236-
/>
237-
</Box>
238-
</Box>
239-
</Modal>
103+
onClose={() => setSpecModalOpen(false)}
104+
content={codebaseContext.content}
105+
onCopy={() => handleCopyToClipboard(codebaseContext.content, showSnackbar, () => showSnackbar(''))}
106+
/>
240107

241108
<Snackbar
242109
anchorOrigin={{
@@ -245,14 +112,14 @@ const App: React.FC = () => {
245112
}}
246113
open={snackbarOpen}
247114
autoHideDuration={2000}
248-
onClose={handleCloseSnackbar}
115+
onClose={closeSnackbar}
249116
message={snackbarMessage}
250117
action={
251118
<IconButton
252119
size="small"
253120
aria-label="close"
254121
color="inherit"
255-
onClick={handleCloseSnackbar}
122+
onClick={closeSnackbar}
256123
>
257124
<CloseIcon fontSize="small" />
258125
</IconButton>
@@ -264,46 +131,4 @@ const App: React.FC = () => {
264131
);
265132
};
266133

267-
const NavTabs: React.FC = () => {
268-
const location = useLocation();
269-
const currentForm = getCurrentForm(location.pathname);
270-
271-
return (
272-
<Tabs value={currentForm} aria-label="file type tabs" variant="fullWidth">
273-
<Tab
274-
icon={<DescriptionIcon />}
275-
label=".context.md"
276-
component={Link}
277-
to="/"
278-
sx={{ textTransform: 'lowercase' }}
279-
/>
280-
<Tab
281-
icon={<LibraryBooksIcon />}
282-
label=".contextdocs.md"
283-
component={Link}
284-
to="/contextdocs"
285-
sx={{ textTransform: 'lowercase' }}
286-
/>
287-
<Tab
288-
icon={<BlockIcon />}
289-
label=".contextignore"
290-
component={Link}
291-
to="/contextignore"
292-
sx={{ textTransform: 'lowercase' }}
293-
/>
294-
</Tabs>
295-
);
296-
};
297-
298-
const getCurrentForm = (pathname: string) => {
299-
switch (pathname) {
300-
case '/contextdocs':
301-
return 1;
302-
case '/contextignore':
303-
return 2;
304-
default:
305-
return 0;
306-
}
307-
};
308-
309134
export default App;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from 'react';
2+
import { Box, Button, Tooltip } from '@mui/material';
3+
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
4+
import DownloadIcon from '@mui/icons-material/Download';
5+
6+
interface ActionButtonsProps {
7+
generatedContent: string;
8+
onCopy: () => void;
9+
onDownload: () => void;
10+
}
11+
12+
const ActionButtons: React.FC<ActionButtonsProps> = ({ generatedContent, onCopy, onDownload }) => {
13+
return (
14+
<Box className="action-buttons">
15+
<Tooltip title="Copy to clipboard" arrow>
16+
<span>
17+
<Button
18+
onClick={onCopy}
19+
variant="contained"
20+
startIcon={<ContentCopyIcon />}
21+
disabled={!generatedContent}
22+
>
23+
Copy
24+
</Button>
25+
</span>
26+
</Tooltip>
27+
<Tooltip title="Download file" arrow>
28+
<span>
29+
<Button
30+
onClick={onDownload}
31+
variant="contained"
32+
startIcon={<DownloadIcon />}
33+
disabled={!generatedContent}
34+
>
35+
Download
36+
</Button>
37+
</span>
38+
</Tooltip>
39+
</Box>
40+
);
41+
};
42+
43+
export default ActionButtons;

0 commit comments

Comments
 (0)