Skip to content

Commit 814bcab

Browse files
committed
server side theme rendering and minor fixes
1 parent 9096adc commit 814bcab

File tree

5 files changed

+58
-33
lines changed

5 files changed

+58
-33
lines changed

src/components/ThemeToggle.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@ export default function ThemeToggle() {
44
const [theme, setTheme] = useState<'light' | 'dark'>('light')
55

66
useEffect(() => {
7-
const storedTheme = localStorage.getItem('theme') as 'light' | 'dark' | null
8-
const initialTheme = storedTheme || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
7+
// Get theme from server-rendered class or localStorage
8+
const serverTheme = document.documentElement.className as 'light' | 'dark' | ''
9+
const storedTheme = localStorage.getItem('basic-memory-theme') as 'light' | 'dark' | null
10+
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
11+
12+
const initialTheme = serverTheme || storedTheme || systemTheme
913
setTheme(initialTheme)
10-
document.documentElement.classList.toggle('dark', initialTheme === 'dark')
14+
15+
// Ensure the class is applied
16+
document.documentElement.className = initialTheme
1117
}, [])
1218

1319
const toggleTheme = () => {
1420
const newTheme = theme === 'light' ? 'dark' : 'light'
1521
setTheme(newTheme)
16-
localStorage.setItem('theme', newTheme)
17-
document.documentElement.classList.toggle('dark', newTheme === 'dark')
22+
localStorage.setItem('basic-memory-theme', newTheme)
23+
document.documentElement.className = newTheme
1824
}
1925

2026
return (

src/layouts/Layout.astro

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,23 @@ const { title = 'Basic Memory', description = 'Basic Memory - Persistent memory
2121
<meta name="generator" content={Astro.generator} />
2222
<meta name="description" content={description} />
2323
<title>{!title || title === 'Basic Memory' ? 'Basic Memory' : `${title} - Basic Memory`}</title>
24+
25+
<!-- Theme initialization script - prevents flash of light mode -->
26+
<script is:inline>
27+
(function() {
28+
// Get theme from localStorage with fallback to system preference
29+
const savedTheme = localStorage.getItem('basic-memory-theme') || 'system';
30+
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
31+
const initialTheme = savedTheme === 'system' ? systemTheme : savedTheme;
32+
33+
// Apply theme immediately to prevent flashing
34+
document.documentElement.className = initialTheme;
35+
})();
36+
</script>
2437
</head>
2538
<body>
2639
<slot />
27-
40+
2841
<script>
2942
// Preserve sidebar scroll position
3043
document.addEventListener('click', (e) => {
@@ -48,23 +61,23 @@ const { title = 'Basic Memory', description = 'Basic Memory - Persistent memory
4861
document.addEventListener('click', (e) => {
4962
const trigger = (e.target as HTMLElement).closest('.accordion-trigger')
5063
if (!trigger) return
51-
64+
5265
const content = trigger.nextElementSibling as HTMLElement
5366
const icon = trigger.querySelector('.accordion-icon')
5467
const isOpen = trigger.getAttribute('data-state') === 'open'
55-
68+
5669
trigger.setAttribute('data-state', isOpen ? 'closed' : 'open')
5770
content.classList.toggle('hidden')
5871
icon?.classList.toggle('rotate-180')
5972
})
60-
73+
6174
// Code tabs functionality
6275
const codeTabs = document.querySelectorAll('.code-tabs')
63-
76+
6477
codeTabs.forEach(tabContainer => {
6578
const buttons = tabContainer.querySelectorAll('.tab-button')
6679
const contents = tabContainer.querySelectorAll('.tab-content')
67-
80+
6881
buttons.forEach((button, index) => {
6982
button.addEventListener('click', () => {
7083
// Update button states
@@ -77,7 +90,7 @@ const { title = 'Basic Memory', description = 'Basic Memory - Persistent memory
7790
btn.classList.add('text-gray-600', 'dark:text-gray-400')
7891
}
7992
})
80-
93+
8194
// Update content visibility
8295
contents.forEach((content, contentIndex) => {
8396
if (contentIndex === index) {
@@ -91,17 +104,17 @@ const { title = 'Basic Memory', description = 'Basic Memory - Persistent memory
91104
})
92105
})
93106
})
94-
107+
95108
// Add copy buttons to code blocks
96109
const codeBlocks = document.querySelectorAll('pre')
97110
codeBlocks.forEach(pre => {
98111
// Skip if already wrapped
99112
if (pre.parentElement?.classList.contains('code-block-wrapper')) return
100-
113+
101114
// Create wrapper
102115
const wrapper = document.createElement('div')
103116
wrapper.className = 'code-block-wrapper relative'
104-
117+
105118
// Create copy button
106119
const button = document.createElement('button')
107120
button.className = 'copy-button'
@@ -112,17 +125,17 @@ const { title = 'Basic Memory', description = 'Basic Memory - Persistent memory
112125
</svg>
113126
`
114127
button.setAttribute('aria-label', 'Copy code')
115-
128+
116129
// Wrap the pre element
117130
pre.parentNode?.insertBefore(wrapper, pre)
118131
wrapper.appendChild(pre)
119132
wrapper.appendChild(button)
120-
133+
121134
// Handle copy
122135
button.addEventListener('click', async () => {
123136
const code = pre.querySelector('code')
124137
const text = code?.textContent || ''
125-
138+
126139
try {
127140
await navigator.clipboard.writeText(text)
128141
button.classList.add('copied')
@@ -131,7 +144,7 @@ const { title = 'Basic Memory', description = 'Basic Memory - Persistent memory
131144
<polyline points="20 6 9 17 4 12"/>
132145
</svg>
133146
`
134-
147+
135148
setTimeout(() => {
136149
button.classList.remove('copied')
137150
button.innerHTML = `
@@ -147,7 +160,7 @@ const { title = 'Basic Memory', description = 'Basic Memory - Persistent memory
147160
})
148161
})
149162
})
150-
163+
151164
// Full screen image viewer
152165
const createImageViewer = () => {
153166
// Create viewer element
@@ -163,30 +176,30 @@ const { title = 'Basic Memory', description = 'Basic Memory - Persistent memory
163176
</div>
164177
`
165178
document.body.appendChild(viewer)
166-
179+
167180
const viewerImg = viewer.querySelector('img')
168181
const closeBtn = viewer.querySelector('.image-viewer-close')
169-
182+
170183
// Close on click outside image or close button
171184
viewer.addEventListener('click', (e) => {
172185
if (e.target === viewer || e.target === closeBtn || closeBtn.contains(e.target)) {
173186
viewer.classList.remove('active')
174187
}
175188
})
176-
189+
177190
// Close on escape key
178191
document.addEventListener('keydown', (e) => {
179192
if (e.key === 'Escape' && viewer.classList.contains('active')) {
180193
viewer.classList.remove('active')
181194
}
182195
})
183-
196+
184197
return { viewer, viewerImg }
185198
}
186-
199+
187200
// Initialize image viewer
188201
const { viewer, viewerImg } = createImageViewer()
189-
202+
190203
// Add click handlers to all images
191204
const images = document.querySelectorAll('article img')
192205
images.forEach(img => {
@@ -198,4 +211,4 @@ const { title = 'Basic Memory', description = 'Basic Memory - Persistent memory
198211
})
199212
</script>
200213
</body>
201-
</html>
214+
</html>

src/pages/getting-started.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Basic Memory works through the Model Context Protocol (MCP) to connect with AI a
1414

1515
You can install Basic Memory using `uv`, an extremely fast Python package and project manager, written in Rust.
1616

17-
You can install `uv` from [astral's website ↗️](https://docs.astral.sh/uv/getting-started/installation/)
17+
You can install `uv` from [astral's website](https://docs.astral.sh/uv/getting-started/installation/)
1818

1919
```bash
2020
uv tool install basic-memory
@@ -403,4 +403,4 @@ If Claude cannot find Basic Memory tools:
403403
If you encounter permission errors:
404404

405405
1. Check that Basic Memory has access to create files in your home directory
406-
2. Ensure Claude Desktop has permission to execute the uvx command
406+
2. Ensure Claude Desktop has permission to execute the uvx command

src/pages/user-guide.mdx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ Claude: I'll create a note summarizing our authentication discussion.
3333

3434
This creates a Markdown file in your `~/basic-memory` directory with semantic markup.
3535

36+
<Tip>
37+
You can store your knowledge at any location you want. `~/basic-memory` is the default project location.
38+
</Tip>
39+
3640
### Direct File Creation
3741

3842
You can create files directly:
@@ -41,7 +45,6 @@ You can create files directly:
4145
2. Add frontmatter with title, type, and optional tags
4246
3. Structure content with observations and relations
4347
4. Save the file
44-
5. Run `basic-memory sync` if not in watch mode
4548

4649
## Using Special Prompts
4750

src/styles/global.css

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,16 @@
206206
color: rgb(209 213 219) !important; /* gray-300 */
207207
}
208208

209+
/* Default link styles for content */
209210
a {
210211
@apply font-medium text-primary hover:text-primary/80;
211212
}
212213

213-
/* Underline links in article content */
214-
article a {
215-
@apply underline underline-offset-2;
214+
/* Article content links with proper dark mode colors */
215+
article a,
216+
main p a,
217+
main li a {
218+
@apply font-medium text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 underline underline-offset-2;
216219
}
217220

218221
/* Remove underlines from specific areas */

0 commit comments

Comments
 (0)