merge: adopt @hanzogui/shell in hanzo.chat (Meet Hanzo launcher + brand tokens + landing header/footer)
This commit is contained in:
@@ -35,12 +35,14 @@
|
||||
"@dicebear/collection": "^9.2.2",
|
||||
"@dicebear/core": "^9.2.2",
|
||||
"@hanzo/ai": "^0.2.1",
|
||||
"@hanzo/brand": "^1.4.1",
|
||||
"@hanzo/event": "^0.2.0",
|
||||
"@hanzo/iam": "^0.13.1",
|
||||
"@hanzo/logo": "^1.0.13",
|
||||
"@hanzo/ui": "npm:@hanzo/ui-shadcn@^5.7.4",
|
||||
"@hanzo/usage": "^0.1.6",
|
||||
"@hanzochat/client": "workspace:*",
|
||||
"@hanzogui/shell": "^7.4.2",
|
||||
"@hanzochat/data-provider": "workspace:*",
|
||||
"@headlessui/react": "^2.1.2",
|
||||
"@marsidev/react-turnstile": "^1.1.0",
|
||||
|
||||
@@ -11,6 +11,7 @@ import ExportAndShareMenu from './ExportAndShareMenu';
|
||||
import BookmarkMenu from './Menus/BookmarkMenu';
|
||||
import { TemporaryChat } from './TemporaryChat';
|
||||
import AddMultiConvo from './AddMultiConvo';
|
||||
import MeetHanzoLauncher from '~/components/Nav/MeetHanzoLauncher';
|
||||
import { useHasAccess } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
@@ -80,14 +81,18 @@ export default function Header() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{!isSmallScreen && (
|
||||
<div className="flex items-center gap-2">
|
||||
<ExportAndShareMenu
|
||||
isSharedButtonEnabled={startupConfig?.sharedLinksEnabled ?? false}
|
||||
/>
|
||||
<TemporaryChat />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
{!isSmallScreen && (
|
||||
<>
|
||||
<ExportAndShareMenu
|
||||
isSharedButtonEnabled={startupConfig?.sharedLinksEnabled ?? false}
|
||||
/>
|
||||
<TemporaryChat />
|
||||
</>
|
||||
)}
|
||||
{/* Cross-app "Meet Hanzo" launcher — unified ecosystem nav, far right. */}
|
||||
<MeetHanzoLauncher />
|
||||
</div>
|
||||
</div>
|
||||
{/* Empty div for spacing */}
|
||||
<div />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { HanzoHeader, HanzoPreFooterCTA, HanzoFooter } from '@hanzogui/shell';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { getHanzoIamSdk } from '~/utils/iam';
|
||||
|
||||
@@ -65,24 +66,6 @@ const IconArrowRight = ({ className = 'ml-2 size-4' }: { className?: string }) =
|
||||
</svg>
|
||||
);
|
||||
|
||||
/* Hanzo geometric H logo */
|
||||
const HanzoLogo = ({ className = 'size-5', style }: { className?: string; style?: React.CSSProperties }) => (
|
||||
<svg viewBox="0 0 67 67" className={className} style={style} xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="currentColor" />
|
||||
<path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="currentColor" />
|
||||
<path d="M22.21 0H0V22.3184H22.21V0Z" fill="currentColor" />
|
||||
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="currentColor" />
|
||||
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="currentColor" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
/* GitHub icon */
|
||||
const IconGitHub = ({ className = 'size-5' }: { className?: string }) => (
|
||||
<svg className={className} role="img" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Data */
|
||||
/* ------------------------------------------------------------------ */
|
||||
@@ -157,55 +140,8 @@ export default function LandingPage() {
|
||||
fontFamily: "'Inter', 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
||||
}}
|
||||
>
|
||||
{/* ---- Navbar (matches fd HomeLayout nav) ---- */}
|
||||
<nav
|
||||
className="sticky top-0 z-50 backdrop-blur-md"
|
||||
style={{
|
||||
backgroundColor: 'rgba(5, 5, 5, 0.8)',
|
||||
borderBottom: `1px solid ${colors.border}`,
|
||||
}}
|
||||
>
|
||||
<div className="mx-auto flex max-w-[1400px] items-center justify-between px-6 py-3">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<HanzoLogo className="size-5 text-white" />
|
||||
<span className="text-sm font-bold tracking-tight">Hanzo Chat</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<a
|
||||
href="https://docs.hanzo.ai/chat"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hidden text-sm transition-colors sm:inline"
|
||||
style={{ color: colors.mutedFg }}
|
||||
onMouseOver={(e) => (e.currentTarget.style.color = colors.fg)}
|
||||
onMouseOut={(e) => (e.currentTarget.style.color = colors.mutedFg)}
|
||||
>
|
||||
Docs
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/hanzoai/chat"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hidden transition-colors sm:inline"
|
||||
style={{ color: colors.mutedFg }}
|
||||
onMouseOver={(e) => (e.currentTarget.style.color = colors.fg)}
|
||||
onMouseOut={(e) => (e.currentTarget.style.color = colors.mutedFg)}
|
||||
>
|
||||
<IconGitHub className="size-[18px]" />
|
||||
</a>
|
||||
<a
|
||||
href={loginHref}
|
||||
onClick={handleLoginClick}
|
||||
className="rounded-full px-5 py-2 text-sm font-medium tracking-tight transition-colors"
|
||||
style={{ backgroundColor: colors.brand, color: '#000' }}
|
||||
onMouseOver={(e) => (e.currentTarget.style.filter = 'brightness(1.15)')}
|
||||
onMouseOut={(e) => (e.currentTarget.style.filter = 'none')}
|
||||
>
|
||||
Log in
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{/* ---- Unified Hanzo marketing header (shared @hanzogui/shell) ---- */}
|
||||
<HanzoHeader surface="hanzo.chat" />
|
||||
|
||||
{/* ---- Hero (bordered card like dev.hanzo.ai) ---- */}
|
||||
<div className="mx-auto w-full max-w-[1400px] px-4 pt-4">
|
||||
@@ -557,39 +493,9 @@ zen5-coder: I'll help you refactor the auth module.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ---- Footer ---- */}
|
||||
<footer
|
||||
className="mt-0 py-8"
|
||||
style={{ borderTop: `1px solid ${colors.border}` }}
|
||||
>
|
||||
<div className="mx-auto flex max-w-[1400px] flex-col items-center justify-between gap-6 px-6 sm:flex-row md:px-12">
|
||||
<div className="flex items-center gap-2 text-sm" style={{ color: 'hsl(0, 0%, 40%)' }}>
|
||||
<HanzoLogo className="size-4" style={{ color: 'hsl(0, 0%, 40%)' }} />
|
||||
Powered by Hanzo AI
|
||||
</div>
|
||||
<div className="flex flex-wrap justify-center gap-6 text-sm" style={{ color: 'hsl(0, 0%, 40%)' }}>
|
||||
{[
|
||||
{ label: 'hanzo.ai', href: 'https://hanzo.ai' },
|
||||
{ label: 'Documentation', href: 'https://docs.hanzo.ai/chat' },
|
||||
{ label: 'Console', href: 'https://console.hanzo.ai' },
|
||||
{ label: 'Privacy', href: 'https://hanzo.ai/privacy' },
|
||||
{ label: 'Terms', href: 'https://hanzo.ai/terms' },
|
||||
].map(({ label, href }) => (
|
||||
<a
|
||||
key={label}
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="transition-colors"
|
||||
onMouseOver={(e) => (e.currentTarget.style.color = colors.fg)}
|
||||
onMouseOut={(e) => (e.currentTarget.style.color = 'hsl(0, 0%, 40%)')}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
{/* ---- Unified Hanzo pre-footer CTA + ecosystem footer (shared shell) ---- */}
|
||||
<HanzoPreFooterCTA surface="hanzo.chat" />
|
||||
<HanzoFooter currentProductId="chat" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Meet Hanzo — the cross-app "9-dot grid" launcher from the shared
|
||||
* @hanzogui/shell. Added ALONGSIDE LibreChat's conversation nav so Hanzo Chat
|
||||
* joins the unified Hanzo ecosystem nav.
|
||||
*
|
||||
* Click-only: the launcher's global ⌘/Ctrl-K quick-switch listener is disabled
|
||||
* (`quickSwitchKey={false}`) so adopting the shell never claims an app-wide
|
||||
* keyboard shortcut on the chat surface.
|
||||
*/
|
||||
import { HanzoAppLauncher } from '@hanzogui/shell';
|
||||
|
||||
export default function MeetHanzoLauncher() {
|
||||
return (
|
||||
<HanzoAppLauncher
|
||||
currentApp="chat"
|
||||
align="right"
|
||||
quickSwitchKey={false}
|
||||
label="Meet Hanzo"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,8 @@
|
||||
/* Shared Hanzo brand tokens (monochrome --hanzo-* scale). Imported first so the
|
||||
chat :root below overrides any collision — chat keeps its own grey ramp while
|
||||
the --hanzo-* palette becomes the single shared source across every surface. */
|
||||
@import '@hanzo/brand/styles/variables.css';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@@ -96,6 +96,24 @@ module.exports = {
|
||||
850: '#171717',
|
||||
900: '#0d0d0d',
|
||||
},
|
||||
// Shared @hanzo/brand monochrome scale (from variables.css). Additive —
|
||||
// chat's own `gray`/`mono` ramp is untouched; new shared chrome can use
|
||||
// `hanzo-*` so the palette resolves to the ONE brand source of truth.
|
||||
hanzo: {
|
||||
black: 'var(--hanzo-black)',
|
||||
white: 'var(--hanzo-white)',
|
||||
50: 'var(--hanzo-mono-50)',
|
||||
100: 'var(--hanzo-mono-100)',
|
||||
200: 'var(--hanzo-mono-200)',
|
||||
300: 'var(--hanzo-mono-300)',
|
||||
400: 'var(--hanzo-mono-400)',
|
||||
500: 'var(--hanzo-mono-500)',
|
||||
600: 'var(--hanzo-mono-600)',
|
||||
700: 'var(--hanzo-mono-700)',
|
||||
800: 'var(--hanzo-mono-800)',
|
||||
900: 'var(--hanzo-mono-900)',
|
||||
950: 'var(--hanzo-mono-950)',
|
||||
},
|
||||
green: mono,
|
||||
red: mono,
|
||||
blue: mono,
|
||||
|
||||
@@ -289,6 +289,10 @@ export default defineConfig(({ command }) => ({
|
||||
'micromark-extension-math': 'micromark-extension-llm-math',
|
||||
},
|
||||
},
|
||||
// Pre-bundle the compiled-ESM shell so the dev server resolves it cleanly.
|
||||
optimizeDeps: {
|
||||
include: ['@hanzogui/shell'],
|
||||
},
|
||||
}));
|
||||
|
||||
interface SourcemapExclude {
|
||||
|
||||
Generated
+34
@@ -379,6 +379,9 @@ importers:
|
||||
'@hanzo/ai':
|
||||
specifier: ^0.2.1
|
||||
version: 0.2.1
|
||||
'@hanzo/brand':
|
||||
specifier: ^1.4.1
|
||||
version: 1.4.1(react@18.3.1)
|
||||
'@hanzo/event':
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0(react@18.3.1)
|
||||
@@ -400,6 +403,9 @@ importers:
|
||||
'@hanzochat/data-provider':
|
||||
specifier: workspace:*
|
||||
version: link:../packages/data-provider
|
||||
'@hanzogui/shell':
|
||||
specifier: ^7.4.2
|
||||
version: 7.4.2(@hanzo/iam@0.13.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@headlessui/react':
|
||||
specifier: ^2.1.2
|
||||
version: 2.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -3797,6 +3803,15 @@ packages:
|
||||
resolution: {integrity: sha512-m0k6V6Im8m5RXWHUy/E7DvpZ9tFBYUw21NTYFxNxUiPI1l+yEvHEVytqEbEtHZOCa9Ytb8nfuNzJIsfCeF/zZw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@hanzo/brand@1.4.1':
|
||||
resolution: {integrity: sha512-tApXct8gE/HOYa61h6TWQfDp07l1pmB+vqmxlJtU+MhocbwEkW4VPJrQdPuwF/5GPZYQauNT2uaRpnZdCK8ikw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
react: '>=18'
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
|
||||
'@hanzo/event@0.2.0':
|
||||
resolution: {integrity: sha512-jx+xlT5no88PYg/k465/pQ7a+oQcfImB5X0dJ4/ZSSF5bwqPCItvN/9Znt4SQpq18EQeMuR5GiLmxo1wSP5uqw==}
|
||||
peerDependencies:
|
||||
@@ -3925,6 +3940,13 @@ packages:
|
||||
'@anthropic-ai/sandbox-runtime':
|
||||
optional: true
|
||||
|
||||
'@hanzogui/shell@7.4.2':
|
||||
resolution: {integrity: sha512-Haig4FLJUAgNbHvYxgsX/Y4D+VZW9fzvYoYi6Z19ZKkYCXnFG6S0wQmwZhqFW5KCmlnwUV7jUSJw9vOdvqj7nw==}
|
||||
peerDependencies:
|
||||
'@hanzo/iam': ^0.13.1
|
||||
react: '*'
|
||||
react-dom: '*'
|
||||
|
||||
'@headlessui/react@2.2.9':
|
||||
resolution: {integrity: sha512-Mb+Un58gwBn0/yWZfyrCh0TJyurtT+dETj7YHleylHk5od3dv2XqETPGWMyQ5/7sYN7oWdyM1u9MvC0OC8UmzQ==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -17704,6 +17726,12 @@ snapshots:
|
||||
|
||||
'@hanzo/ai@0.2.1': {}
|
||||
|
||||
'@hanzo/brand@1.4.1(react@18.3.1)':
|
||||
dependencies:
|
||||
'@hanzo/logo': 1.0.13(react@18.3.1)
|
||||
optionalDependencies:
|
||||
react: 18.3.1
|
||||
|
||||
'@hanzo/event@0.2.0(react@18.3.1)':
|
||||
optionalDependencies:
|
||||
react: 18.3.1
|
||||
@@ -17857,6 +17885,12 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@hanzogui/shell@7.4.2(@hanzo/iam@0.13.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@hanzo/iam': 0.13.1(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
'@headlessui/react@2.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@floating-ui/react': 0.26.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
|
||||
Reference in New Issue
Block a user