WIP: ⌘K palette + 6-cat grid + brand logo rendering (build red)
Builder + brand agents paused on the weekly usage cap (resets Jul 21 6am PT). Preserving in-flight work-board work so nothing is lost; next resume greens + finishes. Co-authored-by: Hanzo Dev <dev@hanzo.ai>
@@ -22,7 +22,7 @@ spec:
|
||||
- name: work-board
|
||||
# Pinned to the immutable CI tag (ghcr.io/luxfi/work-board:sha-<commit>).
|
||||
# CI builds every push to main; bump this to roll a new build.
|
||||
image: ghcr.io/luxfi/work-board:sha-18004aa
|
||||
image: ghcr.io/luxfi/work-board:sha-c2977a5
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
resources:
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<svg viewBox="0 0 67 67" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="#ffffff"/>
|
||||
<path d="M0 44.6369L22.21 46.8285V44.6369H0Z" fill="#DDDDDD"/>
|
||||
<path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="#ffffff"/>
|
||||
<path d="M22.21 0H0V22.3184H22.21V0Z" fill="#ffffff"/>
|
||||
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="#ffffff"/>
|
||||
<path d="M66.6753 22.3185L44.5098 20.0822V22.3185H66.6753Z" fill="#DDDDDD"/>
|
||||
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="#ffffff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 561 B |
@@ -0,0 +1,10 @@
|
||||
<svg viewBox="0 0 1024 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(32, 48) scale(2.388)">
|
||||
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="#ffffff"/>
|
||||
<path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="#ffffff"/>
|
||||
<path d="M22.21 0H0V22.3184H22.21V0Z" fill="#ffffff"/>
|
||||
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="#ffffff"/>
|
||||
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="#ffffff"/>
|
||||
</g>
|
||||
<text x="240" y="172" font-family="Geist Sans, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" font-weight="600" font-size="140" fill="#ffffff" letter-spacing="-4">Hanzo</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 690 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Lux brand mark: solid black square -->
|
||||
<rect width="1024" height="1024" fill="#000000"/>
|
||||
<text x="512" y="640" font-family="ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" font-weight="700" font-size="640" fill="#FFFFFF" text-anchor="middle" letter-spacing="-32">L</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 407 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="1024" height="256" viewBox="0 0 1024 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0" y="48" width="160" height="160" fill="#000000"/>
|
||||
<text x="80" y="172" font-family="ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" font-weight="700" font-size="140" fill="#FFFFFF" text-anchor="middle" letter-spacing="-6">L</text>
|
||||
<text x="200" y="172" font-family="ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" font-weight="700" font-size="140" fill="currentColor" letter-spacing="-6">Lux</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 563 B |
@@ -0,0 +1,69 @@
|
||||
<svg viewBox="-120 -120 240 240" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<!--
|
||||
Pars Network Logo - Persian 8-Pointed Star (Khatam/Shamseh)
|
||||
The traditional Persian geometric motif - recursive fractal star
|
||||
Used in mosques, palaces, and tilework across Persia for millennia.
|
||||
-->
|
||||
<defs>
|
||||
<linearGradient id="pars-gold" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#f5d06f"/>
|
||||
<stop offset="50%" stop-color="#caa24a"/>
|
||||
<stop offset="100%" stop-color="#f3dc8f"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="pars-blue" x1="0" y1="1" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="#003355"/>
|
||||
<stop offset="50%" stop-color="#00abff"/>
|
||||
<stop offset="100%" stop-color="#66d0ff"/>
|
||||
</linearGradient>
|
||||
<filter id="pars-glow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feGaussianBlur stdDeviation="2" result="blur"/>
|
||||
<feComposite in="SourceGraphic" in2="blur" operator="over"/>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- Outer 8-pointed star -->
|
||||
<g filter="url(#pars-glow)">
|
||||
<path
|
||||
d="M0,-100 L30,-60 L100,-40 L60,0 L100,40 L30,60 L0,100 L-30,60 L-100,40 L-60,0 L-100,-40 L-30,-60 Z"
|
||||
fill="none"
|
||||
stroke="url(#pars-gold)"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- Inner star with blue fill -->
|
||||
<path
|
||||
d="M0,-70 L22,-42 L70,-28 L42,0 L70,28 L22,42 L0,70 L-22,42 L-70,28 L-42,0 L-70,-28 L-22,-42 Z"
|
||||
fill="url(#pars-blue)"
|
||||
stroke="url(#pars-gold)"
|
||||
stroke-width="3"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
|
||||
<!-- Recursive inner star -->
|
||||
<path
|
||||
d="M0,-45 L14,-27 L45,-18 L27,0 L45,18 L14,27 L0,45 L-14,27 L-45,18 L-27,0 L-45,-18 L-14,-27 Z"
|
||||
fill="none"
|
||||
stroke="url(#pars-gold)"
|
||||
stroke-width="2"
|
||||
stroke-linejoin="round"
|
||||
opacity="0.8"
|
||||
/>
|
||||
|
||||
<!-- Interlaced circles (Persian geometric pattern) -->
|
||||
<g fill="none" stroke="#eaf7ff" stroke-width="1.5" opacity="0.6">
|
||||
<circle r="55"/>
|
||||
<circle r="35"/>
|
||||
</g>
|
||||
|
||||
<!-- Center rosette -->
|
||||
<circle r="8" fill="url(#pars-gold)"/>
|
||||
<path
|
||||
d="M0,-20 L6,-6 L20,0 L6,6 L0,20 L-6,6 L-20,0 L-6,-6 Z"
|
||||
fill="#002a47"
|
||||
stroke="url(#pars-gold)"
|
||||
stroke-width="1.5"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,83 @@
|
||||
<svg viewBox="0 0 500 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<!--
|
||||
Pars Network Logo + Wordmark (Horizontal)
|
||||
Persian 8-Pointed Star with "PARS NETWORK" text
|
||||
-->
|
||||
<defs>
|
||||
<linearGradient id="pars-gold-lw" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#f5d06f"/>
|
||||
<stop offset="50%" stop-color="#caa24a"/>
|
||||
<stop offset="100%" stop-color="#f3dc8f"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="pars-blue-lw" x1="0" y1="1" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="#003355"/>
|
||||
<stop offset="50%" stop-color="#00abff"/>
|
||||
<stop offset="100%" stop-color="#66d0ff"/>
|
||||
</linearGradient>
|
||||
<filter id="pars-glow-lw" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feGaussianBlur stdDeviation="1" result="blur"/>
|
||||
<feComposite in="SourceGraphic" in2="blur" operator="over"/>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- Logo (scaled to fit) -->
|
||||
<g transform="translate(50, 50) scale(0.4)">
|
||||
<g filter="url(#pars-glow-lw)">
|
||||
<path
|
||||
d="M0,-100 L30,-60 L100,-40 L60,0 L100,40 L30,60 L0,100 L-30,60 L-100,40 L-60,0 L-100,-40 L-30,-60 Z"
|
||||
fill="none"
|
||||
stroke="url(#pars-gold-lw)"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
d="M0,-70 L22,-42 L70,-28 L42,0 L70,28 L22,42 L0,70 L-22,42 L-70,28 L-42,0 L-70,-28 L-22,-42 Z"
|
||||
fill="url(#pars-blue-lw)"
|
||||
stroke="url(#pars-gold-lw)"
|
||||
stroke-width="3"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M0,-45 L14,-27 L45,-18 L27,0 L45,18 L14,27 L0,45 L-14,27 L-45,18 L-27,0 L-45,-18 L-14,-27 Z"
|
||||
fill="none"
|
||||
stroke="url(#pars-gold-lw)"
|
||||
stroke-width="2"
|
||||
stroke-linejoin="round"
|
||||
opacity="0.8"
|
||||
/>
|
||||
<g fill="none" stroke="#eaf7ff" stroke-width="1.5" opacity="0.6">
|
||||
<circle r="55"/>
|
||||
<circle r="35"/>
|
||||
</g>
|
||||
<circle r="8" fill="url(#pars-gold-lw)"/>
|
||||
<path
|
||||
d="M0,-20 L6,-6 L20,0 L6,6 L0,20 L-6,6 L-20,0 L-6,-6 Z"
|
||||
fill="#002a47"
|
||||
stroke="url(#pars-gold-lw)"
|
||||
stroke-width="1.5"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- Wordmark -->
|
||||
<text
|
||||
x="115"
|
||||
y="62"
|
||||
font-family="system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
|
||||
font-size="40"
|
||||
font-weight="700"
|
||||
letter-spacing="0.05em"
|
||||
fill="url(#pars-gold-lw)"
|
||||
>PARS</text>
|
||||
|
||||
<text
|
||||
x="250"
|
||||
y="62"
|
||||
font-family="system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
|
||||
font-size="40"
|
||||
font-weight="300"
|
||||
letter-spacing="0.05em"
|
||||
fill="white"
|
||||
>NETWORK</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{enable-background:new ;}
|
||||
.st1{fill:#231F20;}
|
||||
</style>
|
||||
<g class="st0">
|
||||
<path class="st1" d="M3.5,20.2v-1.1l4.4-5.9H3.5v-1.5h6.7v1.1l-4.4,5.9h4.4v1.5H3.5z"/>
|
||||
<path class="st1" d="M18.9,14.2c0.2,0.5,0.3,1.2,0.3,1.8c0,0.7-0.1,1.3-0.3,1.8c-0.2,0.5-0.5,1-0.9,1.4s-0.8,0.6-1.3,0.8
|
||||
c-0.5,0.2-1,0.3-1.6,0.3S14,20.2,13.5,20s-0.9-0.5-1.3-0.8c-0.4-0.4-0.7-0.8-0.9-1.4C11.1,17.3,11,16.7,11,16
|
||||
c0-0.7,0.1-1.3,0.3-1.8s0.5-1,0.9-1.4s0.8-0.6,1.3-0.8s1-0.3,1.6-0.3s1.1,0.1,1.6,0.3s0.9,0.5,1.3,0.8S18.6,13.6,18.9,14.2z
|
||||
M16.7,18c0.4-0.5,0.6-1.2,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.6-0.7c-0.7,0-1.2,0.2-1.6,0.7c-0.4,0.5-0.6,1.2-0.6,2
|
||||
c0,0.9,0.2,1.6,0.6,2c0.4,0.5,0.9,0.7,1.6,0.7C15.8,18.8,16.3,18.5,16.7,18z"/>
|
||||
<path class="st1" d="M28.2,14.2c0.2,0.5,0.3,1.2,0.3,1.8c0,0.7-0.1,1.3-0.3,1.8c-0.2,0.5-0.5,1-0.9,1.4S26.5,19.8,26,20
|
||||
s-1,0.3-1.6,0.3s-1.1-0.1-1.6-0.3s-0.9-0.5-1.3-0.8c-0.4-0.4-0.7-0.8-0.9-1.4c-0.2-0.5-0.3-1.2-0.3-1.8c0-0.7,0.1-1.3,0.3-1.8
|
||||
c0.2-0.5,0.5-1,0.9-1.4s0.8-0.6,1.3-0.8s1-0.3,1.6-0.3s1.1,0.1,1.6,0.3s0.9,0.5,1.3,0.8C27.7,13.2,28,13.6,28.2,14.2z M26.1,18
|
||||
c0.4-0.5,0.6-1.2,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.6-0.7s-1.2,0.2-1.6,0.7s-0.6,1.2-0.6,2c0,0.9,0.2,1.6,0.6,2
|
||||
c0.4,0.5,0.9,0.7,1.6,0.7S25.7,18.5,26.1,18z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{enable-background:new ;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g class="st0">
|
||||
<path class="st1" d="M3.5,20.2v-1.1l4.4-5.9H3.5v-1.5h6.7v1.1l-4.4,5.9h4.4v1.5H3.5z"/>
|
||||
<path class="st1" d="M18.9,14.2c0.2,0.5,0.3,1.2,0.3,1.8c0,0.7-0.1,1.3-0.3,1.8c-0.2,0.5-0.5,1-0.9,1.4s-0.8,0.6-1.3,0.8
|
||||
c-0.5,0.2-1,0.3-1.6,0.3S14,20.2,13.5,20s-0.9-0.5-1.3-0.8c-0.4-0.4-0.7-0.8-0.9-1.4C11.1,17.3,11,16.7,11,16
|
||||
c0-0.7,0.1-1.3,0.3-1.8s0.5-1,0.9-1.4s0.8-0.6,1.3-0.8s1-0.3,1.6-0.3s1.1,0.1,1.6,0.3s0.9,0.5,1.3,0.8S18.6,13.6,18.9,14.2z
|
||||
M16.7,18c0.4-0.5,0.6-1.2,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.6-0.7c-0.7,0-1.2,0.2-1.6,0.7c-0.4,0.5-0.6,1.2-0.6,2
|
||||
c0,0.9,0.2,1.6,0.6,2c0.4,0.5,0.9,0.7,1.6,0.7C15.8,18.8,16.3,18.5,16.7,18z"/>
|
||||
<path class="st1" d="M28.2,14.2c0.2,0.5,0.3,1.2,0.3,1.8c0,0.7-0.1,1.3-0.3,1.8c-0.2,0.5-0.5,1-0.9,1.4S26.5,19.8,26,20
|
||||
c-0.5,0.2-1,0.3-1.6,0.3s-1.1-0.1-1.6-0.3s-0.9-0.5-1.3-0.8c-0.4-0.4-0.7-0.8-0.9-1.4c-0.2-0.5-0.3-1.2-0.3-1.8
|
||||
c0-0.7,0.1-1.3,0.3-1.8c0.2-0.5,0.5-1,0.9-1.4s0.8-0.6,1.3-0.8s1-0.3,1.6-0.3s1.1,0.1,1.6,0.3s0.9,0.5,1.3,0.8
|
||||
C27.7,13.2,28,13.6,28.2,14.2z M26.1,18c0.4-0.5,0.6-1.2,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.6-0.7s-1.2,0.2-1.6,0.7
|
||||
s-0.6,1.2-0.6,2c0,0.9,0.2,1.6,0.6,2c0.4,0.5,0.9,0.7,1.6,0.7S25.7,18.5,26.1,18z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -1,11 +1,25 @@
|
||||
import type { Address } from 'viem';
|
||||
|
||||
// Brand logos — embedded at build time. Vite inlines these small SVGs as `data:`
|
||||
// URIs (well under the 4 KB asset-inline limit), which the strict production CSP
|
||||
// permits via `img-src 'self' data:`; a missing file fails the build. Each mark is
|
||||
// the brand's own canonical asset (from its @<org>/brand package or app public/),
|
||||
// never cross-brand: a Zoo build embeds only Zoo. `logo` is the full wordmark,
|
||||
// `logoMark` the square/icon mark. Zoo ships one trigram that serves as both.
|
||||
import zooWordmark from './assets/brands/zoo/wordmark.svg';
|
||||
import parsWordmark from './assets/brands/pars/wordmark.svg';
|
||||
import parsMark from './assets/brands/pars/mark.svg';
|
||||
import luxWordmark from './assets/brands/lux/wordmark.svg';
|
||||
import luxMark from './assets/brands/lux/mark.svg';
|
||||
import hanzoWordmark from './assets/brands/hanzo/wordmark.svg';
|
||||
import hanzoMark from './assets/brands/hanzo/mark.svg';
|
||||
|
||||
// The one place a white-label lives. A brand is selected at BUILD time by the
|
||||
// VITE_BRAND build-arg (see Dockerfile / docker.yml); default is 'zoo'. Every
|
||||
// brand-varying value — chain, addresses, owner label, header/title text, the RPC
|
||||
// host baked into the CSP, and all Dework presentation (tagline, accent, socials,
|
||||
// Spaces/categories) — is a field here, so standing up a new board is a data
|
||||
// change, not a code change. Never cross brands: a Zoo build shows only Zoo.
|
||||
// host baked into the CSP, and all Dework presentation (tagline, accent, logos,
|
||||
// socials, Spaces/categories) — is a field here, so standing up a new board is a
|
||||
// data change, not a code change. Never cross brands: a Zoo build shows only Zoo.
|
||||
|
||||
// A Space is a bounty category (Dework "Space"). One Bounty serves the whole
|
||||
// org, so a bounty is routed to a Space by matching its issueRef against `match`
|
||||
@@ -44,6 +58,12 @@ export type Brand = {
|
||||
tagline: string;
|
||||
// Accent hex — primary buttons, active nav, highlights. Per-brand, never cross.
|
||||
accent: string;
|
||||
// Optional secondary/highlight hex (e.g. Pars gold). Omit for single-accent brands.
|
||||
accentSecondary?: string;
|
||||
// Brand logos — embedded SVGs (imported → build-inlined `data:` URI string).
|
||||
// `logo` is the full wordmark; `logoMark` the square/icon mark. Never cross-brand.
|
||||
logo: string;
|
||||
logoMark: string;
|
||||
usdPerNative: number; // native → USD for the "Total paid: $X" header stat
|
||||
social: { discord?: string; twitter?: string; website?: string };
|
||||
tags: string[]; // About-panel chips
|
||||
@@ -73,13 +93,16 @@ export const BRANDS = {
|
||||
org: 'Zoo DAO',
|
||||
workspace: 'Zoo',
|
||||
tagline: 'Open AI research network — DeAI & DeSci',
|
||||
accent: '#22c55e',
|
||||
accent: '#6c5efb',
|
||||
logo: zooWordmark,
|
||||
logoMark: zooWordmark,
|
||||
usdPerNative: 1,
|
||||
social: { discord: 'https://discord.gg/zoo', twitter: 'https://twitter.com/zoo_labs', website: 'https://zoo.ngo' },
|
||||
tags: ['DeAI', 'DeSci', 'Research', 'Open Source', 'AI'],
|
||||
spaces: [
|
||||
{ key: 'engineering', name: 'Engineering', emoji: '⚙️', skills: ['Development', 'Product'], match: ['zooai/', 'zoo-'] },
|
||||
{ key: 'research', name: 'AI & Research', emoji: '🧬', skills: ['Research', 'Data Analytics'], match: ['research/', 'zoo-research'] },
|
||||
{ key: 'ecosystem', name: 'Ecosystem & Partnerships', emoji: '🤝', skills: ['Partnerships', 'Business Development'] },
|
||||
{ key: 'community', name: 'Community & Social', emoji: '💬', skills: ['Community', 'Marketing'] },
|
||||
{ key: 'content', name: 'Content Creation', emoji: '🎬', skills: ['Writing', 'Design'] },
|
||||
{ key: 'governance', name: 'Governance', emoji: '🏛️', skills: ['Legal', 'Operations'], match: ['zips/'] },
|
||||
@@ -100,19 +123,85 @@ export const BRANDS = {
|
||||
org: 'Pars DAO',
|
||||
workspace: 'Pars',
|
||||
tagline: 'The community L1',
|
||||
accent: '#3b82f6',
|
||||
accent: '#1C3879',
|
||||
accentSecondary: '#D4AF37',
|
||||
logo: parsWordmark,
|
||||
logoMark: parsMark,
|
||||
usdPerNative: 1,
|
||||
social: { website: 'https://pars.network' },
|
||||
tags: ['Community', 'L1', 'Governance'],
|
||||
spaces: [
|
||||
{ key: 'engineering', name: 'Engineering', emoji: '⚙️', skills: ['Development', 'Product'] },
|
||||
{ key: 'ecosystem', name: 'Ecosystem & Partnerships', emoji: '🤝', skills: ['Partnerships', 'Business Development'] },
|
||||
{ key: 'community', name: 'Community & Social', emoji: '💬', skills: ['Community', 'Marketing'] },
|
||||
{ key: 'content', name: 'Content Creation', emoji: '🎬', skills: ['Writing', 'Design'] },
|
||||
{ key: 'education', name: 'Education & Research', emoji: '📚', skills: ['Education', 'Research'] },
|
||||
{ key: 'governance', name: 'Governance', emoji: '🏛️', skills: ['Legal', 'Operations'], match: ['pips/'] },
|
||||
],
|
||||
rpcUrl: 'https://api.pars.network/v1/bc/C/rpc',
|
||||
},
|
||||
// lux + hanzo brands land in the batch-3 white-label pass, together with their
|
||||
// fixtures, CI matrix entries and k8s manifests (post flag-day / deploying).
|
||||
lux: {
|
||||
chainId: 96369,
|
||||
chainName: 'Lux',
|
||||
nativeSymbol: 'LUX',
|
||||
addresses: {
|
||||
// TODO: no work-market deployed yet (Lux frozen / Hanzo key-gap)
|
||||
bounty: '0x0000000000000000000000000000000000000000',
|
||||
escrow: '0x0000000000000000000000000000000000000000',
|
||||
reputation: '0x0000000000000000000000000000000000000000',
|
||||
owner: '0x0000000000000000000000000000000000000000',
|
||||
},
|
||||
ownerLabel: 'Lux DAO Safe',
|
||||
org: 'Lux DAO',
|
||||
workspace: 'Lux',
|
||||
tagline: 'Quantum-safe multi-consensus L1',
|
||||
accent: '#7000FF',
|
||||
logo: luxWordmark,
|
||||
logoMark: luxMark,
|
||||
usdPerNative: 1,
|
||||
social: { discord: 'https://discord.gg/lux', twitter: 'https://x.com/luxfi', website: 'https://lux.network' },
|
||||
tags: ['Consensus', 'Post-Quantum', 'L1', 'DeFi', 'Open Source'],
|
||||
spaces: [
|
||||
{ key: 'engineering', name: 'Engineering', emoji: '⚙️', skills: ['Development', 'Product'], match: ['luxfi/', 'lux-'] },
|
||||
{ key: 'ecosystem', name: 'Ecosystem & Partnerships', emoji: '🤝', skills: ['Partnerships', 'Business Development'] },
|
||||
{ key: 'community', name: 'Community & Social', emoji: '💬', skills: ['Community', 'Marketing'] },
|
||||
{ key: 'content', name: 'Content Creation', emoji: '🎬', skills: ['Writing', 'Design'] },
|
||||
{ key: 'research', name: 'Research', emoji: '🔬', skills: ['Research', 'Cryptography'] },
|
||||
{ key: 'governance', name: 'Governance', emoji: '🏛️', skills: ['Legal', 'Operations'] },
|
||||
],
|
||||
rpcUrl: 'https://api.lux.network/v1/bc/C/rpc',
|
||||
},
|
||||
hanzo: {
|
||||
chainId: 36963,
|
||||
chainName: 'Hanzo',
|
||||
nativeSymbol: 'AI',
|
||||
addresses: {
|
||||
// TODO: no work-market deployed yet (Lux frozen / Hanzo key-gap)
|
||||
bounty: '0x0000000000000000000000000000000000000000',
|
||||
escrow: '0x0000000000000000000000000000000000000000',
|
||||
reputation: '0x0000000000000000000000000000000000000000',
|
||||
owner: '0x0000000000000000000000000000000000000000',
|
||||
},
|
||||
ownerLabel: 'Hanzo DAO Safe',
|
||||
org: 'Hanzo DAO',
|
||||
workspace: 'Hanzo',
|
||||
tagline: 'Frontier AI & foundational models',
|
||||
accent: '#ea580c',
|
||||
logo: hanzoWordmark,
|
||||
logoMark: hanzoMark,
|
||||
usdPerNative: 1,
|
||||
social: { discord: 'https://discord.gg/hanzo', website: 'https://hanzo.ai' },
|
||||
tags: ['AI', 'LLM', 'MCP', 'Agents', 'Open Source'],
|
||||
spaces: [
|
||||
{ key: 'engineering', name: 'Engineering', emoji: '⚙️', skills: ['Development', 'Product'], match: ['hanzoai/', 'hanzo-'] },
|
||||
{ key: 'research', name: 'AI & Research', emoji: '🧠', skills: ['Research', 'Machine Learning'] },
|
||||
{ key: 'ecosystem', name: 'Ecosystem & Partnerships', emoji: '🤝', skills: ['Partnerships', 'Business Development'] },
|
||||
{ key: 'community', name: 'Community & Social', emoji: '💬', skills: ['Community', 'Marketing'] },
|
||||
{ key: 'content', name: 'Content Creation', emoji: '🎬', skills: ['Writing', 'Design'] },
|
||||
{ key: 'governance', name: 'Governance', emoji: '🏛️', skills: ['Legal', 'Operations'] },
|
||||
],
|
||||
rpcUrl: 'https://api.hanzo.network/v1/bc/C/rpc',
|
||||
},
|
||||
} as const satisfies Record<string, Brand>;
|
||||
|
||||
export type BrandKey = keyof typeof BRANDS;
|
||||
|
||||
@@ -3,7 +3,8 @@ import { ORG } from '../config';
|
||||
import { useRoute, navigate } from '../router';
|
||||
import type { Route } from '../router';
|
||||
import {
|
||||
IconHome,
|
||||
BrandMark,
|
||||
BrandLogo,
|
||||
IconPlus,
|
||||
IconGrid,
|
||||
IconBulb,
|
||||
@@ -15,6 +16,28 @@ import {
|
||||
IconDoc,
|
||||
} from '../ui';
|
||||
|
||||
// The far-left 64px icon rail — a SEPARATE column beside the 256px sidebar
|
||||
// (canonical Dework). Home + org-switcher "+". Both collapse into the mobile drawer.
|
||||
export function IconRail({ onNavigate }: { onNavigate?: () => void }) {
|
||||
const go = (path: string) => {
|
||||
navigate(path);
|
||||
onNavigate?.();
|
||||
};
|
||||
return (
|
||||
<div
|
||||
className="flex h-full w-16 shrink-0 flex-col items-center gap-2 border-r border-[var(--border)] bg-[var(--rail)] pt-3"
|
||||
style={{ paddingTop: 'calc(env(safe-area-inset-top) + 0.75rem)' }}
|
||||
>
|
||||
<button onClick={() => go('/')} className="flex h-10 w-10 items-center justify-center" title="Home" aria-label={`${ORG.workspace} home`}>
|
||||
<BrandMark size={40} className="shadow-sm" />
|
||||
</button>
|
||||
<button onClick={() => go('/explore')} className="flex h-10 w-10 items-center justify-center rounded-full bg-white/5 text-neutral-400 ring-1 ring-inset ring-white/8 hover:text-neutral-200" title="Browse bounties across all DAOs">
|
||||
<IconPlus className="h-[18px] w-[18px]" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function NavItem({
|
||||
active,
|
||||
icon,
|
||||
@@ -58,22 +81,9 @@ export function Sidebar({ onNavigate }: { onNavigate?: () => void }) {
|
||||
|
||||
return (
|
||||
<aside className="flex h-full w-64 shrink-0 flex-col overflow-y-auto border-r border-[var(--border)] bg-[var(--rail)]">
|
||||
{/* org switcher rail */}
|
||||
<div className="flex items-center gap-2 px-3 pt-3" style={{ paddingTop: 'calc(env(safe-area-inset-top) + 0.75rem)' }}>
|
||||
<button onClick={() => go('/')} style={{ backgroundColor: 'var(--brand)' }} className="flex h-9 w-9 items-center justify-center rounded-xl text-white shadow-sm" title="Home">
|
||||
<IconHome className="h-[18px] w-[18px]" />
|
||||
</button>
|
||||
<button onClick={() => go('/explore')} className="flex h-9 w-9 items-center justify-center rounded-xl bg-white/5 text-neutral-400 ring-1 ring-inset ring-white/8 hover:text-neutral-200" title="Browse bounties across all DAOs">
|
||||
<IconPlus className="h-[18px] w-[18px]" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* workspace */}
|
||||
<button onClick={() => go('/')} className="mx-3 mt-3 flex items-center gap-2.5 rounded-md px-1 py-1 text-left hover:bg-white/5">
|
||||
<span className="flex h-7 w-7 items-center justify-center rounded-lg text-sm font-bold text-white" style={{ backgroundColor: 'var(--brand)' }}>
|
||||
{ORG.workspace.charAt(0)}
|
||||
</span>
|
||||
<span className="flex-1 truncate text-sm font-semibold text-neutral-100">{ORG.workspace}</span>
|
||||
<button onClick={() => go('/')} className="mx-3 mt-3 flex items-center gap-2.5 rounded-md px-1 py-1 text-left hover:bg-white/5" style={{ marginTop: 'calc(env(safe-area-inset-top) + 0.75rem)' }}>
|
||||
<BrandLogo className="flex-1" />
|
||||
<IconChevronsLeft className="h-4 w-4 text-neutral-600" />
|
||||
</button>
|
||||
|
||||
|
||||
@@ -97,8 +97,8 @@ export function TaskDetail({ task, ws }: { task: Task; ws: Workspace }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-stretch justify-center overflow-y-auto bg-black/60 sm:items-start sm:px-4 sm:py-10" onClick={closeTask}>
|
||||
<div className="min-h-full w-full max-w-4xl bg-[var(--surface)] shadow-2xl ring-1 ring-inset ring-white/10 sm:min-h-0 sm:rounded-xl" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="fixed inset-0 z-50 flex items-end justify-center bg-black/60 sm:items-start sm:px-4 sm:py-10" onClick={closeTask}>
|
||||
<div className="flex max-h-[92vh] w-full max-w-4xl flex-col overflow-y-auto rounded-t-2xl bg-[var(--surface)] shadow-2xl ring-1 ring-inset ring-white/10 sm:max-h-[86vh] sm:rounded-xl" onClick={(e) => e.stopPropagation()}>
|
||||
{/* header */}
|
||||
<div className="flex items-start justify-between gap-3 border-b border-white/6 px-6 py-4">
|
||||
<div className="min-w-0">
|
||||
|
||||
@@ -4,12 +4,60 @@ import { skillMeta } from './skills';
|
||||
import { formatReward } from './reward';
|
||||
import type { NftMeta } from './reward';
|
||||
import type { Reward } from './types';
|
||||
import { NATIVE_SYMBOL } from './config';
|
||||
import { NATIVE_SYMBOL, ORG } from './config';
|
||||
|
||||
// ---- Brand accent ----
|
||||
export const accent: CSSProperties = { backgroundColor: 'var(--brand)' };
|
||||
export const accentText: CSSProperties = { color: 'var(--brand)' };
|
||||
|
||||
// ---- Brand identity (the ONE place the org's logo renders) ----
|
||||
// BrandMark is the square mark: brand.logoMark (an image src / data URI) when the
|
||||
// brand supplies one, else a letter tile on the accent. BrandLogo is the full
|
||||
// sidebar lockup: brand.logo when supplied, else mark + workspace name. Both read
|
||||
// the logo fields defensively (optional) — ae530aa6 supplies them; until then the
|
||||
// letter tile / name stand in, and the image appears the moment the field lands.
|
||||
export function BrandMark({ size = 28, className = '' }: { size?: number; className?: string }) {
|
||||
const mark = (ORG as { logoMark?: string }).logoMark;
|
||||
const radius = Math.round(size * 0.28);
|
||||
if (mark) {
|
||||
return (
|
||||
<img
|
||||
src={mark}
|
||||
alt={ORG.workspace}
|
||||
width={size}
|
||||
height={size}
|
||||
style={{ borderRadius: radius }}
|
||||
className={`shrink-0 object-contain ${className}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span
|
||||
aria-hidden
|
||||
className={`flex shrink-0 items-center justify-center font-bold leading-none text-white ${className}`}
|
||||
style={{ width: size, height: size, borderRadius: radius, backgroundColor: 'var(--brand)', fontSize: Math.round(size * 0.42) }}
|
||||
>
|
||||
{ORG.workspace.charAt(0)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export function BrandLogo({ className = '' }: { className?: string }) {
|
||||
const logo = (ORG as { logo?: string }).logo;
|
||||
return (
|
||||
<span className={`flex min-w-0 items-center gap-2.5 ${className}`}>
|
||||
{logo ? (
|
||||
<img src={logo} alt={ORG.workspace} className="h-7 w-auto max-w-full object-contain object-left" />
|
||||
) : (
|
||||
<>
|
||||
<BrandMark size={28} />
|
||||
<span className="truncate text-sm font-semibold text-neutral-100">{ORG.workspace}</span>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
// ---- Avatar (deterministic identity for an address) ----
|
||||
export function Avatar({ addr, size = 24, title }: { addr: string; size?: number; title?: string }) {
|
||||
return (
|
||||
|
||||