Skip to content

Commit ba0bdef

Browse files
committed
feat(ui): hooks / code highlighting refactor
Redesigned homepage hero with integrated search, terminal component, and partner marquee. Added system status page for API health monitoring. Migrated code highlighting from sugar-high to Shiki for better syntax highlighting across all code blocks. Enhanced search system with unified provider, saved presets, and homepage integration. Improved hook infrastructure with localStorage/sessionStorage utilities and multiple intersection observer. Set up Supabase migration infrastructure for GitHub branch management.
1 parent d6edbef commit ba0bdef

File tree

187 files changed

+58041
-3321
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

187 files changed

+58041
-3321
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,5 @@ SEARCH_OPTIMIZATION_ANALYSIS.md
146146
SEARCH_SYSTEM_ARCHITECTURE.md
147147
SEARCH_UNIFICATION_TODO.md
148148
VERIFY_INNGEST_DEPLOYMENT.md
149+
apps/web/src/components/features/home/HERO_IMPLEMENTATION_SUMMARY.md
150+
apps/web/src/components/features/home/HERO_REDESIGN.md

.zed/settings.json

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"language_servers": ["deno", "!typescript-language-server", "!vtsls"]
2525
},
2626
"TypeScript": {
27-
"language_servers": ["vtsls", "typescript-language-server", "!deno"],
27+
"language_servers": ["vtsls", "typescript-language-server", "ast-grep", "!deno"],
2828
"formatter": [
2929
{
3030
"code_action": "source.fixAll.eslint"
@@ -38,7 +38,7 @@
3838
]
3939
},
4040
"JavaScript": {
41-
"language_servers": ["vtsls", "typescript-language-server", "!deno"],
41+
"language_servers": ["vtsls", "typescript-language-server", "ast-grep", "!deno"],
4242
"formatter": [
4343
{
4444
"code_action": "source.fixAll.eslint"
@@ -52,7 +52,7 @@
5252
]
5353
},
5454
"TypeScript React": {
55-
"language_servers": ["vtsls", "typescript-language-server", "!deno"],
55+
"language_servers": ["vtsls", "typescript-language-server", "ast-grep", "!deno"],
5656
"formatter": [
5757
{
5858
"code_action": "source.fixAll.eslint"
@@ -66,7 +66,7 @@
6666
]
6767
},
6868
"JavaScript React": {
69-
"language_servers": ["vtsls", "typescript-language-server", "!deno"],
69+
"language_servers": ["vtsls", "typescript-language-server", "ast-grep", "!deno"],
7070
"formatter": [
7171
{
7272
"code_action": "source.fixAll.eslint"
@@ -222,6 +222,77 @@
222222
"typescriptreact": "javascriptreact"
223223
}
224224
}
225+
},
226+
"ast-grep": {
227+
"binary": {
228+
"path": "ast-grep",
229+
"arguments": ["lsp"]
230+
}
231+
},
232+
"discord_presence": {
233+
"initialization_options": {
234+
"application_id": "1263505205522337886",
235+
"base_icons_url": "https://raw.githubusercontent.com/xhyrom/zed-discord-presence/main/assets/icons/",
236+
"state": "Building heyclau.de: {folder_and_file}",
237+
"details": "Claude Pro Directory • {workspace}",
238+
"large_image": "{base_icons_url}/{language:lo}.png",
239+
"large_text": "{language:u}",
240+
"small_image": "{base_icons_url}/zed.png",
241+
"small_text": "Zed",
242+
"idle": {
243+
"timeout": 300,
244+
"action": "change_activity",
245+
"state": "Taking a break from heyclau.de",
246+
"details": "Claude Pro Directory • Idling",
247+
"large_image": "{base_icons_url}/zed.png",
248+
"large_text": "Zed",
249+
"small_image": "{base_icons_url}/idle.png",
250+
"small_text": "Coffee break ☕"
251+
},
252+
"git_integration": true,
253+
"languages": {
254+
"typescript": {
255+
"state": "TypeScript wizardry: {folder_and_file}",
256+
"details": "Building Claude Pro Directory",
257+
"large_text": "TypeScript"
258+
},
259+
"javascript": {
260+
"state": "JS magic: {folder_and_file}",
261+
"details": "Claude Pro Directory",
262+
"large_text": "JavaScript"
263+
},
264+
"typescriptreact": {
265+
"state": "React + TS: {folder_and_file}",
266+
"details": "Claude Pro Directory UI",
267+
"large_text": "React + TypeScript"
268+
},
269+
"javascriptreact": {
270+
"state": "React component: {folder_and_file}",
271+
"details": "Claude Pro Directory",
272+
"large_text": "React"
273+
},
274+
"markdown": {
275+
"state": "Documenting: {filename}",
276+
"details": "Claude Pro Directory docs",
277+
"large_text": "Documentation"
278+
},
279+
"yaml": {
280+
"state": "Config: {filename}",
281+
"details": "Claude Pro Directory setup",
282+
"large_text": "Configuration"
283+
},
284+
"json": {
285+
"state": "Config: {filename}",
286+
"details": "Claude Pro Directory",
287+
"large_text": "JSON"
288+
},
289+
"css": {
290+
"state": "Styling: {filename}",
291+
"details": "Claude Pro Directory",
292+
"large_text": "CSS"
293+
}
294+
}
295+
}
225296
}
226297
}
227298
}

apps/edge/supabase/deno-imports.d.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,6 @@ declare module 'npm:@react-email/components@*' {
4545
export * from '@react-email/components';
4646
}
4747

48-
declare module 'npm:sugar-high@*' {
49-
const content: any;
50-
export default content;
51-
export * from 'sugar-high';
52-
}
53-
5448
// HTTPS imports - declare as any to allow imports
5549
// Supports both default and named exports
5650
// Note: TypeScript doesn't support index signatures in module declarations,

apps/web/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
"server-only": "^0.0.1",
6969
"shiki": "^3.20.0",
7070
"sonner": "^2.0.7",
71-
"sugar-high": "^0.9.5",
7271
"tailwind-merge": "^3.4.0",
7372
"zod": "^4.1.13",
7473
"zustand": "^5.0.9"

apps/web/public/partners/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Partner Logos
2+
3+
This directory contains partner logos for the "Trusted by" marquee in the homepage hero section.
4+
5+
## Current Partners
6+
7+
- **Neon** - 1-year partnership (logo needed: `neon.svg`)
8+
9+
## Logo Requirements
10+
11+
- **Format:** SVG preferred (scalable, crisp at any size)
12+
- **Size:** Will be displayed at max-height 48px (h-12)
13+
- **Naming:** Use kebab-case (e.g., `neon.svg`, `company-name.svg`)
14+
- **Styling:** Logos will be grayscale by default, color on hover
15+
16+
## Adding New Partner Logos
17+
18+
1. Add the logo file to this directory
19+
2. Update `apps/web/src/components/features/home/hero-partners.tsx`:
20+
```typescript
21+
const PARTNERS: Partner[] = [
22+
// ... existing partners
23+
{
24+
name: 'Company Name',
25+
logo: '/partners/company-name.svg',
26+
href: 'https://company.com',
27+
alt: 'Company Name - Description',
28+
},
29+
];
30+
```

apps/web/src/app/(auth)/auth/link/[provider]/callback/page.tsx

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import { normalizeError } from '@heyclaude/shared-runtime';
99
import { isValidProvider, validateNextParameter } from '@heyclaude/web-runtime';
10-
import { useAuthenticatedUser } from '@heyclaude/web-runtime/hooks';
10+
import { useAuthenticatedUser, useBoolean, useTimeout } from '@heyclaude/web-runtime/hooks';
1111
import { AlertCircle, Loader2 } from '@heyclaude/web-runtime/icons';
1212
import { logClientError, logClientWarn } from '@heyclaude/web-runtime/logging/client';
1313
import {
@@ -49,6 +49,8 @@ export default function OAuthLinkCallbackPage({
4949
const [status, setStatus] = useState<'error' | 'loading'>('loading');
5050
const [errorMessage, setErrorMessage] = useState<null | string>(null);
5151
const [provider, setProvider] = useState<null | string>(null);
52+
const { setTrue: setShouldRedirectTrue, value: shouldRedirect } = useBoolean();
53+
const [redirectProvider, setRedirectProvider] = useState<null | string>(null);
5254
const hasAttempted = useRef<boolean>(false);
5355
const {
5456
isAuthenticated,
@@ -57,9 +59,24 @@ export default function OAuthLinkCallbackPage({
5759
user,
5860
} = useAuthenticatedUser({ context: 'OAuthLinkCallback' });
5961

62+
// Use useTimeout for redirect when user is not authenticated
63+
useTimeout(
64+
() => {
65+
if (shouldRedirect && redirectProvider) {
66+
const next = validateNextParameter(
67+
searchParameters.get('next'),
68+
'/account/connected-accounts'
69+
);
70+
router.push(
71+
`/login?redirect=${encodeURIComponent(`/auth/link/${redirectProvider}?next=${encodeURIComponent(next)}`)}`
72+
);
73+
}
74+
},
75+
shouldRedirect ? 2000 : null
76+
);
77+
6078
useEffect(() => {
6179
let mounted = true;
62-
let redirectTimeoutId: null | ReturnType<typeof setTimeout> = null;
6380

6481
// Use shared validation utility to prevent open redirects
6582
/**
@@ -125,17 +142,11 @@ export default function OAuthLinkCallbackPage({
125142
provider: rawProvider,
126143
route,
127144
});
128-
// Guard redirect with mounted check and store timeout ID for cleanup
129-
redirectTimeoutId = setTimeout(() => {
130-
if (!mounted) return; // Don't redirect if component unmounted
131-
const next = validateNextParameter(
132-
searchParameters.get('next'),
133-
'/account/connected-accounts'
134-
);
135-
router.push(
136-
`/login?redirect=${encodeURIComponent(`/auth/link/${rawProvider}?next=${encodeURIComponent(next)}`)}`
137-
);
138-
}, 2000);
145+
// Set state to trigger useTimeout redirect
146+
if (mounted) {
147+
setRedirectProvider(rawProvider);
148+
setShouldRedirectTrue();
149+
}
139150
return;
140151
}
141152

@@ -207,11 +218,6 @@ export default function OAuthLinkCallbackPage({
207218

208219
return () => {
209220
mounted = false;
210-
// Clear any pending redirect timeout on unmount
211-
if (redirectTimeoutId) {
212-
clearTimeout(redirectTimeoutId);
213-
redirectTimeoutId = null;
214-
}
215221
};
216222
}, [
217223
resolvedParameters.provider,
@@ -255,7 +261,7 @@ export default function OAuthLinkCallbackPage({
255261
</CardDescription>
256262
</CardHeader>
257263
<CardContent className={UI_CLASSES.FLEX_COL_GAP_2}>
258-
<Button type="button" onClick={() => router.push('/account/connected-accounts')}>
264+
<Button onClick={() => router.push('/account/connected-accounts')} type="button">
259265
Return to Connected Accounts
260266
</Button>
261267
</CardContent>

apps/web/src/app/(auth)/login/login-panel-client.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { VALID_PROVIDERS } from '@heyclaude/web-runtime';
44
import { ensureString } from '@heyclaude/web-runtime/data/utils';
5+
import { useBoolean } from '@heyclaude/web-runtime/hooks';
56
import { logClientWarn, normalizeError } from '@heyclaude/web-runtime/logging/client';
67
import { useEffect, useMemo, useState } from 'react';
78

@@ -33,7 +34,7 @@ interface LoginPanelClientProperties {
3334
* @see useNewsletterCount
3435
*/
3536
export function LoginPanelClient({ redirectTo }: LoginPanelClientProperties) {
36-
const [newsletterOptIn, setNewsletterOptIn] = useState(false);
37+
const { setValue: setNewsletterOptIn, value: newsletterOptIn } = useBoolean();
3738
const [newsletterConfig, setNewsletterConfig] = useState<Record<string, unknown>>({});
3839
const { count, isLoading } = useNewsletterCount();
3940
const subscriberCountLabel = useMemo(() => formatSubscriberCount(count), [count]);
@@ -98,9 +99,9 @@ export function LoginPanelClient({ redirectTo }: LoginPanelClientProperties) {
9899
checked={newsletterOptIn}
99100
headline={tileProperties.tileHeadline}
100101
isLoadingCount={isLoading}
102+
onChange={setNewsletterOptIn}
101103
safetyCopy={tileProperties.tileSafety}
102104
subscriberCountLabel={subscriberCountLabel}
103-
onChange={setNewsletterOptIn}
104105
/>
105106
}
106107
description="Choose your preferred sign-in method"

apps/web/src/app/account/settings/mfa/mfa-factors-list-client.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client';
22

3+
import { useBoolean } from '@heyclaude/web-runtime/hooks';
34
import { Shield } from '@heyclaude/web-runtime/icons';
45
import { Button, UI_CLASSES } from '@heyclaude/web-runtime/ui';
56
import { useState } from 'react';
@@ -8,7 +9,11 @@ import { EnrollMFADialog } from '@/src/components/features/account/mfa/enroll-mf
89
import { MFAFactorsList } from '@/src/components/features/account/mfa/mfa-factors-list';
910

1011
export function MFAFactorsListClient() {
11-
const [enrollDialogOpen, setEnrollDialogOpen] = useState(false);
12+
const {
13+
setTrue: setEnrollDialogOpenTrue,
14+
setValue: setEnrollDialogOpen,
15+
value: enrollDialogOpen,
16+
} = useBoolean();
1217
const [refreshKey, setRefreshKey] = useState(0);
1318

1419
const handleEnrolled = () => {
@@ -18,7 +23,7 @@ export function MFAFactorsListClient() {
1823
return (
1924
<div className="space-y-4">
2025
<div className="flex justify-end">
21-
<Button onClick={() => setEnrollDialogOpen(true)}>
26+
<Button onClick={setEnrollDialogOpenTrue}>
2227
<Shield className={UI_CLASSES.ICON_SM_LEADING} />
2328
Add Authenticator
2429
</Button>

apps/web/src/app/account/sponsorships/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ export async function generateMetadata(): Promise<Metadata> {
7878
* @param {{ active: boolean | null; end_date: string; start_date: string }} sponsorship Parameter description
7979
* @param {{ active: boolean | null; end_date: string; start_date: string }} sponsorship Parameter description
8080
* @param {{ active: boolean | null; end_date: string; start_date: string }} sponsorship Parameter description
81+
* @param {{ active: boolean | null; end_date: string; start_date: string }} sponsorship Parameter description
82+
* @param {{ active: boolean | null; end_date: string; start_date: string }} sponsorship Parameter description
83+
* @param {{ active: boolean | null; end_date: string; start_date: string }} sponsorship Parameter description
84+
* @param {{ active: boolean | null; end_date: string; start_date: string }} sponsorship Parameter description
85+
* @param {{ active: boolean | null; end_date: string; start_date: string }} sponsorship Parameter description
8186
* @param {{ active: boolean | null; end_date: string; start_date: string }} sponsorship Parameter description
8287
* @param {{ active: boolean | null; end_date: string; start_date: string }} sponsorship Parameter description
8388
*/

0 commit comments

Comments
 (0)