Compare commits

..
Author SHA1 Message Date
Abdullah ac1fc1a65a refactor(website): drop the fill mode superseded by compact + dead shell defaults
After compact landed, ProductVisual's fill only ever co-occurred with compact,
which overrode everything fill did in the shell. Removed fill from AppPreviewFrame
(and its crop branches) and from ShellScene; fill now solely drives StyledRoot
filling the morph area. Also removed ShellScene's now-unreachable aspect-ratio /
max-height defaults (every instance is bleed or compact, so height is constant).
2026-06-07 05:47:57 +05:00
Abdullah 28e94a49ba fix(website): give the mobile AI section standard section top padding
On mobile the AI section is a normal stacked section (not the first below the
nav), so it now uses spacing(12) top padding to match TrustedBy/ProductFeature,
via a $secondary prop on MobileSection. The intro section keeps spacing(7.5).
2026-06-07 04:59:56 +05:00
Abdullah b7179a66e8 fix(website): render both hero layouts and CSS-toggle to kill the mobile jump
The product hero is statically prerendered as the desktop morph (200vh), so on
a phone it swapped to the stacked mobile layout after hydration and reflowed the
page. Now both the morph and mobile layouts render and are shown/hidden via CSS
@media, so neither side jumps when the viewport resolves — desktop unchanged.
Each side's WebGL halftone and the mobile AI autoplay are gated by visibility so
only the on-screen layout does the heavy work.
2026-06-07 04:11:24 +05:00
Abdullah babd52516b feat(website): lock the phone AI panel to a 320px chat width
Below 600px the panel-only window is capped at 320px and centered, so it reads
as a chat panel instead of stretching toward the 600px breakpoint.
2026-06-07 02:17:19 +05:00
Abdullah 2514f2d760 feat(website): panel-only AI section on phones (<600px)
Below 600px the CRM board and AI panel can't coexist, so the AI section
collapses to a full-width 'Ask AI' window: AppPreviewLayout short-circuits to
render only the aside, and AiPanel goes full-width/flush. 600-921 keeps the
compact board+panel; the desktop morph is unchanged.
2026-06-07 02:11:27 +05:00
Abdullah 7abdaac42b feat(website): compact the AI morph so the panel never bleeds off-screen
- ProductVisual/AppPreviewFrame: add a compact mode — fixed-height window that
  fits the viewport width (capped), no aspect-ratio, so the board flexes while
  the sidebar + AI panel stay legible. Used by both morph layers (intro + AI)
  so the wipe stays aligned, and by the mobile AI section.
- Remove the two md-breakpoint 'display: none' rules (AsideSlot + AiPanel) that
  hid the AI panel below 921px; with the compact window it now fits and renders.
2026-06-07 01:58:26 +05:00
Abdullah 726c956afe feat(website): bleed the Demo AppPreview
- ProductDemo: enable bleed on the static AppPreview (fixed 1040x676 window,
  bleeds right when narrow, centers when wide) and clip the section overflow so
  the bleed never causes horizontal page scroll.
- Drop PreviewRoot's leftover margin-bottom; the bleed window already owns its
  below-space (consistent with HomeHero), so the old aspect-era margin just
  double-stacked.
2026-06-06 23:05:24 +05:00
Abdullah 4792b49ade feat(website): bleed the ProductHero intro + align spacing with HomeHero
- ProductVisual: add a bleed mode (fixed 1040x676 window, no aspect/flex
  scaling) so the intro window holds full scale and bleeds right instead of
  aspect-shrinking. Enable it on the desktop + mobile intro instances.
- HeroVisualScroll: render the halftone background on mobile too (it was
  desktop-only), scoped to the visual area and stretched into the bottom space.
- Match ProductHero spacing to HomeHero: body margin, CTA-to-visual gap
  (row-gap on FullLayer + MobileSection), and the mobile top padding (the
  in-flow mobile branch no longer double-counts sticky-nav clearance).
  Replace raw px with theme.spacing.
2026-06-06 22:53:16 +05:00
Abdullah 0f4064d326 feat(website): bleed the HomeHero app window at fixed scale
- AppPreview: add a bleed mode (BleedShellScene) — fixed 1040x676 window box
  with margin auto (centers when it fits, bleeds right when narrower), constant
  section height, and a fixed below-window space. No aspect-ratio.
- AppWindow: fill the box (width INITIAL_MAX_WIDTH, height = parent) instead of
  capping to an aspect ratio, so the window stays full-scale and bleeds.
- HomeHero: opt into bleed.
- Terminal: anchor the AI chat to the fixed window box (no width-drift), tune its
  bottom/right offsets, and CSS-hide it below 1350px (no hydration flash).
- Update terminal-window-geometry offsets + test.
2026-06-06 20:03:22 +05:00
Abdullah 8c0a0f08ea fix(website): prevent demo AppPreview from overflowing on responsive widths
ProductDemo's grid wrappers used grid-template-columns: 1fr, whose auto min
floors the column at the AppPreview's intrinsic min-content width (from its
aspect-ratio + max-height). On mid widths the column blew out wider than the
container and the window overflowed right. Use minmax(0, 1fr) + min-width: 0
(matching HeroSection) so the column can shrink to fit.
2026-06-05 19:58:38 +05:00
Abdullah 1d1c3dc9f3 Fill the hero visual and full-bleed the halftone behind it
- ProductVisual/AppPreviewFrame: add a fill mode that crops the natural-aspect
  window to the available area (top-aligned, overflow) instead of stretching, so
  the visual fills the pinned frame without distortion. Mobile stays aspect-locked.
- HeroVisualScroll: make the pattern overlay full-bleed (inset:0) so the halftone
  covers the whole frame behind the visual instead of a fixed bottom band.
- use-product-background-halftone: map the image with a true cover (fill both
  axes, crop overflow) instead of cover-by-width, so the pattern reaches full
  height on tall viewports instead of letterboxing into a low band.
2026-06-05 18:51:20 +05:00
Abdullah 71a8142346 Open the AI panel on hero->AI scroll and fix tab focus ring
- AppPreviewLayout: render the right aside in a width-animated slot driven by
  asideProgress, so the board reflows smaller as the panel opens (instead of
  overlaying). Hidden below md to match AiPanel.
- ProductVisual: thread aiPanelProgress -> asideProgress.
- HeroVisualScroll: derive aiPanelProgress from morphProgress so the Ask AI
  panel slides open as the section wipes in, and start playback once it's open
  (thinking -> answer -> board builds as the result), so the section reads as AI.
- TabButton: preventDefault on mousedown so the :focus-visible ring no longer
  lingers after a pointer click while keyboard focus still shows it.
2026-06-05 16:46:47 +05:00
Abdullah.andGitHub 3b69047b83 Merge branch 'main' into website-product-hero 2026-06-05 14:35:41 +05:00
Abdullah becae12903 chore(website): downscale product-hero wheat bg and convert to webp
The source was a 4.2MB 6720x4480 JPEG used only as a WebGL halftone source.
Resize to 2048x1365 and encode as webp (q80) -> 170KB (~96% smaller), matching
the repo's webp convention.
2026-06-04 19:18:33 +05:00
Abdullah.andGitHub 86cad7aee6 Merge branch 'main' into website-product-hero 2026-06-04 14:49:54 +05:00
Abdullah 81b2155e7d Render product hero as stacked sections below md
The sticky scroll-morph relied on 200vh/100dvh/innerHeight which disagree on
mobile (toolbar-driven viewport), causing jumpy scroll and a long dead-scroll
tail, and the flex:1 visual reserved full-viewport height under a short
aspect-ratio preview, leaving an empty band. Below md, drop the morph and
render the intro and AI as two plain content-sized sections.
2026-06-03 17:58:15 +05:00
Abdullah 5c6701e37a Refine product-hero cursor handoffs and simplify tour state
- Wait for the previous cursor to return home before the next moves on the
  Anthropic-row and Notes-tab handoffs (insert home-hold beats)
- Make the loop seam return to the settle beat so Cara lands home before
  Alice starts, and give her cross-window return room (cap 960->1000, longer
  Companies-rail move + seam beat) instead of the old slow-glide override
- Drop CURSOR_COUNT: the hook now returns the active cursor's state and
  ProductVisual derives per-cursor state from HERO_CURSORS; idle cursors
  default to home via an optional target prop
2026-06-03 17:25:39 +05:00
Abdullah 1e196e410d feat(website): float product-hero multiplayer cursors in the hero layer
Portal the cursors out of the clipped visual into the intro hero layer so
they rest in the page whitespace (and still glide onto in-window targets,
which the layer contains). Reposition the three home spots accordingly.
2026-06-03 16:37:49 +05:00
Abdullah 729b8269a0 refactor(website): strip inert machinery from product-hero halftone
Remove the HomeHero-derived zoom/footprint-scale system, image pixel
offsets, edgeFade/solidness, and applyToDarkAreas from the product
background halftone -- all were no-ops at the fixed settings. Render is
unchanged; the shader is now just a cover-fit image pass + halftone pass.
2026-06-03 16:20:06 +05:00
Abdullah 15795191d4 chore(website): rename product-hero wheat asset to home-background-wheat 2026-06-03 16:13:17 +05:00
Abdullah 632bf9609f feat(website): wheat-field halftone background for product hero
Adopt the halftone-studio wheat-field look in the existing typed,
visual-runtime-based ProductBackgroundHalftone instead of the standalone
studio export: cover-fit image, denser dash settings (tile 8, power 0.1,
width 0.52, contrast 0.95), and per-layer dash color (purple on the white
intro, white on the dark AI section). Removes the orphaned ai-bg-1 asset.
2026-06-03 16:09:23 +05:00
Abdullah 05eea18241 feat(website): image-driven halftone background for product hero
Replace the procedural product-hero background with an image-driven
two-pass halftone (HomeHero-style), full-bleed behind the visual,
sampling a mapped landscape image.
2026-06-03 00:20:36 +05:00
Abdullah bd86e3f3f1 refactor(website): drop dead code in product-hero autoplay
Remove the unused preambleComplete return and two unnecessary useMemos
(fullTextVisibleLength, scenePhase) that memoized trivial pure computations.
2026-06-02 20:01:43 +05:00
Abdullah 33480c6699 feat(website): multiplayer cursors for the product-hero AI demo
- Render three labelled cursors (Alice/Ben/Cara) that frame the visual at
  its edges and take turns clicking through the tour
- Give every view (Companies, the three record tabs, People, Notes) an
  equal ~1700ms on screen
- Time cursor glides from pixel distance anchored to a calm baseline so
  short and long moves read as synchronized, and skip sub-threshold
  re-measures so an in-flight glide is never snapped
- Slow Alice's approach to the Anthropic row so she lands as Cara finishes
  her cross-window return home
2026-06-02 19:58:06 +05:00
Abdullah ac5eb7cc5e feat(website): tighten product-hero stack and refine collapse/spread timing
- Tighten the resting stack (offsets [0,4,8,12], subtler per-card scale)
- Snappy vertical collapse (0.62-0.66) handing straight off to the
  horizontal spread with no overlap or waiting gap
- Slow, eased horizontal spread (0.66-0.93) landing before the selector
  reveal; move the appear entrance and deck shift to match the tighter stack
2026-06-02 18:23:54 +05:00
Abdullah e3839c364f feat(website): split product-hero prompt buttons to the sides earlier
Move the tab stack align/spread windows earlier in the morph so the
buttons fan out to the sides sooner (align 0.50-0.66, spread 0.64-0.84).
2026-06-02 18:01:22 +05:00
Abdullah 764421d8ff feat(website): use semantic tabler icons for product-hero prompt chips
Replace the generic eye/check/lightbulb/code glyphs with icons that match
each prompt: kanban board, checklist, bar chart, and workflow hierarchy.
Added as new informative-icon registry keys so existing usages are unchanged.
2026-06-02 17:53:19 +05:00
Abdullah 231a4715df fix(website): product-hero skeleton polish and earlier view reveal
- Reveal skeleton-loader views (kanban, table, dashboard, workflow) as
  soon as the answer starts streaming instead of after it completes
- Neutralize the skeleton shimmer to twenty-front's grey palette
  (#f1f1f1 base) to remove the cool/blue cast
- Widen entity chip horizontal padding to 3px 6px to match the vertical
2026-06-02 17:47:29 +05:00
Abdullah ea4f27caca feat(website): match product-hero AI panel to twenty-front
Align the product-hero AI chat panel with twenty-front's real chat:
- Type scale: 13px title/messages/chips, 12px thinking-step labels
- Thinking rows use twenty's primitives — orbit loader (active), IconCpu
  (done), light/tertiary icon tones, plain (non-shimmer) labels
- Collapse finished steps into an "N steps" summary, mirroring
  ThinkingStepsDisplay's expand/collapse logic
- Stream the assistant response as separate paragraphs (string[] so each
  stays an independent translation unit) with twenty's 8px paragraph
  spacing and 1.5 line-height
2026-06-02 17:28:49 +05:00
Abdullah 077d5ee500 refactor(website): share one fade keyframe across workflow node content
- Replace the three duplicate workflowNode*Appear keyframes with a single nodeContentAppear css fragment applied via className
- Keeps the keyframe and its animation co-located so Linaria scopes them together (single source of truth for timing)
2026-06-01 20:03:05 +05:00
Abdullah d17e90b931 fix(website): remove the page flash when the product hero tour clicks the sidebar
- Set each rail click's destination pageItemId during the click phase so selectPageItem applies before the reveal
- Prevents the record -> stale Companies -> People flash (and equivalent stale frames on the other rail clicks)
2026-06-01 19:54:45 +05:00
Abdullah 802b1468cf fix(website): shorten the Notes/Calendar dwell in the product hero record tour
- Cut the Notes and Calendar tab dwell ~1/3 so the cursor lingers less and each tab is in view briefly
2026-06-01 19:46:36 +05:00
Abdullah 6e4a2ec185 refactor(website): address product hero review feedback
- Collapse the duplicate viewbar wrappers into a single ViewbarBar
- Style the workflow canvas via a data-workflow-canvas hook instead of an aria-label substring + positional selector
- Use the TABLE_PAGE_COLORS.text token for the checkbox border instead of a hardcoded hex
- Extract shared rail-item styles into a css fragment
- Match the workflow skeleton icon radius to the real node icon
2026-06-01 19:46:35 +05:00
Abdullah b346237263 feat(website): reset the AI section to the first tab when the hero returns to the top
- Reset activeTab to 0 once morphProgress falls back to 0 (fully scrolled back to the intro)
- Partial scroll-backs keep the selected tab
2026-06-01 17:29:31 +05:00
Abdullah e49dcc3183 feat(website): restart the product hero intro tour when scrolling back from the AI section
- Gate the collaborative cursor tour on the intro being the dominant view (morphProgress < 0.5)
- Reset the tour to its first phase when disabled so re-entering the intro replays from the start
2026-06-01 17:09:31 +05:00
Abdullah 8010e28b24 fix(website): coherent AI-section counts and clean ARR chart reveal
- Hide the pipeline/tasks header count while generating so it reads as built by AI, not pre-existing
- Show 10 tasks (the count the AI claims) instead of base+new
- Fade the ARR line/area in as a complete line instead of a stroke-draw that flashed a partial segment
2026-06-01 16:57:26 +05:00
Abdullah 5312a2fd56 feat(website): drive the product hero record tabs with the cursor
- Externally control the record's active tab (RecordPageDefinition.activeTabLabel); disable self-advance when controlled
- Cursor clicks Timeline -> Notes -> Calendar before navigating the sidebar, so tabs no longer flip on their own
- Add a tab cursor target (data-record-tab) and tune rail/tab landing offsets and the row->tab glide pacing
2026-06-01 16:30:22 +05:00
Abdullah a12a060985 feat(website): turn the product hero intro into a guided multi-page tour
- Replace the single-record tab loop with a looping cursor tour: Companies -> Anthropic record -> People -> Notes
- Keep the cursor hidden while the record plays its tabs to Calendar, then navigate the sidebar rail
- Generalize the hero cursor to target table rows and rail items; add data-rail-item-id to rail items
- Deliberately avoid the AI section's surfaces (pipeline/tasks/dashboard/workflow)
2026-06-01 16:18:27 +05:00
Abdullah c5ffdd13a9 chore(website): remove dead OpenAI/Sam Altman demo data from product hero
- Delete the unused NEW_COMPANY_ROW/NEW_PERSON_ROW lead-creation rows and their resolveDisplayPage branch
- Clear the intro scene's unused AI response copy and prune the now-dead scene phases
- Replace Sam Altman (a competitor CEO) in Anthropic's QBR with a generic teammate
2026-06-01 15:44:06 +05:00
Abdullah 3fcfb39e7d fix(website): align pipeline board stages with copy and soften halftone hover
- Rename kanban lanes to New/Screening/Meeting/Proposal/Customer to match the AI response copy, the dashboard's deals-by-stage chart, and Twenty's default opportunity stages
- Reduce the halftone hover lift intensity and make it a tunable constant
2026-06-01 15:29:10 +05:00
Abdullah 80e0d6092e feat(website): darker, dashed hero halftone tone and pattern
- Add a solidness control to the product halftone; intro renders darker, edge-to-edge dashes while the AI section keeps its faded look
- Cap dash half-length so dense cells stay dashed instead of merging into solid lines (both heroes)
2026-06-01 15:15:53 +05:00
Abdullah 41baeefcae feat(website): stage the product hero workflow build animation
- Suppress edges, branch labels and plus node during generation so it no longer looks pre-built
- Draw edges in sequentially, then ease in ports, connector, labels and the add-node as a finale
- Fade in node content; drive edge stagger via inline animationDelay to avoid leaking a DOM prop
2026-06-01 06:58:38 +05:00
Abdullah e261f1268e feat(website): reuse AI halftone for product hero intro, scoped to the visual
- Drop the bespoke intro halftone; render the AI section's halftone tinted with the intro's blue
- Scope both hero halftones inside the visual wrapper so they no longer sit behind the CTA/tab buttons
- Remove the now-orphaned ProductIntroHalftone, its hook, and the skyline texture
2026-06-01 06:44:40 +05:00
Abdullah a42f91e494 feat(website): flow the hero color wipe up into the product menu
- Span the dark wipe across the full viewport so it rises continuously through the nav
- Make the menu transparent only while the black sweeps through it, solid (dark) once complete, and white again on exit
- Shorten AI hero tab labels to fit without ellipsis while keeping full prompts
2026-06-01 06:32:50 +05:00
Abdullah 108d850000 feat(website): coherent skeleton loading and real charts across product hero AI scenes
- Stream the AI answer first, reveal the CRM artifact as a finale
- Restructure the 4 AI prompts into build pillars (board, tasks, dashboard, workflow)
- Render real animated SVG charts for the dashboard, matched to twenty-front step-8 palette
- Add a unified `generating` skeleton state across table, kanban, workflow and dashboard surfaces
- Share PreviewSkeleton primitives with a single shimmer keyframe
2026-06-01 05:26:08 +05:00
Abdullah e346b9f505 feat(website): add agentic thinking + tool steps to product hero AI panel 2026-06-01 03:00:59 +05:00
Abdullah cd1c188fb1 feat(website): cycle record tabs with twenty-front parity and post-tour clicking 2026-06-01 02:12:30 +05:00
Abdullah 27b2f0cab7 feat(website): render full-fidelity timeline on product hero record page 2026-06-01 00:35:37 +05:00
Abdullah 45aa0898f2 feat(website): replace product hero intro AI panel with collaborative cursor demo 2026-05-31 23:53:00 +05:00
Abdullah 0ff7b6b365 fix(website): start product hero morph on first scroll 2026-05-31 22:46:08 +05:00
Abdullah 2a77c4c7f5 chore(website): remove orphaned image assets (zero references) 2026-05-31 21:40:01 +05:00
Abdullah e5be4e09e5 refactor(website): drop dead guard on required stepVisuals prop 2026-05-31 21:35:56 +05:00
Abdullah 0759333e8f refactor(twenty-website): type the social/client icon registries + catalog widths
Continue Phase 0 across the icon/identifier registries:
- SOCIAL_ICONS and CLIENT_ICONS now use 'satisfies' and export their key unions
  (SocialIconKey, ClientIconKey).
- Type the data fields against them: MenuSocialLinkType.icon, HeadingCardType.icon,
  and CaseStudy/CaseStudyCatalog 'clientIcon' (was string) — all compile-checked.
- CATALOG_LOGO_WIDTHS becomes a total Record<ClientIconKey, number>; its '?? 140'
  defaults are now dead (a new client is a compile error, not a silent default).
- Remove the now-dead guards: 'if (!IconComponent) return null' in Menu Social +
  Drawer, and the 'IconComponent ? : null' in HelpedCard. Footer's social icon,
  previously unguarded over a lying Record<string>, is now type-safe.

typecheck/lint/build green; all existing keys were valid.
2026-05-31 20:15:30 +05:00
Abdullah 7d3a5802be refactor(twenty-website): type the INFORMATIVE_ICONS registry + its keys
Phase 0 (type-tightening), first registry. INFORMATIVE_ICONS was annotated
Record<string, …>, so every icon key compiled unchecked and every lookup was
typed as always-defined while actually being maybe-undefined at runtime — which
is why each call site carried an 'Icon ? … : null' guard.

- Type the registry with 'satisfies' so it self-describes its key union, and
  export InformativeIconKey = keyof typeof INFORMATIVE_ICONS.
- Replace 'icon: string' with InformativeIconKey in TabType, the product-stepper
  step types, and FeatureBullet — icon keys in data are now compile-checked.
- Drop the now-redundant 'as keyof' cast and the three dead 'Icon ? : null'
  guards (the lookup is provably defined for a valid key).

typecheck/lint/build green; every existing icon value was already valid.
2026-05-31 20:00:10 +05:00
Abdullah 1522704387 style(twenty-website): format product-hero files to oxfmt
The product-hero branch's files predated main's oxfmt config and failed
oxfmt --check after the merge. Apply oxfmt across them (AppPreview, ProductVisual,
the app-preview data) — formatting only, no behavior change. Kept as its own
commit so the structural cleanup stays reviewable.
2026-05-31 19:22:21 +05:00
Abdullah 623847251f refactor(twenty-website): tidy product-hero merge artifacts
Post-merge structural cleanup found by auditing the auto-merged files:
- Remove hero-scroll-colors.ts — ~200 lines of scroll/color helpers that were
  already dead on the branch (zero importers, pre-merge).
- Lift app-preview.data.ts out of the app/(home) route folder into the
  AppPreview section that owns it, and export APP_PREVIEW_DATA from the section
  barrel. Breaks the home->product cross-route data coupling; home, product
  hero, and product demo now all import it from @/sections/AppPreview. The data
  file's type import points at ./types to avoid a barrel cycle.

typecheck (tsc + tsgo), build, boundaries, section-shape, oxlint all pass.
2026-05-31 19:20:18 +05:00
Abdullah d724a587f7 refactor(twenty-website): rework product hero onto post-refactor structure
Reconcile the product-hero branch with main's restructure (page-local blocks,
flattened Menu):
- ProductHeroMenuSync: rebuild against the flat <Menu> (the refactor removed the
  compound Menu.Root/.Logo/.Nav/.Cta API). It now renders <Menu> with the
  scroll-derived backgroundColor + scheme; the morph-progress context the hero
  feeds is unchanged.
- product/page.tsx: wrap the page-local <ProductHero> in <ProductHeroMenuSync>
  (which now owns the menu) instead of rendering a static <Menu>.
- ProductHero: re-apply the branch's refined hero copy and restore the
  'Talk to us' secondary CTA (introSecondaryCta), as <Trans> units.
- Fix two pre-existing lint errors the merge surfaced (unused theme import;
  duplicated SidebarDesktopItem import).
2026-05-31 18:39:37 +05:00
Abdullah 1c41422177 Merge branch 'main' into website-product-hero
# Conflicts:
#	packages/twenty-website/src/app/[locale]/product/page.tsx
#	packages/twenty-website/src/sections/Demo/components/Preview.tsx
2026-05-31 18:21:03 +05:00
Abdullah b24acd0c98 fix: row gap between subtitle and buttons 2026-05-26 19:56:53 +05:00
Abdullah e0056ff197 fix: button stacking 2026-05-26 01:13:20 +05:00
Abdullah edca145544 feat(website): refine product hero ai demos and app preview navigation 2026-05-26 00:42:53 +05:00
Abdullah 635157e7d0 feat(website): refine product hero ai transition and preview fidelity 2026-05-25 22:36:47 +05:00
Abdullah 504494ebfa feat(website): refine app preview fidelity across product hero scenes 2026-05-25 20:04:33 +05:00
Abdullah f04958469e feat(website): add symmetric skyline halftone to product hero intro
Adds a halftone background effect to the product hero intro section using
a symmetric skyline image with edge-detected outlines, matching the Home
Hero's proven halftone architecture and parameters.
2026-05-24 12:48:01 +05:00
Abdullah 776ce25617 feat(website): update product hero intro background image 2026-05-23 21:05:02 +05:00
Abdullah 06a2b2dc04 feat(website): add procedural halftone background and fix hydration errors
- Replace static background image with procedural WebGL halftone glow on AI layer
- Refactor hero to clip-path wipe transition with two stacked layers
- Fix hydration mismatch by removing useId() from EditIcon and HeroVisualScroll
- Add ProductBackgroundHalftone component with mouse-follow hover interaction
2026-05-23 20:37:48 +05:00
Abdullah 431d487b6a feat(website): smooth scroll-driven hero morph with synced nav
Replace the binary phase-switch hero with a continuous scroll-driven
morph: background/nav interpolate smoothly while text swaps at the
threshold. Nav reverts to light only after the hero leaves the viewport.
2026-05-22 15:18:32 +05:00
Abdullah 2e081575fe feat(website): add sliding hero tabs and improve mobile nav color sync
Introduce a sliding tab indicator for the product AI hero and align the
sticky nav transition on mobile with the intro/AI boundary using measured
nav height, earlier lead offset, and blur-free solid backgrounds.
2026-05-22 15:18:32 +05:00
Abdullah 90d09fe0a5 fix(website): polish product hero opacity sync and hydration
Align dark overlay and nav opacity with the AI panel when fully in view,
use stable tab ids and remove Edit icon clipPath useId to fix SSR mismatches,
and stabilize menu scroll effect dependencies.
2026-05-22 15:18:31 +05:00
Abdullah bba61c3245 feat(website): sync product nav with hero scroll color transition
Drive the product page navbar from hero scroll progress with opacity-based
light-to-dark transitions, including fade back to light when leaving the AI section.
2026-05-22 15:18:31 +05:00
Abdullah a737a3c8fe feat(website): add scroll-driven product hero with stacked mobile layout
Replace the static product hero with a unified intro-to-AI scroll transition on
desktop and a stacked mobile layout, including taller preview sizing and updated
AI heading copy.
2026-05-22 15:18:31 +05:00
396 changed files with 11931 additions and 17246 deletions
+3 -28
View File
@@ -6,43 +6,18 @@ permissions:
on:
push:
tags:
- 'twenty/v*'
- 'sdk/v*'
defaults:
run:
shell: bash --noprofile --norc -euo pipefail {0}
- 'v*'
jobs:
dispatch-tag:
deploy-tag:
timeout-minutes: 3
runs-on: ubuntu-latest
steps:
- name: Resolve dispatch event from tag family
id: target
env:
REF_NAME: ${{ github.ref_name }}
run: |
case "$REF_NAME" in
twenty/v*)
event_type=auto-deploy-twenty
;;
sdk/v*)
event_type=auto-publish-npm
;;
*)
echo "Unsupported tag '$REF_NAME', expected 'twenty/v*' or 'sdk/v*'." >&2
exit 1
;;
esac
printf 'event_type=%s\n' "$event_type" >> "$GITHUB_OUTPUT"
- name: Repository Dispatch
env:
GH_TOKEN: ${{ secrets.TWENTY_INFRA_TOKEN }}
EVENT_TYPE: ${{ steps.target.outputs.event_type }}
REF_NAME: ${{ github.ref_name }}
run: |
gh api repos/twentyhq/twenty-infra/dispatches \
-f "event_type=$EVENT_TYPE" \
-f event_type=auto-deploy-tag \
-f "client_payload[github][ref_name]=$REF_NAME"
+63
View File
@@ -0,0 +1,63 @@
name: "Release: on merge"
permissions:
contents: write
on:
pull_request:
types:
- closed
defaults:
run:
shell: bash --noprofile --norc -euo pipefail {0}
jobs:
tag_and_release:
timeout-minutes: 10
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'release')
steps:
- name: Check PR Author
id: check_author
env:
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
run: |
set -euo pipefail
if [[ "$PR_AUTHOR" != "github-actions[bot]" ]]; then
echo "PR author ($PR_AUTHOR) is not trusted. Exiting."
exit 1
fi
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
ref: main
- name: Get version from PR title
id: extract_version
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
set -euo pipefail
VERSION=$(printf '%s' "$PR_TITLE" | sed -n 's/.*Release v\([0-9][0-9.]*\).*/\1/p')
if [ -z "$VERSION" ]; then
echo "No valid version found in PR title. Exiting."
exit 1
fi
printf 'VERSION=%s\n' "$VERSION" >> "$GITHUB_ENV"
- name: Push new tag
run: |
set -euo pipefail
git config --global user.name 'Github Action Deploy'
git config --global user.email '[email protected]'
git tag "v${{ env.VERSION }}"
git push origin "v${{ env.VERSION }}"
- uses: release-drafter/release-drafter@09c613e259eb8d4e7c81c2cb00618eb5fc4575a7 # v5
if: contains(github.event.pull_request.labels.*.name, 'create_release')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag: v${{ env.VERSION }}
-1
View File
@@ -52,7 +52,6 @@
"packages/twenty-server",
"packages/twenty-emails",
"packages/twenty-ui",
"packages/twenty-new-ui",
"packages/twenty-utils",
"packages/twenty-zapier",
"packages/twenty-website",
@@ -1787,7 +1787,6 @@ enum FeatureFlagKey {
IS_REST_METADATA_API_NEW_FORMAT_DIRECT
IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED
IS_SETTINGS_DISCOVERY_HERO_ENABLED
IS_CALL_RECORDING_ENABLED
IS_WORKFLOW_RUN_STEP_LOGS_ENABLED
}
@@ -1414,7 +1414,7 @@ export interface FeatureFlag {
__typename: 'FeatureFlag'
}
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' | 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' | 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' | 'IS_CALL_RECORDING_ENABLED' | 'IS_WORKFLOW_RUN_STEP_LOGS_ENABLED'
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' | 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' | 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' | 'IS_WORKFLOW_RUN_STEP_LOGS_ENABLED'
export interface WorkspaceUrls {
customUrl?: Scalars['String']
@@ -8812,7 +8812,6 @@ export const enumFeatureFlagKey = {
IS_REST_METADATA_API_NEW_FORMAT_DIRECT: 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' as const,
IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED: 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' as const,
IS_SETTINGS_DISCOVERY_HERO_ENABLED: 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' as const,
IS_CALL_RECORDING_ENABLED: 'IS_CALL_RECORDING_ENABLED' as const,
IS_WORKFLOW_RUN_STEP_LOGS_ENABLED: 'IS_WORKFLOW_RUN_STEP_LOGS_ENABLED' as const
}
@@ -283,7 +283,6 @@ export type FeatureFlag = {
};
export enum FeatureFlagKey {
IS_CALL_RECORDING_ENABLED = 'IS_CALL_RECORDING_ENABLED',
IS_EMAIL_GROUP_ENABLED = 'IS_EMAIL_GROUP_ENABLED',
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
@@ -1648,7 +1648,6 @@ export type FeatureFlag = {
};
export enum FeatureFlagKey {
IS_CALL_RECORDING_ENABLED = 'IS_CALL_RECORDING_ENABLED',
IS_EMAIL_GROUP_ENABLED = 'IS_EMAIL_GROUP_ENABLED',
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
@@ -30,7 +30,7 @@ export default meta;
export type Story = StoryObj<typeof RecordIndexPage>;
export const Default: Story = {
// oxlint-disable-next-line typescript/ban-ts-comment
// oxlint-disable-next-line @typescripttypescript/ban-ts-comment
// @ts-ignore
decorators: [LoadingDecorator, PageDecorator],
play: async ({ canvasElement }) => {
@@ -79,7 +79,7 @@ export type Story = StoryObj<typeof RecordIndexPage>;
export const Default: Story = {
parameters: userMetadataLoaderMocks,
// oxlint-disable-next-line typescript/ban-ts-comment
// oxlint-disable-next-line @typescripttypescript/ban-ts-comment
// @ts-ignore
decorators: [PageDecorator],
play: async ({ canvasElement }) => {
@@ -32,7 +32,7 @@ export const StepBar = ({ activeStep, children }: StepBarProps) => {
}
// If the child is not a Step, return it as-is
// oxlint-disable-next-line typescript/ban-ts-comment
// oxlint-disable-next-line @typescripttypescript/ban-ts-comment
// @ts-expect-error
if (child.type?.displayName !== Step.displayName) {
return child;
@@ -64,7 +64,7 @@ export type Story = StoryObj<typeof RecordShowPage>;
// TEMP_DISABLED_TEST: Temporarily commented out due to test failure
// export const Default: Story = {
// // oxlint-disable-next-line typescript/ban-ts-comment
// // oxlint-disable-next-line @typescripttypescript/ban-ts-comment
// // @ts-ignore
// decorators: [PageDecorator, ContextStoreDecorator],
// play: async ({ canvasElement }) => {
@@ -1,4 +1,4 @@
// oxlint-disable-next-line typescript/ban-ts-comment
// oxlint-disable-next-line @typescripttypescript/ban-ts-comment
// @ts-ignore
import { type WorkflowRun } from '@/workflow/types/Workflow';
import { StepStatus } from 'twenty-shared/workflow';
-77
View File
@@ -1,77 +0,0 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["react", "typescript", "import", "unicorn"],
"jsPlugins": ["../twenty-oxlint-rules/dist/oxlint-plugin.mjs"],
"categories": {
"correctness": "off"
},
"ignorePatterns": ["node_modules", "generated", "**/*.module.scss.d.ts"],
"rules": {
"func-style": ["error", "declaration", { "allowArrowFunctions": true }],
"no-console": [
"warn",
{ "allow": ["group", "groupCollapsed", "groupEnd"] }
],
"no-control-regex": "off",
"no-debugger": "error",
"no-duplicate-imports": "error",
"no-undef": "off",
"no-unused-vars": "off",
"no-redeclare": "off",
"import/no-duplicates": "error",
"react/no-unescaped-entities": "off",
"react/prop-types": "off",
"react/jsx-key": "off",
"react/display-name": "off",
"react/jsx-uses-react": "off",
"react/react-in-jsx-scope": "off",
"react/jsx-no-useless-fragment": "off",
"react/jsx-props-no-spreading": ["error", { "explicitSpread": "ignore" }],
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"typescript/no-redeclare": "error",
"typescript/ban-ts-comment": "error",
"typescript/consistent-type-imports": [
"error",
{
"prefer": "type-imports",
"fixStyle": "inline-type-imports"
}
],
"typescript/explicit-function-return-type": "off",
"typescript/explicit-module-boundary-types": "off",
"typescript/no-empty-object-type": [
"error",
{
"allowInterfaces": "with-single-extends"
}
],
"typescript/no-empty-function": "off",
"typescript/no-explicit-any": "off",
"typescript/no-unused-vars": [
"warn",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_"
}
],
"twenty/enforce-module-boundaries": [
"error",
{
"depConstraints": [
{
"sourceTag": "scope:shared",
"onlyDependOnLibsWithTags": ["scope:shared"]
}
]
}
]
}
}
-6
View File
@@ -1,6 +0,0 @@
dist
storybook-static
coverage
# Generated by vite-plugin-sass-dts (committed; regenerated in dev mode).
*.module.scss.d.ts
-78
View File
@@ -1,78 +0,0 @@
[
{
"name": ". (root barrel)",
"path": "dist/index.mjs",
"limit": "60 kB",
"import": "*"
},
{
"name": "accessibility",
"path": "dist/accessibility.mjs",
"limit": "10 kB"
},
{
"name": "assets",
"path": "dist/assets.mjs",
"limit": "10 kB"
},
{
"name": "testing",
"path": "dist/testing.mjs",
"limit": "10 kB"
},
{
"name": "components",
"path": "dist/components.mjs",
"limit": "40 kB"
},
{
"name": "display",
"path": "dist/display.mjs",
"limit": "30 kB"
},
{
"name": "feedback",
"path": "dist/feedback.mjs",
"limit": "20 kB"
},
{
"name": "input",
"path": "dist/input.mjs",
"limit": "50 kB"
},
{
"name": "layout",
"path": "dist/layout.mjs",
"limit": "20 kB"
},
{
"name": "navigation",
"path": "dist/navigation.mjs",
"limit": "20 kB"
},
{
"name": "json-visualizer",
"path": "dist/json-visualizer.mjs",
"limit": "30 kB"
},
{
"name": "theme",
"path": "dist/theme.mjs",
"limit": "55 kB"
},
{
"name": "theme-constants",
"path": "dist/theme-constants.mjs",
"limit": "20 kB"
},
{
"name": "utilities",
"path": "dist/utilities.mjs",
"limit": "10 kB"
},
{
"name": "style.css",
"path": "dist/style.css",
"limit": "40 kB"
}
]
-58
View File
@@ -1,58 +0,0 @@
import type { StorybookConfig } from '@storybook/react-vite';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import checker from 'vite-plugin-checker';
const dirname =
typeof __dirname !== 'undefined'
? __dirname
: path.dirname(fileURLToPath(import.meta.url));
const isVitest = Boolean(process.env.VITEST);
const config: StorybookConfig = {
stories: ['../src/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'],
addons: [
'@storybook-community/storybook-addon-cookie',
'@storybook/addon-links',
'@storybook/addon-coverage',
'@storybook/addon-a11y',
'storybook-addon-pseudo-states',
'@storybook/addon-vitest',
],
framework: '@storybook/react-vite',
viteFinal: async (viteConfig) => {
const plugins = [...(viteConfig.plugins ?? [])];
if (!isVitest) {
plugins.push(
checker({
typescript: {
tsconfigPath: path.resolve(dirname, '../tsconfig.json'),
},
}),
);
}
return {
...viteConfig,
plugins,
resolve: {
...viteConfig.resolve,
alias: {
...(viteConfig.resolve?.alias ?? {}),
'@tabler/icons-react': '@tabler/icons-react/dist/esm/icons/index.mjs',
},
},
};
},
};
export default config;
// To customize your Vite configuration you can use the viteFinal field.
// Check https://storybook.js.org/docs/react/builders/vite#configuration
// and https://nx.dev/recipes/storybook/custom-builder-configs
@@ -1,34 +0,0 @@
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
rel="stylesheet"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.7/iframeResizer.contentWindow.min.js"></script>
<style type="text/css">
body {
margin: 0;
font-family: 'Inter', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
html {
font-size: 13px;
}
.sbdocs-wrapper {
padding: 0 !important;
}
*::-webkit-scrollbar {
height: 4px;
width: 4px;
}
*::-webkit-scrollbar-corner {
background-color: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: transparent;
border-radius: 2px;
}
</style>
@@ -1,24 +0,0 @@
import { type Preview } from '@storybook/react-vite';
import '@new-ui/theme-constants/theme-light.css';
import '@new-ui/theme-constants/theme-dark.css';
import { ThemeProvider } from '@new-ui/theme-constants';
const preview: Preview = {
tags: ['autodocs'],
parameters: {
a11y: {
test: 'error',
},
},
decorators: [
(Story) => {
return (
<ThemeProvider colorScheme="light">
<Story />
</ThemeProvider>
);
},
],
};
export default preview;
@@ -1,5 +0,0 @@
import { setProjectAnnotations } from '@storybook/react-vite';
import * as projectAnnotations from './preview';
// Apply Storybook's preview configuration to Vitest runs.
setProjectAnnotations([projectAnnotations]);
+57 -13
View File
@@ -1,10 +1,6 @@
# twenty-new-ui
> **Status:** Phase 0 — Foundations in progress. The package is scaffolded and builds
> on SCSS Modules + Base UI; the theme layer is ported from `twenty-ui` with a parity
> test, and the size/Storybook/a11y harnesses are wired up. Remaining Phase 0 work: the
> CI diff-table workflow, the `twenty-ui` component inventory, and the `modules/ui` triage.
> The sections below remain the design document for the full effort.
> **Status:** Planning. This is a design document; no implementation has started.
`twenty-new-ui` is the next generation of Twenty's UI library, replacing [`twenty-ui`](../twenty-ui).
It is built on a headless component library and a zero-runtime, CSS-variable styling layer.
@@ -34,9 +30,8 @@ components are now **in scope** — they migrate into `twenty-new-ui` (see [Appl
## Decision 1 — Headless library: Base UI
Adopt **Base UI** ([`mui/base-ui`](https://github.com/mui/base-ui), published to npm as
[`@base-ui/react`](https://base-ui.com), MIT) as the behavioral foundation; build Twenty's visual
design on top of it.
Adopt **Base UI** (`@base-ui-components/react`, MIT) as the behavioral foundation; build Twenty's
visual design on top of it.
| | Base UI | shadcn/ui | Radix |
| --- | --- | --- | --- |
@@ -89,7 +84,7 @@ packages/twenty-new-ui/
├── vitest.config.ts # storybook component tests
├── .storybook/
├── .size-limit.json # per-entry bundle budgets
├── scripts/ # generateBarrels.ts
├── scripts/ # generateBarrels.ts, generateTheme.ts
└── src/
├── styles/ # global: reset, theme vars, mixins, breakpoints
├── theme/ theme-constants/
@@ -111,8 +106,8 @@ as-is.
- Keep the public API identical: `ThemeProvider`, `ThemeContext`, `useTheme`, the `themeCssVariables` shape, `ThemeType`, color helpers, and the `theme-light.css` / `theme-dark.css` exports.
- Reuse `twenty-ui`'s token values verbatim to guarantee identical design.
- Tokens live in `src/theme/` (`THEME_LIGHT` / `THEME_DARK`); the `--t-*` CSS variables and the `themeCssVariables` accessor are static files mirrored token-for-token from `twenty-ui` (matching `twenty-ui`'s own static-CSS approach).
- A theme parity test asserts the theme CSS and `themeCssVariables` stay identical to `twenty-ui`'s `--t-*` values.
- Tokens are authored in `src/theme/` and generated into CSS variables + a typed accessor.
- A generated-output diff test asserts the new theme CSS produces the same `--t-*` values as `twenty-ui`.
## Component migration map
@@ -224,7 +219,7 @@ CI surfaces a per-PR diff table (`twenty-ui` vs `twenty-new-ui`) for size, a11y,
- Vite library mode, dual ESM/CJS, `vite-plugin-dts`, `vite-plugin-svgr`; SCSS via Vite's built-in `sass`; no Babel.
- `sideEffects: ["**/*.css", "**/*.scss"]`; emit per-entry CSS plus `style.css` / `theme-light.css` / `theme-dark.css`.
- Public package (remove `private`); ships as `twenty-new-ui` until cut-over, then claims the `twenty-ui` name once the old package is removed.
- Public package (remove `private`); scoped name (e.g. `@twenty/ui`).
- **Changesets** for semver + changelog; GitHub Actions release with `npm publish --provenance`.
- Declare `react` / `react-dom` as peer dependencies; validate the `exports`/types map with `publint` + `@arethetypeswrong/cli`.
- Publish the Storybook as living documentation.
@@ -264,10 +259,59 @@ a passing visual-parity diff, and a within-budget size entry.
## Open questions
1. Published package name: `twenty-new-ui` now, renamed to `twenty-ui` at cut-over (Phase 6).
1. Published package name/scope (proposed `@twenty/ui`).
2. Styling: confirm SCSS Modules vs vanilla-extract vs plain CSS Modules.
3. Variants helper: `clsx` + `data-*` vs `cva`.
4. Visual regression tooling: Chromatic vs self-hosted image snapshots.
5. How aggressively to drop `framer-motion` in favor of CSS/Base UI transitions.
6. Scope of `assets` / `testing` / `json-visualizer`: port verbatim or modernize.
7. Where to draw the generic-vs-app-specific line for `modules/ui`, and whether hybrid components live as a headless core in `twenty-new-ui` with a thin app wrapper in `twenty-front`.
## Appendix — example component pattern
`src/input/components/Toggle.tsx`
```tsx
import { Switch } from '@base-ui-components/react/switch';
import { clsx } from 'clsx';
import styles from './Toggle.module.scss';
type ToggleProps = {
value?: boolean;
onChange?: (value: boolean) => void;
disabled?: boolean;
size?: 'small' | 'medium';
};
export const Toggle = ({ value, onChange, disabled, size = 'medium' }: ToggleProps) => (
<Switch.Root
checked={value}
onCheckedChange={onChange}
disabled={disabled}
className={clsx(styles.root, styles[size])}
>
<Switch.Thumb className={styles.thumb} />
</Switch.Root>
);
```
`src/input/components/Toggle.module.scss`
```scss
.root {
background: var(--t-background-quaternary);
border-radius: var(--t-border-radius-pill);
transition: background var(--t-animation-duration-fast) ease;
&[data-checked] { background: var(--t-color-blue); }
&[data-disabled] { opacity: 0.32; cursor: not-allowed; }
}
.thumb {
background: var(--t-background-primary);
border-radius: 50%;
transition: translate var(--t-animation-duration-fast) ease;
.root[data-checked] & { translate: 100% 0; }
}
```
@@ -1 +0,0 @@
export default 'test-file-stub';
@@ -1,7 +0,0 @@
// Proxy so `styles.anyClassName` resolves to its key when SCSS is imported in Jest.
module.exports = new Proxy(
{},
{
get: (_target, key) => (key === '__esModule' ? false : String(key)),
},
);
-41
View File
@@ -1,41 +0,0 @@
import { readFileSync } from 'fs';
import { dirname, resolve } from 'path';
import { pathsToModuleNameMapper } from 'ts-jest';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const tsConfigPath = resolve(__dirname, './tsconfig.json');
const tsConfig = JSON.parse(readFileSync(tsConfigPath, 'utf8'));
const jestConfig = {
displayName: 'twenty-new-ui',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['./setupTests.ts'],
testEnvironment: 'jsdom',
transformIgnorePatterns: ['../../node_modules/'],
transform: {
'^.+\\.[tj]sx?$': [
'@swc/jest',
{
jsc: {
parser: { syntax: 'typescript', tsx: true },
transform: { react: { runtime: 'automatic' } },
},
},
],
},
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|webp|svg|svg)$': '<rootDir>/__mocks__/imageMockUi.js',
'\\.(scss|css)$': '<rootDir>/__mocks__/styleMock.js',
...pathsToModuleNameMapper(tsConfig.compilerOptions.paths, {
prefix: '<rootDir>/',
}),
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
extensionsToTreatAsEsm: ['.ts', '.tsx'],
coverageDirectory: './coverage',
};
export default jestConfig;
-208
View File
@@ -1,208 +0,0 @@
{
"name": "twenty-new-ui",
"//name": "Named `twenty-new-ui` because the target name `twenty-ui` is still taken by the existing packages/twenty-ui workspace (Yarn forbids duplicate workspace names). Renamed to `twenty-ui` at the Phase 6 cut-over once the old package is removed.",
"version": "0.0.0",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"style": "./dist/style.css",
"type": "module",
"sideEffects": [
"**/*.css",
"**/*.scss"
],
"devDependencies": {
"@argos-ci/storybook": "^6.0.6",
"@prettier/sync": "^0.5.2",
"@size-limit/preset-small-lib": "^11.1.6",
"@storybook-community/storybook-addon-cookie": "^5.0.0",
"@storybook/addon-a11y": "^10.3.3",
"@storybook/addon-coverage": "^3.0.0",
"@storybook/addon-links": "^10.3.3",
"@storybook/addon-vitest": "^10.2.13",
"@storybook/react-vite": "^10.3.3",
"@swc/core": "^1.15.11",
"@swc/jest": "^0.2.39",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@types/jest": "^30.0.0",
"@types/react": "^18.2.39",
"@types/react-dom": "^18.2.15",
"@vitejs/plugin-react-swc": "4.2.3",
"@vitest/browser-playwright": "4.0.18",
"jest": "29.7.0",
"jest-environment-jsdom": "30.0.0-beta.3",
"prettier": "^3.1.1",
"sass": "^1.83.0",
"sass-embedded": "^1.83.0",
"size-limit": "^11.1.6",
"slash": "^5.1.0",
"storybook-addon-pseudo-states": "^10.3.3",
"ts-jest": "^29.1.1",
"tsx": "^4.19.3",
"vite-plugin-checker": "^0.10.2",
"vite-plugin-dts": "3.8.1",
"vite-plugin-sass-dts": "^1.3.31",
"vite-plugin-svgr": "^4.3.0",
"vite-tsconfig-paths": "^4.2.1",
"vitest": "4.0.18"
},
"dependencies": {
"@base-ui/react": "^1.5.0",
"@monaco-editor/react": "^4.7.0",
"@radix-ui/colors": "^3.0.0",
"@tabler/icons-react": "^3.31.0",
"clsx": "^2.1.1",
"date-fns": "^2.30.0",
"framer-motion": "^11.18.0",
"glob": "^11.1.0",
"hex-rgb": "^5.0.0",
"jotai": "^2.17.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-responsive": "^9.0.2",
"react-router-dom": "^6.4.4",
"twenty-shared": "workspace:*",
"zod": "^4.1.11"
},
"peerDependencies": {
"monaco-editor": ">= 0.25.0 < 1"
},
"scripts": {
"build": "npx vite build"
},
"files": [
"dist",
"accessibility",
"assets",
"components",
"display",
"feedback",
"input",
"json-visualizer",
"layout",
"navigation",
"testing",
"theme",
"theme-constants",
"utilities"
],
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./style.css": "./dist/style.css",
"./theme-light.css": "./dist/theme-light.css",
"./theme-dark.css": "./dist/theme-dark.css",
"./accessibility": {
"types": "./dist/accessibility/index.d.ts",
"import": "./dist/accessibility.mjs",
"require": "./dist/accessibility.cjs"
},
"./assets": {
"types": "./dist/assets/index.d.ts",
"import": "./dist/assets.mjs",
"require": "./dist/assets.cjs"
},
"./components": {
"types": "./dist/components/index.d.ts",
"import": "./dist/components.mjs",
"require": "./dist/components.cjs"
},
"./display": {
"types": "./dist/display/index.d.ts",
"import": "./dist/display.mjs",
"require": "./dist/display.cjs"
},
"./feedback": {
"types": "./dist/feedback/index.d.ts",
"import": "./dist/feedback.mjs",
"require": "./dist/feedback.cjs"
},
"./input": {
"types": "./dist/input/index.d.ts",
"import": "./dist/input.mjs",
"require": "./dist/input.cjs"
},
"./json-visualizer": {
"types": "./dist/json-visualizer/index.d.ts",
"import": "./dist/json-visualizer.mjs",
"require": "./dist/json-visualizer.cjs"
},
"./layout": {
"types": "./dist/layout/index.d.ts",
"import": "./dist/layout.mjs",
"require": "./dist/layout.cjs"
},
"./navigation": {
"types": "./dist/navigation/index.d.ts",
"import": "./dist/navigation.mjs",
"require": "./dist/navigation.cjs"
},
"./testing": {
"types": "./dist/testing/index.d.ts",
"import": "./dist/testing.mjs",
"require": "./dist/testing.cjs"
},
"./theme": {
"types": "./dist/theme/index.d.ts",
"import": "./dist/theme.mjs",
"require": "./dist/theme.cjs"
},
"./theme-constants": {
"types": "./dist/theme-constants/index.d.ts",
"import": "./dist/theme-constants.mjs",
"require": "./dist/theme-constants.cjs"
},
"./utilities": {
"types": "./dist/utilities/index.d.ts",
"import": "./dist/utilities.mjs",
"require": "./dist/utilities.cjs"
}
},
"typesVersions": {
"*": {
"accessibility": [
"dist/accessibility/index.d.ts"
],
"assets": [
"dist/assets/index.d.ts"
],
"components": [
"dist/components/index.d.ts"
],
"display": [
"dist/display/index.d.ts"
],
"feedback": [
"dist/feedback/index.d.ts"
],
"input": [
"dist/input/index.d.ts"
],
"json-visualizer": [
"dist/json-visualizer/index.d.ts"
],
"layout": [
"dist/layout/index.d.ts"
],
"navigation": [
"dist/navigation/index.d.ts"
],
"testing": [
"dist/testing/index.d.ts"
],
"theme": [
"dist/theme/index.d.ts"
],
"theme-constants": [
"dist/theme-constants/index.d.ts"
],
"utilities": [
"dist/utilities/index.d.ts"
]
}
}
}
-103
View File
@@ -1,103 +0,0 @@
{
"name": "twenty-new-ui",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/twenty-new-ui/src",
"projectType": "library",
"tags": ["scope:shared"],
"targets": {
"build": {
"dependsOn": ["^build"],
"outputs": [
"{projectRoot}/dist",
"{projectRoot}/accessibility/package.json",
"{projectRoot}/accessibility/dist",
"{projectRoot}/assets/package.json",
"{projectRoot}/assets/dist",
"{projectRoot}/components/package.json",
"{projectRoot}/components/dist",
"{projectRoot}/display/package.json",
"{projectRoot}/display/dist",
"{projectRoot}/feedback/package.json",
"{projectRoot}/feedback/dist",
"{projectRoot}/input/package.json",
"{projectRoot}/input/dist",
"{projectRoot}/json-visualizer/package.json",
"{projectRoot}/json-visualizer/dist",
"{projectRoot}/layout/package.json",
"{projectRoot}/layout/dist",
"{projectRoot}/navigation/package.json",
"{projectRoot}/navigation/dist",
"{projectRoot}/testing/package.json",
"{projectRoot}/testing/dist",
"{projectRoot}/theme/package.json",
"{projectRoot}/theme/dist",
"{projectRoot}/theme-constants/package.json",
"{projectRoot}/theme-constants/dist",
"{projectRoot}/utilities/package.json",
"{projectRoot}/utilities/dist"
]
},
"generateBarrels": {
"executor": "nx:run-commands",
"cache": true,
"inputs": ["production", "{projectRoot}/scripts/generateBarrels.ts"],
"outputs": [
"{projectRoot}/src/**/*/index.ts",
"{projectRoot}/package.json"
],
"options": { "command": "tsx {projectRoot}/scripts/generateBarrels.ts" }
},
"build:individual": {
"executor": "nx:run-commands",
"cache": true,
"dependsOn": ["build"],
"inputs": ["production", "^production"],
"outputs": ["{projectRoot}/dist/individual"],
"options": {
"cwd": "{projectRoot}",
"command": "npx vite build -c vite.config.individual.ts"
}
},
"size": {
"executor": "nx:run-commands",
"cache": true,
"dependsOn": ["build"],
"inputs": ["{projectRoot}/dist", "{projectRoot}/.size-limit.json"],
"options": {
"cwd": "{projectRoot}",
"command": "npx size-limit"
},
"configurations": {
"why": { "command": "npx size-limit --why" }
}
},
"clean": {
"executor": "nx:run-commands",
"options": { "command": "rimraf {projectRoot}/dist" }
},
"lint": {},
"fmt": { "options": { "files": "src" }, "configurations": { "fix": {} } },
"test": {},
"typecheck": {},
"storybook:build": { "configurations": { "test": {} } },
"storybook:serve:dev": { "options": { "port": 6008 } },
"storybook:serve:static": {
"options": {
"buildTarget": "twenty-new-ui:storybook:build",
"port": 6008
},
"configurations": { "test": {} }
},
"storybook:test": {},
"storybook:test:no-coverage": {},
"storybook:visual-diff": {
"executor": "nx:run-commands",
"dependsOn": ["storybook:build"],
"options": {
"cwd": "{projectRoot}",
"command": "bash scripts/visual-diff.sh"
}
},
"storybook:coverage": {}
}
}
@@ -1,505 +0,0 @@
import prettier from '@prettier/sync';
import * as fs from 'fs';
import { globSync } from 'glob';
import path from 'path';
import { type Options } from 'prettier';
import slash from 'slash';
import ts from 'typescript';
// TODO prastoin refactor this file in several one into its dedicated package and make it a TypeScript CLI
const INDEX_FILENAME = 'index';
const PACKAGE_JSON_FILENAME = 'package.json';
const NX_PROJECT_CONFIGURATION_FILENAME = 'project.json';
const PACKAGE_PATH = path.resolve('packages/twenty-ui');
const SRC_PATH = path.resolve(`${PACKAGE_PATH}/src`);
const PACKAGE_JSON_PATH = path.join(PACKAGE_PATH, PACKAGE_JSON_FILENAME);
const NX_PROJECT_CONFIGURATION_PATH = path.join(
PACKAGE_PATH,
NX_PROJECT_CONFIGURATION_FILENAME,
);
const prettierConfigFile = prettier.resolveConfigFile();
if (prettierConfigFile == null) {
throw new Error('Prettier config file not found');
}
const prettierConfiguration = prettier.resolveConfig(prettierConfigFile);
const prettierFormat = (str: string, parser: Options['parser']) =>
prettier.format(str, {
...prettierConfiguration,
parser,
});
type createTypeScriptFileArgs = {
path: string;
content: string;
filename: string;
};
const createTypeScriptFile = ({
content,
path: filePath,
filename,
}: createTypeScriptFileArgs) => {
const header = `
/*
* _____ _
*|_ _|_ _____ _ __ | |_ _ _
* | | \\ \\ /\\ / / _ \\ '_ \\| __| | | | Auto-generated file
* | | \\ V V / __/ | | | |_| |_| | Any edits to this will be overridden
* |_| \\_/\\_/ \\___|_| |_|\\__|\\__, |
* |___/
*/
`;
const formattedContent = prettierFormat(
`${header}\n${content}\n`,
'typescript',
);
fs.writeFileSync(
path.join(filePath, `${filename}.ts`),
formattedContent,
'utf-8',
);
};
const getLastPathFolder = (pathStr: string) => path.basename(pathStr);
const getSubDirectoryPaths = (directoryPath: string): string[] => {
const pattern = slash(path.join(directoryPath, '*/'));
return globSync(pattern, {
ignore: [...EXCLUDED_DIRECTORIES],
cwd: SRC_PATH,
nodir: false,
maxDepth: 1,
}).sort((a, b) => a.localeCompare(b));
};
const partitionFileExportsByType = (declarations: DeclarationOccurrence[]) => {
return declarations.reduce<{
typeAndInterfaceDeclarations: DeclarationOccurrence[];
otherDeclarations: DeclarationOccurrence[];
}>(
(acc, { kind, name }) => {
if (kind === 'type' || kind === 'interface') {
return {
...acc,
typeAndInterfaceDeclarations: [
...acc.typeAndInterfaceDeclarations,
{ kind, name },
],
};
}
return {
...acc,
otherDeclarations: [...acc.otherDeclarations, { kind, name }],
};
},
{
typeAndInterfaceDeclarations: [],
otherDeclarations: [],
},
);
};
const generateModuleIndexFiles = (exportByBarrel: ExportByBarrel[]) => {
return exportByBarrel.map<createTypeScriptFileArgs>(
({ barrel: { moduleDirectory }, allFileExports }) => {
const content = allFileExports
.sort((a, b) => a.file.localeCompare(b.file))
.map(({ exports, file }) => {
const { otherDeclarations, typeAndInterfaceDeclarations } =
partitionFileExportsByType(exports);
const fileWithoutExtension = path.parse(file).name;
const pathToImport = slash(
path.relative(
moduleDirectory,
path.join(path.dirname(file), fileWithoutExtension),
),
);
const mapDeclarationNameAndJoin = (
declarations: DeclarationOccurrence[],
) => declarations.map(({ name }) => name).join(', ');
const typeExport =
typeAndInterfaceDeclarations.length > 0
? `export type { ${mapDeclarationNameAndJoin(typeAndInterfaceDeclarations)} } from "./${pathToImport}"`
: '';
const othersExport =
otherDeclarations.length > 0
? `export { ${mapDeclarationNameAndJoin(otherDeclarations)} } from "./${pathToImport}"`
: '';
return [typeExport, othersExport]
.filter((el) => el !== '')
.join('\n');
})
.join('\n');
return {
content,
path: moduleDirectory,
filename: INDEX_FILENAME,
};
},
);
};
type JsonUpdate = Record<string, any>;
type WriteInJsonFileArgs = {
content: JsonUpdate;
file: string;
};
const updateJsonFile = ({ content, file }: WriteInJsonFileArgs) => {
const updatedJsonFile = JSON.stringify(content);
const formattedContent = prettier.format(updatedJsonFile, {
...prettierConfiguration,
filepath: file,
});
fs.writeFileSync(file, formattedContent, 'utf-8');
};
const writeInPackageJson = (update: JsonUpdate) => {
const rawJsonFile = fs.readFileSync(PACKAGE_JSON_PATH, 'utf-8');
const initialJsonFile = JSON.parse(rawJsonFile);
updateJsonFile({
file: PACKAGE_JSON_PATH,
content: {
...initialJsonFile,
...update,
},
});
};
const updateNxProjectConfigurationBuildOutputs = (outputs: JsonUpdate) => {
const rawJsonFile = fs.readFileSync(NX_PROJECT_CONFIGURATION_PATH, 'utf-8');
const initialJsonFile = JSON.parse(rawJsonFile);
updateJsonFile({
file: NX_PROJECT_CONFIGURATION_PATH,
content: {
...initialJsonFile,
targets: {
...initialJsonFile.targets,
build: {
...initialJsonFile.targets.build,
outputs,
},
},
},
});
};
type ExportOccurrence = {
types: string;
import: string;
require: string;
};
type ExportsConfig = Record<string, ExportOccurrence | string>;
const generateModulePackageExports = (moduleDirectories: string[]) => {
return moduleDirectories.reduce<ExportsConfig>(
(acc, moduleDirectory) => {
const moduleName = getLastPathFolder(moduleDirectory);
if (moduleName === undefined) {
throw new Error(
`Should never occur, moduleName is undefined ${moduleDirectory}`,
);
}
return {
...acc,
[`./${moduleName}`]: {
types: `./dist/${moduleName}/index.d.ts`,
import: `./dist/${moduleName}.mjs`,
require: `./dist/${moduleName}.cjs`,
},
};
},
{
'./style.css': './dist/style.css',
'./theme-light.css': './dist/theme-light.css',
'./theme-dark.css': './dist/theme-dark.css',
},
);
};
const computePackageJsonFilesAndExportsConfig = (
moduleDirectories: string[],
) => {
const entrypoints = moduleDirectories.map(getLastPathFolder);
const exports = {
'.': {
types: './dist/index.d.ts',
import: './dist/index.mjs',
require: './dist/index.cjs',
},
...generateModulePackageExports(moduleDirectories),
} satisfies ExportsConfig;
const typesVersionsEntries = entrypoints.reduce<Record<string, string[]>>(
(acc, moduleName) => ({
...acc,
[`${moduleName}`]: [`dist/${moduleName}/index.d.ts`],
}),
{},
);
return {
exports,
typesVersions: { '*': typesVersionsEntries },
files: ['dist', ...entrypoints],
};
};
const computeProjectNxBuildOutputsPath = (moduleDirectories: string[]) => {
const dynamicOutputsPath = moduleDirectories
.map(getLastPathFolder)
.flatMap((barrelName) =>
['package.json', 'dist'].map(
(subPath) => `{projectRoot}/${barrelName}/${subPath}`,
),
);
return ['{projectRoot}/dist', ...dynamicOutputsPath];
};
const EXCLUDED_EXTENSIONS = [
'**/*.test.ts',
'**/*.test.tsx',
'**/*.spec.ts',
'**/*.spec.tsx',
'**/*.stories.ts',
'**/*.stories.tsx',
] as const;
const EXCLUDED_DIRECTORIES = [
'**/__tests__/**',
'**/__mocks__/**',
'**/__stories__/**',
'**/internal/**',
] as const;
function getTypeScriptFiles(
directoryPath: string,
includeIndex: boolean = false,
): string[] {
const pattern = slash(path.join(directoryPath, '**', '*.{ts,tsx}'));
const files = globSync(pattern, {
cwd: SRC_PATH,
nodir: true,
ignore: [...EXCLUDED_EXTENSIONS, ...EXCLUDED_DIRECTORIES],
});
return files.filter(
(file) =>
!file.endsWith('.d.ts') &&
(includeIndex ? true : !file.endsWith('index.ts')),
);
}
const getKind = (
node: ts.VariableStatement,
): Extract<ExportKind, 'const' | 'let' | 'var'> => {
const isConst = (node.declarationList.flags & ts.NodeFlags.Const) !== 0;
if (isConst) {
return 'const';
}
const isLet = (node.declarationList.flags & ts.NodeFlags.Let) !== 0;
if (isLet) {
return 'let';
}
return 'var';
};
function extractExportsFromSourceFile(sourceFile: ts.SourceFile) {
const exports: DeclarationOccurrence[] = [];
function visit(node: ts.Node) {
if (!ts.canHaveModifiers(node)) {
return ts.forEachChild(node, visit);
}
const modifiers = ts.getModifiers(node);
const isExport = modifiers?.some(
(mod) => mod.kind === ts.SyntaxKind.ExportKeyword,
);
if (!isExport && !ts.isExportDeclaration(node)) {
return ts.forEachChild(node, visit);
}
switch (true) {
case ts.isTypeAliasDeclaration(node):
exports.push({
kind: 'type',
name: node.name.text,
});
break;
case ts.isInterfaceDeclaration(node):
exports.push({
kind: 'interface',
name: node.name.text,
});
break;
case ts.isEnumDeclaration(node):
exports.push({
kind: 'enum',
name: node.name.text,
});
break;
case ts.isFunctionDeclaration(node) && node.name !== undefined:
exports.push({
kind: 'function',
name: node.name.text,
});
break;
case ts.isVariableStatement(node):
node.declarationList.declarations.forEach((decl) => {
const kind = getKind(node);
if (ts.isIdentifier(decl.name)) {
exports.push({
kind,
name: decl.name.text,
});
} else if (ts.isObjectBindingPattern(decl.name)) {
decl.name.elements.forEach((element) => {
if (
!ts.isBindingElement(element) ||
!ts.isIdentifier(element.name)
) {
return;
}
exports.push({
kind,
name: element.name.text,
});
});
}
});
break;
case ts.isClassDeclaration(node) && node.name !== undefined:
exports.push({
kind: 'class',
name: node.name.text,
});
break;
case ts.isExportDeclaration(node):
if (node.exportClause && ts.isNamedExports(node.exportClause)) {
node.exportClause.elements.forEach((element) => {
const exportName = element.name.text;
// Check both the declaration and the individual specifier for type-only exports
const isTypeExport =
node.isTypeOnly || ts.isTypeOnlyExportDeclaration(node);
if (isTypeExport) {
// should handle kind
exports.push({
kind: 'type',
name: exportName,
});
return;
}
exports.push({
kind: 'const',
name: exportName,
});
});
}
break;
}
return ts.forEachChild(node, visit);
}
visit(sourceFile);
return exports;
}
type ExportKind =
| 'type'
| 'interface'
| 'enum'
| 'function'
| 'const'
| 'let'
| 'var'
| 'class';
type DeclarationOccurrence = { kind: ExportKind; name: string };
type FileExports = Array<{
file: string;
exports: DeclarationOccurrence[];
}>;
function findAllExports(directoryPath: string): FileExports {
const results: FileExports = [];
const files = getTypeScriptFiles(directoryPath);
for (const file of files) {
const sourceFile = ts.createSourceFile(
file,
fs.readFileSync(file, 'utf8'),
ts.ScriptTarget.Latest,
true,
);
const exports = extractExportsFromSourceFile(sourceFile);
if (exports.length > 0) {
results.push({
file,
exports,
});
}
}
return results;
}
type ExportByBarrel = {
barrel: {
moduleName: string;
moduleDirectory: string;
};
allFileExports: FileExports;
};
const retrieveExportsByBarrel = (barrelDirectories: string[]) => {
return barrelDirectories.map<ExportByBarrel>((moduleDirectory) => {
const moduleExportsPerFile = findAllExports(moduleDirectory);
const moduleName = getLastPathFolder(moduleDirectory);
if (!moduleName) {
throw new Error(
`Should never occur moduleName not found ${moduleDirectory}`,
);
}
return {
barrel: {
moduleName,
moduleDirectory,
},
allFileExports: moduleExportsPerFile,
};
});
};
const main = () => {
const moduleDirectories = getSubDirectoryPaths(SRC_PATH);
const exportsByBarrel = retrieveExportsByBarrel(moduleDirectories);
const moduleIndexFiles = generateModuleIndexFiles(exportsByBarrel);
const packageJsonConfig =
computePackageJsonFilesAndExportsConfig(moduleDirectories);
const nxBuildOutputsPath =
computeProjectNxBuildOutputsPath(moduleDirectories);
updateNxProjectConfigurationBuildOutputs(nxBuildOutputsPath);
writeInPackageJson(packageJsonConfig);
moduleIndexFiles.forEach(createTypeScriptFile);
};
main();
@@ -1,49 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
if [[ -f "$SCRIPT_DIR/.env" ]]; then
set -a
source "$SCRIPT_DIR/.env"
set +a
fi
ARGOS_API_BASE_URL="${ARGOS_API_BASE_URL:-http://127.0.0.1:4002/v2/}"
ARGOS_TOKEN="${ARGOS_TOKEN:?ARGOS_TOKEN is required set it in packages/twenty-new-ui/.env}"
USERNAME=$(whoami)
GIT_BRANCH="${ARGOS_BRANCH:-$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")}"
COMMIT="${ARGOS_COMMIT:-$(git rev-parse HEAD 2>/dev/null || echo "unknown")}"
REFERENCE_COMMIT="${ARGOS_REFERENCE_COMMIT:-$(git merge-base HEAD main 2>/dev/null || echo "")}"
export ARGOS_API_BASE_URL
export ARGOS_TOKEN
export ARGOS_BUILD_NAME="${USERNAME}/twenty-new-ui"
export ARGOS_BRANCH="${USERNAME}/${GIT_BRANCH}"
export ARGOS_COMMIT="$COMMIT"
export ARGOS_REFERENCE_COMMIT="${REFERENCE_COMMIT}"
echo "Argos visual diff"
echo " API: $ARGOS_API_BASE_URL"
echo " Build name: $ARGOS_BUILD_NAME"
echo " Branch: $ARGOS_BRANCH"
echo " Commit: ${ARGOS_COMMIT:0:12}"
echo " Ref commit: ${ARGOS_REFERENCE_COMMIT:0:12}"
echo ""
npx http-server storybook-static --port 6007 --silent &
HTTP_PID=$!
trap "kill $HTTP_PID 2>/dev/null || true" EXIT
SERVER_UP=false
for i in $(seq 1 30); do
if curl -sf http://localhost:6007 > /dev/null 2>&1; then SERVER_UP=true; break; fi
sleep 1
done
if [[ "$SERVER_UP" != "true" ]]; then
echo "Storybook static server did not start on http://localhost:6007 after 30s" >&2
exit 1
fi
export STORYBOOK_URL="http://localhost:6007"
npx vitest run
-5
View File
@@ -1,5 +0,0 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
@@ -1,2 +0,0 @@
// Auto-generated barrel placeholder — populated as components migrate into this entry point.
export {};
@@ -1,2 +0,0 @@
// Auto-generated barrel placeholder — populated as components migrate into this entry point.
export {};
@@ -1,2 +0,0 @@
// Auto-generated barrel placeholder — populated as components migrate into this entry point.
export {};
@@ -1,2 +0,0 @@
// Auto-generated barrel placeholder — populated as components migrate into this entry point.
export {};
@@ -1,2 +0,0 @@
// Auto-generated barrel placeholder — populated as components migrate into this entry point.
export {};
-7
View File
@@ -1,7 +0,0 @@
declare global {
interface Window {
_env_?: Record<string, string>;
}
}
export {};
-4
View File
@@ -1,4 +0,0 @@
// Side-effect import: the reset must ship exactly once in the aggregated style.css.
import './styles/base/reset.scss';
export {};
@@ -1,15 +0,0 @@
// Entry point for the individual/self-contained build (vite.config.individual.ts).
// Re-exports all public modules so a single bundle contains every component with
// internal deps bundled, while React stays external for the consumer's bundler.
export * from './accessibility';
export * from './components';
export * from './display';
export * from './feedback';
export * from './input';
export * from './json-visualizer';
export * from './layout';
export * from './navigation';
export * from './theme';
export * from './theme-constants';
export * from './utilities';
@@ -1,64 +0,0 @@
.root {
position: relative;
display: flex;
flex-shrink: 0;
align-items: center;
align-self: flex-start;
border-radius: 10px;
background-color: var(--t-background-transparent-medium);
cursor: pointer;
transition: background-color duration(normal) ease;
&[data-checked] {
background-color: var(--toggle-on-color, var(--t-color-blue));
}
&[data-disabled] {
opacity: 0.5;
pointer-events: none;
}
}
.centered {
align-self: center;
}
.small {
width: 24px;
height: 16px;
}
.medium {
width: 32px;
height: 20px;
}
.thumb {
position: absolute;
top: 50%;
left: 0;
display: block;
border-radius: 50%;
background-color: var(--t-background-primary);
transition: transform duration(normal) ease;
}
.small .thumb {
width: 12px;
height: 12px;
transform: translate(2px, -50%);
}
.medium .thumb {
width: 16px;
height: 16px;
transform: translate(2px, -50%);
}
.small[data-checked] .thumb {
transform: translate(10px, -50%);
}
.medium[data-checked] .thumb {
transform: translate(14px, -50%);
}
@@ -1,8 +0,0 @@
declare const classNames: {
readonly root: 'root';
readonly centered: 'centered';
readonly small: 'small';
readonly medium: 'medium';
readonly thumb: 'thumb';
};
export default classNames;
@@ -1,50 +0,0 @@
import { type Meta, type StoryObj } from '@storybook/react-vite';
import { useState } from 'react';
import { ThemeProvider } from '@new-ui/theme-constants';
import { Toggle } from './Toggle';
const meta: Meta<typeof Toggle> = {
title: 'Input/Toggle',
component: Toggle,
args: { toggleSize: 'medium', 'aria-label': 'Example toggle' },
};
export default meta;
type Story = StoryObj<typeof Toggle>;
export const On: Story = { args: { value: true } };
export const Off: Story = { args: { value: false } };
export const Small: Story = { args: { value: true, toggleSize: 'small' } };
export const CustomColor: Story = {
args: { value: true, color: 'color(display-p3 0.2 0.7 0.4)' },
};
export const Disabled: Story = { args: { value: true, disabled: true } };
const ControlledToggle = () => {
const [value, setValue] = useState(false);
return (
<Toggle value={value} onChange={setValue} aria-label="Example toggle" />
);
};
export const Interactive: Story = {
render: () => <ControlledToggle />,
};
export const Dark: Story = {
args: { value: true },
decorators: [
(Story) => (
<ThemeProvider colorScheme="dark">
<Story />
</ThemeProvider>
),
],
};
@@ -1,54 +0,0 @@
import { Switch } from '@base-ui/react/switch';
import { clsx } from 'clsx';
import styles from './Toggle.module.scss';
export type ToggleSize = 'small' | 'medium';
export type ToggleProps = {
id?: string;
value?: boolean;
onChange?: (value: boolean, e?: React.MouseEvent<HTMLDivElement>) => void;
color?: string;
toggleSize?: ToggleSize;
className?: string;
centered?: boolean;
disabled?: boolean;
'aria-label'?: string;
'aria-labelledby'?: string;
};
export const Toggle = ({
id,
value = false,
onChange,
color,
toggleSize = 'medium',
className,
centered,
disabled,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy,
}: ToggleProps) => (
<Switch.Root
id={id}
checked={value}
disabled={disabled}
onCheckedChange={(checked) => onChange?.(checked)}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledBy}
className={clsx(
styles.root,
styles[toggleSize],
centered && styles.centered,
className,
)}
style={
color
? ({ '--toggle-on-color': color } as React.CSSProperties)
: undefined
}
>
<Switch.Thumb className={styles.thumb} />
</Switch.Root>
);
@@ -1,2 +0,0 @@
export { Toggle } from './components/Toggle';
export type { ToggleProps, ToggleSize } from './components/Toggle';
@@ -1,2 +0,0 @@
// Auto-generated barrel placeholder — populated as components migrate into this entry point.
export {};
@@ -1,2 +0,0 @@
// Auto-generated barrel placeholder — populated as components migrate into this entry point.
export {};
@@ -1,2 +0,0 @@
// Auto-generated barrel placeholder — populated as components migrate into this entry point.
export {};
@@ -1,18 +0,0 @@
@use 'sass:map';
// Mirrors twenty-ui's MOBILE_VIEWPORT (768px).
$breakpoints: (
'mobile': 768px,
);
@mixin respond-to($name) {
$value: map.get($breakpoints, $name);
@if $value == null {
@error 'Unknown breakpoint: #{$name}';
}
@media (max-width: $value) {
@content;
}
}
@@ -1,5 +0,0 @@
// duration(fast) => calc(var(--t-animation-duration-fast) * 1s)
// Theme animation durations are stored unitless; this scales them to seconds.
@function duration($name) {
@return calc(var(--t-animation-duration-#{$name}) * 1s);
}
@@ -1,6 +0,0 @@
@mixin focus-ring {
&:focus-visible {
outline: 2px solid var(--t-color-blue);
outline-offset: 1px;
}
}
@@ -1,15 +0,0 @@
*,
*::before,
*::after {
box-sizing: border-box;
}
button {
margin: 0;
padding: 0;
font: inherit;
color: inherit;
background: none;
border: none;
cursor: pointer;
}
@@ -1,2 +0,0 @@
// Auto-generated barrel placeholder — populated as components migrate into this entry point.
export {};
@@ -1,121 +0,0 @@
import { createContext, useLayoutEffect, useState } from 'react';
import { themeCssVariables } from './themeCssVariables';
type StringLeaves<T> = {
[K in keyof T]: T[K] extends string ? string : StringLeaves<T[K]>;
};
type DeepMerge<T, U> = {
[K in keyof T]: K extends keyof U
? U[K] extends Record<string, unknown>
? T[K] extends Record<string, unknown>
? DeepMerge<T[K], U[K]>
: U[K]
: U[K]
: T[K];
};
// CSS variables that resolve to pure numbers at runtime
type NumericOverrides = {
icon: {
size: { sm: number; md: number; lg: number; xl: number };
stroke: { sm: number; md: number; lg: number };
};
animation: {
duration: { instant: number; fast: number; normal: number; slow: number };
};
text: {
lineHeight: { lg: number; md: number };
iconSizeMedium: number;
iconSizeSmall: number;
iconStrikeLight: number;
iconStrikeMedium: number;
iconStrikeBold: number;
};
spacingMultiplicator: number;
lastLayerZIndex: number;
};
export type ThemeType = DeepMerge<
StringLeaves<typeof themeCssVariables>,
NumericOverrides
>;
export type ThemeContextType = {
theme: ThemeType;
colorScheme: 'light' | 'dark';
};
const computeThemeFromCss = (): ThemeType => {
if (
typeof document === 'undefined' ||
typeof getComputedStyle !== 'function'
) {
return themeCssVariables as unknown as ThemeType;
}
const computedStyle = getComputedStyle(document.documentElement);
const resolve = (obj: Record<string, unknown>): Record<string, unknown> => {
const result: Record<string, unknown> = {};
for (const key of Object.keys(obj)) {
const value = obj[key];
if (typeof value === 'string' && value.startsWith('var(')) {
const varName = value.slice(4, -1);
const raw = computedStyle.getPropertyValue(varName).trim();
const num = Number(raw);
result[key] = raw !== '' && !isNaN(num) ? num : raw;
} else if (typeof value === 'object' && value !== null) {
result[key] = resolve(value as Record<string, unknown>);
} else {
result[key] = value;
}
}
return result;
};
return resolve(
themeCssVariables as unknown as Record<string, unknown>,
) as unknown as ThemeType;
};
const applyColorSchemeClass = (colorScheme: 'light' | 'dark') => {
if (typeof document === 'undefined') return;
const root = document.documentElement;
if (!root?.classList) return;
root.classList.toggle('dark', colorScheme === 'dark');
root.classList.toggle('light', colorScheme === 'light');
};
export const ThemeContext = createContext<ThemeContextType>({
theme: themeCssVariables as unknown as ThemeType,
colorScheme: 'light',
});
export const ThemeProvider = ({
children,
colorScheme,
}: {
children: React.ReactNode;
colorScheme: 'light' | 'dark';
}) => {
const [theme, setTheme] = useState<ThemeType>(() => {
applyColorSchemeClass(colorScheme);
return computeThemeFromCss();
});
useLayoutEffect(() => {
applyColorSchemeClass(colorScheme);
setTheme(computeThemeFromCss());
}, [colorScheme]);
return (
<ThemeContext.Provider value={{ theme, colorScheme }}>
{children}
</ThemeContext.Provider>
);
};
@@ -1,28 +0,0 @@
import {
MAIN_COLOR_NAMES,
type ThemeColor,
} from '@new-ui/theme/constants/MainColorNames';
import { getNextThemeColor } from '../getNextThemeColor';
describe('getNextThemeColor', () => {
it('returns the next theme color', () => {
const currentColor: ThemeColor = MAIN_COLOR_NAMES[0];
const nextColor: ThemeColor = MAIN_COLOR_NAMES[1];
expect(getNextThemeColor(MAIN_COLOR_NAMES, currentColor)).toBe(nextColor);
});
it('returns the first color when reaching the end', () => {
const currentColor: ThemeColor =
MAIN_COLOR_NAMES[MAIN_COLOR_NAMES.length - 1];
const nextColor: ThemeColor = MAIN_COLOR_NAMES[0];
expect(getNextThemeColor(MAIN_COLOR_NAMES, currentColor)).toBe(nextColor);
});
it('returns the first color when currentColorIsUndefined', () => {
const firstColor: ThemeColor = MAIN_COLOR_NAMES[0];
expect(getNextThemeColor(MAIN_COLOR_NAMES, undefined)).toBe(firstColor);
});
});
@@ -1,50 +0,0 @@
import { readFileSync } from 'fs';
import { resolve } from 'path';
import { themeCssVariables as newThemeCssVariables } from '../themeCssVariables';
import { themeCssVariables as oldThemeCssVariables } from '../../../../twenty-ui/src/theme-constants/themeCssVariables';
const NEW_DIR = resolve(__dirname, '..');
const OLD_DIR = resolve(__dirname, '../../../../twenty-ui/src/theme-constants');
// Parse a theme CSS file into ordered [name, value] pairs, normalizing
// whitespace so formatting differences (multi-line vs single-line values,
// header comment) don't affect the comparison. Stops each value at the ';'
// that terminates it, skipping ';' embedded in values (e.g. data URIs).
const parseTokens = (dir: string, file: string): [string, string][] => {
const text = readFileSync(resolve(dir, file), 'utf8');
const body = text.slice(text.indexOf('{') + 1, text.lastIndexOf('}'));
const re = /--t-([a-z0-9_-]+):\s*([\s\S]*?);(?=\s*(?:--t-|$))/g;
const tokens: [string, string][] = [];
let match: RegExpExecArray | null;
while ((match = re.exec(body)) !== null) {
const value = match[2]
.trim()
.replace(/\s+/g, ' ')
.replace(/\(\s+/g, '(')
.replace(/\s+\)/g, ')');
tokens.push([match[1], value]);
}
return tokens;
};
// twenty-new-ui must produce the exact same --t-* tokens and values (and order)
// as twenty-ui, so the swap is token-for-token with no visual change.
// Comparison ignores incidental formatting (header, whitespace) but not values.
describe('theme parity with twenty-ui', () => {
it('theme-light.css tokens match twenty-ui', () => {
expect(parseTokens(NEW_DIR, 'theme-light.css')).toEqual(
parseTokens(OLD_DIR, 'theme-light.css'),
);
});
it('theme-dark.css tokens match twenty-ui', () => {
expect(parseTokens(NEW_DIR, 'theme-dark.css')).toEqual(
parseTokens(OLD_DIR, 'theme-dark.css'),
);
});
it('themeCssVariables is deeply equal to twenty-ui', () => {
expect(newThemeCssVariables).toEqual(oldThemeCssVariables);
});
});
@@ -1,3 +0,0 @@
// CSS custom properties don't work in media queries, so MOBILE_VIEWPORT
// must be a static number rather than a var(--...) reference.
export const MOBILE_VIEWPORT = 768;
@@ -1,15 +0,0 @@
import { type ThemeColor } from '@new-ui/theme/constants/MainColorNames';
export const getNextThemeColor = (
colorNames: ThemeColor[],
currentColor?: ThemeColor,
): ThemeColor => {
if (currentColor === null || currentColor === undefined) {
return colorNames[0];
}
const currentColorIndex = colorNames.findIndex(
(color) => color === currentColor,
);
const nextColorIndex = (currentColorIndex + 1) % colorNames.length;
return colorNames[nextColorIndex];
};
@@ -1,14 +0,0 @@
/*
* _____ _
*|_ _|_ _____ _ __ | |_ _ _
* | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file
* | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden
* |_| \_/\_/ \___|_| |_|\__|\__, |
* |___/
*/
export { MOBILE_VIEWPORT } from './constants';
export { getNextThemeColor } from './getNextThemeColor';
export { themeCssVariables } from './themeCssVariables';
export type { ThemeType, ThemeContextType } from './ThemeProvider';
export { ThemeContext, ThemeProvider } from './ThemeProvider';
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -1,23 +0,0 @@
import * as RadixColors from '@radix-ui/colors';
import { COLOR_DARK } from '@new-ui/theme/constants/ColorsDark';
export const ACCENT_DARK = {
primary: COLOR_DARK.blue5,
secondary: COLOR_DARK.blue5,
tertiary: COLOR_DARK.blue3,
quaternary: COLOR_DARK.blue2,
accent3570: COLOR_DARK.blue8,
accent4060: COLOR_DARK.blue8,
accent1: RadixColors.indigoDarkP3.indigo1,
accent2: RadixColors.indigoDarkP3.indigo2,
accent3: RadixColors.indigoDarkP3.indigo3,
accent4: RadixColors.indigoDarkP3.indigo4,
accent5: RadixColors.indigoDarkP3.indigo5,
accent6: RadixColors.indigoDarkP3.indigo6,
accent7: RadixColors.indigoDarkP3.indigo7,
accent8: RadixColors.indigoDarkP3.indigo8,
accent9: RadixColors.indigoDarkP3.indigo9,
accent10: RadixColors.indigoDarkP3.indigo10,
accent11: RadixColors.indigoDarkP3.indigo11,
accent12: RadixColors.indigoDarkP3.indigo12,
};
@@ -1,23 +0,0 @@
import * as RadixColors from '@radix-ui/colors';
import { COLOR_LIGHT } from '@new-ui/theme/constants/ColorsLight';
export const ACCENT_LIGHT = {
primary: COLOR_LIGHT.blue5,
secondary: COLOR_LIGHT.blue5,
tertiary: COLOR_LIGHT.blue3,
quaternary: COLOR_LIGHT.blue2,
accent3570: COLOR_LIGHT.blue8,
accent4060: COLOR_LIGHT.blue8,
accent1: RadixColors.indigoP3.indigo1,
accent2: RadixColors.indigoP3.indigo2,
accent3: RadixColors.indigoP3.indigo3,
accent4: RadixColors.indigoP3.indigo4,
accent5: RadixColors.indigoP3.indigo5,
accent6: RadixColors.indigoP3.indigo6,
accent7: RadixColors.indigoP3.indigo7,
accent8: RadixColors.indigoP3.indigo8,
accent9: RadixColors.indigoP3.indigo9,
accent10: RadixColors.indigoP3.indigo10,
accent11: RadixColors.indigoP3.indigo11,
accent12: RadixColors.indigoP3.indigo12,
};
@@ -1,10 +0,0 @@
export const ANIMATION = {
duration: {
instant: 0.075,
fast: 0.15,
normal: 0.3,
slow: 1.5,
},
};
export type AnimationDuration = keyof typeof ANIMATION.duration;
@@ -1,35 +0,0 @@
import * as RadixColors from '@radix-ui/colors';
import { COLOR_DARK } from '@new-ui/theme/constants/ColorsDark';
import { GRAY_SCALE_DARK } from './GrayScaleDark';
import { TRANSPARENT_COLORS_DARK } from './TransparentColorsDark';
export const BACKGROUND_DARK = {
noisy: 'var(--t-background-noisy)',
primary: GRAY_SCALE_DARK.gray1,
secondary: GRAY_SCALE_DARK.gray2,
tertiary: GRAY_SCALE_DARK.gray4,
quaternary: GRAY_SCALE_DARK.gray5,
invertedPrimary: GRAY_SCALE_DARK.gray12,
invertedSecondary: GRAY_SCALE_DARK.gray11,
danger: COLOR_DARK.red3,
transparent: {
primary: RadixColors.blackP3A.blackA7,
secondary: RadixColors.blackP3A.blackA6,
strong: TRANSPARENT_COLORS_DARK.gray7,
medium: TRANSPARENT_COLORS_DARK.gray5,
light: TRANSPARENT_COLORS_DARK.gray2,
lighter: TRANSPARENT_COLORS_DARK.gray1,
danger: TRANSPARENT_COLORS_DARK.red3,
blue: TRANSPARENT_COLORS_DARK.blue4,
orange: TRANSPARENT_COLORS_DARK.orange4,
success: TRANSPARENT_COLORS_DARK.green4,
},
overlayPrimary: '#000000b8',
overlaySecondary: '#0000005c',
overlayTertiary: '#0000005c',
radialGradient: `radial-gradient(50% 62.62% at 50% 0%, ${GRAY_SCALE_DARK.gray9} 0%, ${GRAY_SCALE_DARK.gray10} 100%)`,
radialGradientHover: `radial-gradient(76.32% 95.59% at 50% 0%, ${GRAY_SCALE_DARK.gray10} 0%, ${GRAY_SCALE_DARK.gray11} 100%)`,
primaryInverted: GRAY_SCALE_DARK.gray12,
primaryInvertedHover: GRAY_SCALE_DARK.gray11,
};
@@ -1,35 +0,0 @@
import * as RadixColors from '@radix-ui/colors';
import { COLOR_LIGHT } from '@new-ui/theme/constants/ColorsLight';
import { GRAY_SCALE_LIGHT } from './GrayScaleLight';
import { TRANSPARENT_COLORS_LIGHT } from './TransparentColorsLight';
export const BACKGROUND_LIGHT = {
noisy: 'var(--t-background-noisy)',
primary: GRAY_SCALE_LIGHT.gray1,
secondary: GRAY_SCALE_LIGHT.gray2,
tertiary: GRAY_SCALE_LIGHT.gray4,
quaternary: GRAY_SCALE_LIGHT.gray5,
invertedPrimary: GRAY_SCALE_LIGHT.gray12,
invertedSecondary: GRAY_SCALE_LIGHT.gray11,
danger: COLOR_LIGHT.red3,
transparent: {
primary: RadixColors.whiteP3A.whiteA7,
secondary: RadixColors.whiteP3A.whiteA6,
strong: TRANSPARENT_COLORS_LIGHT.gray7,
medium: TRANSPARENT_COLORS_LIGHT.gray5,
light: TRANSPARENT_COLORS_LIGHT.gray2,
lighter: TRANSPARENT_COLORS_LIGHT.gray1,
danger: TRANSPARENT_COLORS_LIGHT.red3,
blue: TRANSPARENT_COLORS_LIGHT.blue3,
orange: TRANSPARENT_COLORS_LIGHT.orange3,
success: TRANSPARENT_COLORS_LIGHT.green3,
},
overlayPrimary: TRANSPARENT_COLORS_LIGHT.gray11,
overlaySecondary: TRANSPARENT_COLORS_LIGHT.gray9,
overlayTertiary: TRANSPARENT_COLORS_LIGHT.gray4,
radialGradient: `radial-gradient(50% 62.62% at 50% 0%, ${GRAY_SCALE_LIGHT.gray9} 0%, ${GRAY_SCALE_LIGHT.gray10} 100%)`,
radialGradientHover: `radial-gradient(76.32% 95.59% at 50% 0%, ${GRAY_SCALE_LIGHT.gray10} 0%, ${GRAY_SCALE_LIGHT.gray11} 100%)`,
primaryInverted: GRAY_SCALE_LIGHT.gray12,
primaryInvertedHover: GRAY_SCALE_LIGHT.gray11,
};
@@ -1,5 +0,0 @@
export const BLUR_DARK = {
light: 'blur(6px) saturate(200%) contrast(100%) brightness(130%)',
medium: 'blur(12px) saturate(200%) contrast(100%) brightness(130%)',
strong: 'blur(20px) saturate(200%) contrast(100%) brightness(130%)',
};
@@ -1,5 +0,0 @@
export const BLUR_LIGHT = {
light: 'blur(6px) saturate(200%) contrast(50%) brightness(130%)',
medium: 'blur(12px) saturate(200%) contrast(50%) brightness(130%)',
strong: 'blur(20px) saturate(200%) contrast(50%) brightness(130%)',
};
@@ -1,11 +0,0 @@
export const BORDER_COMMON = {
radius: {
xs: '2px',
sm: '4px',
md: '8px',
xl: '20px',
xxl: '40px',
pill: '999px',
rounded: '100%',
},
};
@@ -1,18 +0,0 @@
import { COLOR_DARK } from '@new-ui/theme/constants/ColorsDark';
import { BORDER_COMMON } from './BorderCommon';
import { GRAY_SCALE_DARK } from './GrayScaleDark';
import { TRANSPARENT_COLORS_DARK } from './TransparentColorsDark';
export const BORDER_DARK = {
color: {
strong: GRAY_SCALE_DARK.gray6,
medium: GRAY_SCALE_DARK.gray5,
light: GRAY_SCALE_DARK.gray4,
secondaryInverted: GRAY_SCALE_DARK.gray11,
inverted: GRAY_SCALE_DARK.gray12,
danger: COLOR_DARK.red5,
blue: COLOR_DARK.blue7,
transparentStrong: TRANSPARENT_COLORS_DARK.gray4,
},
...BORDER_COMMON,
};
@@ -1,18 +0,0 @@
import { COLOR_LIGHT } from '@new-ui/theme/constants/ColorsLight';
import { BORDER_COMMON } from './BorderCommon';
import { GRAY_SCALE_LIGHT } from './GrayScaleLight';
import { TRANSPARENT_COLORS_LIGHT } from './TransparentColorsLight';
export const BORDER_LIGHT = {
color: {
strong: GRAY_SCALE_LIGHT.gray6,
medium: GRAY_SCALE_LIGHT.gray5,
light: GRAY_SCALE_LIGHT.gray4,
secondaryInverted: GRAY_SCALE_LIGHT.gray11,
inverted: GRAY_SCALE_LIGHT.gray12,
danger: COLOR_LIGHT.red5,
blue: COLOR_LIGHT.blue7,
transparentStrong: TRANSPARENT_COLORS_LIGHT.gray4,
},
...BORDER_COMMON,
};
@@ -1,19 +0,0 @@
import { RGBA } from '@new-ui/theme/constants/Rgba';
/* oxlint-disable twenty/no-hardcoded-colors */
export const BOX_SHADOW_DARK = {
color: RGBA('#000000', 0.6),
light: `0px 2px 4px 0px ${RGBA(
'#000000',
0.04,
)}, 0px 0px 4px 0px ${RGBA('#000000', 0.08)}`,
strong: `2px 4px 16px 0px ${RGBA(
'#000000',
0.16,
)}, 0px 2px 4px 0px ${RGBA('#000000', 0.08)}`,
underline: `0px 1px 0px 0px ${RGBA('#000000', 0.32)}`,
superHeavy: `2px 4px 16px 0px ${RGBA(
'#000000',
0.12,
)}, 0px 2px 4px 0px ${RGBA('#000000', 0.04)}`,
};
@@ -1,9 +0,0 @@
import { GRAY_SCALE_LIGHT_ALPHA } from '@new-ui/theme/constants/GrayScaleLightAlpha';
export const BOX_SHADOW_LIGHT = {
color: GRAY_SCALE_LIGHT_ALPHA.gray2,
light: `0px 2px 4px 0px ${GRAY_SCALE_LIGHT_ALPHA.gray2}, 0px 0px 4px 0px ${GRAY_SCALE_LIGHT_ALPHA.gray5}`,
strong: `2px 4px 16px 0px ${GRAY_SCALE_LIGHT_ALPHA.gray7}, 0px 2px 4px 0px ${GRAY_SCALE_LIGHT_ALPHA.gray5}`,
underline: `0px 1px 0px 0px ${GRAY_SCALE_LIGHT_ALPHA.gray9}`,
superHeavy: `0px 0px 8px 0px ${GRAY_SCALE_LIGHT_ALPHA.gray7}, 0px 8px 64px -16px ${GRAY_SCALE_LIGHT_ALPHA.gray10}, 0px 24px 56px -16px ${GRAY_SCALE_LIGHT_ALPHA.gray5}`,
};
@@ -1,12 +0,0 @@
import { COLOR_DARK } from '@new-ui/theme/constants/ColorsDark';
export const CODE_DARK = {
text: {
gray: COLOR_DARK.gray10,
sky: COLOR_DARK.sky10,
pink: COLOR_DARK.pink10,
orange: COLOR_DARK.orange8,
green: COLOR_DARK.lime8,
},
font: { family: 'DM Mono' },
};
@@ -1,12 +0,0 @@
import { COLOR_LIGHT } from '@new-ui/theme/constants/ColorsLight';
export const CODE_LIGHT = {
text: {
gray: COLOR_LIGHT.gray10,
sky: COLOR_LIGHT.sky10,
pink: COLOR_LIGHT.pink10,
orange: COLOR_LIGHT.orange8,
green: COLOR_LIGHT.lime8,
},
font: { family: 'DM Mono' },
};
@@ -1,9 +0,0 @@
import { MAIN_COLORS_DARK } from './MainColorsDark';
import { SECONDARY_COLORS_DARK } from './SecondaryColorsDark';
import { TRANSPARENT_COLORS_DARK } from './TransparentColorsDark';
export const COLOR_DARK = {
...MAIN_COLORS_DARK,
...SECONDARY_COLORS_DARK,
transparent: TRANSPARENT_COLORS_DARK,
};
@@ -1,9 +0,0 @@
import { MAIN_COLORS_LIGHT } from './MainColorsLight';
import { SECONDARY_COLORS_LIGHT } from './SecondaryColorsLight';
import { TRANSPARENT_COLORS_LIGHT } from './TransparentColorsLight';
export const COLOR_LIGHT = {
...MAIN_COLORS_LIGHT,
...SECONDARY_COLORS_LIGHT,
transparent: TRANSPARENT_COLORS_LIGHT,
};
@@ -1,3 +0,0 @@
import { type ThemeColor } from './MainColorNames';
export const DEFAULT_THEME_COLOR_FALLBACK: ThemeColor = 'gray';
@@ -1,17 +0,0 @@
export const FONT_COMMON = {
size: {
xxs: '0.625rem',
xs: '0.85rem',
sm: '0.92rem',
md: '1rem',
lg: '1.23rem',
xl: '1.54rem',
xxl: '1.85rem',
},
weight: {
regular: 400,
medium: 500,
semiBold: 600,
},
family: 'Inter, sans-serif',
};
@@ -1,16 +0,0 @@
import { COLOR_DARK } from '@new-ui/theme/constants/ColorsDark';
import { FONT_COMMON } from './FontCommon';
import { GRAY_SCALE_DARK } from './GrayScaleDark';
export const FONT_DARK = {
color: {
primary: GRAY_SCALE_DARK.gray12,
secondary: GRAY_SCALE_DARK.gray11,
tertiary: GRAY_SCALE_DARK.gray9,
light: GRAY_SCALE_DARK.gray8,
extraLight: GRAY_SCALE_DARK.gray7,
inverted: GRAY_SCALE_DARK.gray1,
danger: COLOR_DARK.red,
},
...FONT_COMMON,
};
@@ -1,16 +0,0 @@
import { COLOR_LIGHT } from '@new-ui/theme/constants/ColorsLight';
import { FONT_COMMON } from './FontCommon';
import { GRAY_SCALE_LIGHT } from './GrayScaleLight';
export const FONT_LIGHT = {
color: {
primary: GRAY_SCALE_LIGHT.gray12,
secondary: GRAY_SCALE_LIGHT.gray11,
tertiary: GRAY_SCALE_LIGHT.gray9,
light: GRAY_SCALE_LIGHT.gray8,
extraLight: GRAY_SCALE_LIGHT.gray7,
inverted: GRAY_SCALE_LIGHT.gray1,
danger: COLOR_LIGHT.red,
},
...FONT_COMMON,
};
@@ -1,14 +0,0 @@
export const GRAY_SCALE_DARK = {
gray1: 'color(display-p3 0.09 0.09 0.09)',
gray2: 'color(display-p3 0.106 0.106 0.106)',
gray3: 'color(display-p3 0.098 0.098 0.098)',
gray4: 'color(display-p3 0.114 0.114 0.114)',
gray5: 'color(display-p3 0.133 0.133 0.133)',
gray6: 'color(display-p3 0.282 0.282 0.282)',
gray7: 'color(display-p3 0.298 0.298 0.298)',
gray8: 'color(display-p3 0.4 0.4 0.4)',
gray9: 'color(display-p3 0.506 0.506 0.506)',
gray10: 'color(display-p3 0.482 0.482 0.482)',
gray11: 'color(display-p3 0.702 0.702 0.702)',
gray12: 'color(display-p3 0.922 0.922 0.922)',
};
@@ -1,14 +0,0 @@
export const GRAY_SCALE_DARK_ALPHA = {
gray1: 'color(display-p3 1 1 1 / 0.031)',
gray2: 'color(display-p3 1 1 1 / 0.059)',
gray3: 'color(display-p3 1 1 1 / 0.047)',
gray4: 'color(display-p3 1 1 1 / 0.071)',
gray5: 'color(display-p3 1 1 1 / 0.102)',
gray6: 'color(display-p3 1 1 1 / 0.114)',
gray7: 'color(display-p3 1 1 1 / 0.141)',
gray8: 'color(display-p3 1 1 1 / 0.22)',
gray9: 'color(display-p3 1 1 1 / 0.427)',
gray10: 'color(display-p3 1 1 1 / 0.478)',
gray11: 'color(display-p3 1 1 1 / 0.565)',
gray12: 'color(display-p3 1 1 1 / 0.91)',
};
@@ -1,14 +0,0 @@
export const GRAY_SCALE_LIGHT = {
gray1: 'color(display-p3 1 1 1)',
gray2: 'color(display-p3 0.988 0.988 0.988)',
gray3: 'color(display-p3 0.976 0.976 0.976)',
gray4: 'color(display-p3 0.945 0.945 0.945)',
gray5: 'color(display-p3 0.922 0.922 0.922)',
gray6: 'color(display-p3 0.839 0.839 0.839)',
gray7: 'color(display-p3 0.8 0.8 0.8)',
gray8: 'color(display-p3 0.702 0.702 0.702)',
gray9: 'color(display-p3 0.6 0.6 0.6)',
gray10: 'color(display-p3 0.514 0.514 0.514)',
gray11: 'color(display-p3 0.4 0.4 0.4)',
gray12: 'color(display-p3 0.2 0.2 0.2)',
};
@@ -1,14 +0,0 @@
export const GRAY_SCALE_LIGHT_ALPHA = {
gray1: 'color(display-p3 0 0 0 / 0.02)',
gray2: 'color(display-p3 0 0 0 / 0.039)',
gray3: 'color(display-p3 0 0 0 / 0.047)',
gray4: 'color(display-p3 0 0 0 / 0.071)',
gray5: 'color(display-p3 0 0 0 / 0.078)',
gray6: 'color(display-p3 0 0 0 / 0.114)',
gray7: 'color(display-p3 0 0 0 / 0.161)',
gray8: 'color(display-p3 0 0 0 / 0.22)',
gray9: 'color(display-p3 0 0 0 / 0.361)',
gray10: 'color(display-p3 0 0 0 / 0.478)',
gray11: 'color(display-p3 0 0 0 / 0.722)',
gray12: 'color(display-p3 0 0 0 / 0.91)',
};
@@ -1,13 +0,0 @@
export const ICON = {
size: {
sm: 14,
md: 16,
lg: 20,
xl: 24,
},
stroke: {
sm: 1.6,
md: 2,
lg: 2.5,
},
};
@@ -1,13 +0,0 @@
import { COLOR_DARK } from '@new-ui/theme/constants/ColorsDark';
import { GRAY_SCALE_DARK } from '@new-ui/theme/constants/GrayScaleDark';
export const ILLUSTRATION_ICON_DARK = {
color: {
blue: COLOR_DARK.blue10,
gray: GRAY_SCALE_DARK.gray8,
},
fill: {
blue: COLOR_DARK.blue12,
gray: GRAY_SCALE_DARK.gray5,
},
};
@@ -1,13 +0,0 @@
import { COLOR_LIGHT } from '@new-ui/theme/constants/ColorsLight';
import { GRAY_SCALE_LIGHT } from '@new-ui/theme/constants/GrayScaleLight';
export const ILLUSTRATION_ICON_LIGHT = {
color: {
blue: COLOR_LIGHT.blue8,
gray: GRAY_SCALE_LIGHT.gray9,
},
fill: {
blue: COLOR_LIGHT.blue5,
gray: GRAY_SCALE_LIGHT.gray5,
},
};
@@ -1,5 +0,0 @@
import { MAIN_COLORS_LIGHT } from './MainColorsLight';
export const MAIN_COLOR_NAMES = Object.keys(MAIN_COLORS_LIGHT) as ThemeColor[];
export type ThemeColor = keyof typeof MAIN_COLORS_LIGHT;
@@ -1,41 +0,0 @@
import * as RadixColors from '@radix-ui/colors';
import { GRAY_SCALE_DARK } from '@new-ui/theme/constants/GrayScaleDark';
export const MAIN_COLORS_DARK = {
// Reds
red: RadixColors.redDarkP3.red9,
ruby: RadixColors.rubyDarkP3.ruby9,
crimson: RadixColors.crimsonDarkP3.crimson9,
tomato: RadixColors.tomatoDarkP3.tomato9,
// Oranges & Yellows
orange: RadixColors.orangeDarkP3.orange9,
amber: RadixColors.amberDarkP3.amber9,
yellow: RadixColors.yellowDarkP3.yellow9,
// Greens
lime: RadixColors.limeDarkP3.lime9,
grass: RadixColors.grassDarkP3.grass9,
green: RadixColors.greenDarkP3.green9,
jade: RadixColors.jadeDarkP3.jade9,
mint: RadixColors.mintDarkP3.mint9,
// Cyans & Blues
turquoise: RadixColors.tealDarkP3.teal9,
cyan: RadixColors.cyanDarkP3.cyan9,
sky: RadixColors.skyDarkP3.sky9,
blue: RadixColors.indigoDarkP3.indigo9,
// Purples & Pinks
iris: RadixColors.irisDarkP3.iris9,
violet: RadixColors.violetDarkP3.violet9,
purple: RadixColors.purpleDarkP3.purple9,
plum: RadixColors.plumDarkP3.plum9,
pink: RadixColors.pinkDarkP3.pink9,
// Earth tones & Neutrals
bronze: RadixColors.bronzeDarkP3.bronze9,
gold: RadixColors.goldDarkP3.gold9,
brown: RadixColors.brownDarkP3.brown9,
gray: GRAY_SCALE_DARK.gray7,
};
@@ -1,41 +0,0 @@
import * as RadixColors from '@radix-ui/colors';
import { GRAY_SCALE_LIGHT } from './GrayScaleLight';
export const MAIN_COLORS_LIGHT = {
// Reds
red: RadixColors.redP3.red9,
ruby: RadixColors.rubyP3.ruby9,
crimson: RadixColors.crimsonP3.crimson9,
tomato: RadixColors.tomatoP3.tomato9,
// Oranges & Yellows
orange: RadixColors.orangeP3.orange9,
amber: RadixColors.amberP3.amber9,
yellow: RadixColors.yellowP3.yellow9,
// Greens
lime: RadixColors.limeP3.lime9,
grass: RadixColors.grassP3.grass9,
green: RadixColors.greenP3.green9,
jade: RadixColors.jadeP3.jade9,
mint: RadixColors.mintP3.mint9,
// Cyans & Blues
turquoise: RadixColors.tealP3.teal9,
cyan: RadixColors.cyanP3.cyan9,
sky: RadixColors.skyP3.sky9,
blue: RadixColors.indigoP3.indigo9,
// Purples & Pinks
iris: RadixColors.irisP3.iris9,
violet: RadixColors.violetP3.violet9,
purple: RadixColors.purpleP3.purple9,
plum: RadixColors.plumP3.plum9,
pink: RadixColors.pinkP3.pink9,
// Earth tones & Neutrals
bronze: RadixColors.bronzeP3.bronze9,
gold: RadixColors.goldP3.gold9,
brown: RadixColors.brownP3.brown9,
gray: GRAY_SCALE_LIGHT.gray9,
};
@@ -1,23 +0,0 @@
export const MODAL: {
size: { [key: string]: { width?: string; height?: string } };
} = {
size: {
sm: {
width: '300px',
},
md: {
width: '400px',
},
lg: {
width: '53%',
},
xl: {
width: '1200px',
height: '800px',
},
fullscreen: {
width: '100dvw',
height: '100dvh',
},
},
};
@@ -1,8 +0,0 @@
/* oxlint-disable twenty/no-hardcoded-colors */
import hexRgb from 'hex-rgb';
export const RGBA = (hex: string, alpha: number) => {
return `rgba(${hexRgb(hex, { format: 'array' })
.slice(0, -1)
.join(',')},${alpha})`;
};
@@ -1,394 +0,0 @@
import * as RadixColors from '@radix-ui/colors';
import { GRAY_SCALE_DARK } from '@new-ui/theme/constants/GrayScaleDark';
export const SECONDARY_COLORS_DARK = {
yellow1: RadixColors.yellowDarkP3.yellow1,
yellow2: RadixColors.yellowDarkP3.yellow2,
yellow3: RadixColors.yellowDarkP3.yellow3,
yellow4: RadixColors.yellowDarkP3.yellow4,
yellow5: RadixColors.yellowDarkP3.yellow5,
yellow6: RadixColors.yellowDarkP3.yellow6,
yellow7: RadixColors.yellowDarkP3.yellow7,
yellow8: RadixColors.yellowDarkP3.yellow8,
yellow9: RadixColors.yellowDarkP3.yellow9,
yellow10: RadixColors.yellowDarkP3.yellow10,
yellow11: RadixColors.yellowDarkP3.yellow11,
yellow12: RadixColors.yellowDarkP3.yellow12,
green1: RadixColors.greenDarkP3.green1,
green2: RadixColors.greenDarkP3.green2,
green3: RadixColors.greenDarkP3.green3,
green4: RadixColors.greenDarkP3.green4,
green5: RadixColors.greenDarkP3.green5,
green6: RadixColors.greenDarkP3.green6,
green7: RadixColors.greenDarkP3.green7,
green8: RadixColors.greenDarkP3.green8,
green9: RadixColors.greenDarkP3.green9,
green10: RadixColors.greenDarkP3.green10,
green11: RadixColors.greenDarkP3.green11,
green12: RadixColors.greenDarkP3.green12,
turquoise1: RadixColors.tealDarkP3.teal1,
turquoise2: RadixColors.tealDarkP3.teal2,
turquoise3: RadixColors.tealDarkP3.teal3,
turquoise4: RadixColors.tealDarkP3.teal4,
turquoise5: RadixColors.tealDarkP3.teal5,
turquoise6: RadixColors.tealDarkP3.teal6,
turquoise7: RadixColors.tealDarkP3.teal7,
turquoise8: RadixColors.tealDarkP3.teal8,
turquoise9: RadixColors.tealDarkP3.teal9,
turquoise10: RadixColors.tealDarkP3.teal10,
turquoise11: RadixColors.tealDarkP3.teal11,
turquoise12: RadixColors.tealDarkP3.teal12,
sky1: RadixColors.skyDarkP3.sky1,
sky2: RadixColors.skyDarkP3.sky2,
sky3: RadixColors.skyDarkP3.sky3,
sky4: RadixColors.skyDarkP3.sky4,
sky5: RadixColors.skyDarkP3.sky5,
sky6: RadixColors.skyDarkP3.sky6,
sky7: RadixColors.skyDarkP3.sky7,
sky8: RadixColors.skyDarkP3.sky8,
sky9: RadixColors.skyP3.sky9,
sky10: RadixColors.skyDarkP3.sky10,
sky11: RadixColors.skyDarkP3.sky11,
sky12: RadixColors.skyDarkP3.sky12,
blue1: RadixColors.indigoDarkP3.indigo1,
blue2: RadixColors.indigoDarkP3.indigo2,
blue3: RadixColors.indigoDarkP3.indigo3,
blue4: RadixColors.indigoDarkP3.indigo4,
blue5: RadixColors.indigoDarkP3.indigo5,
blue6: RadixColors.indigoDarkP3.indigo6,
blue7: RadixColors.indigoDarkP3.indigo7,
blue8: RadixColors.indigoDarkP3.indigo8,
blue9: RadixColors.indigoDarkP3.indigo9,
blue10: RadixColors.indigoDarkP3.indigo10,
blue11: RadixColors.indigoDarkP3.indigo11,
blue12: RadixColors.indigoDarkP3.indigo12,
purple1: RadixColors.purpleDarkP3.purple1,
purple2: RadixColors.purpleDarkP3.purple2,
purple3: RadixColors.purpleDarkP3.purple3,
purple4: RadixColors.purpleDarkP3.purple4,
purple5: RadixColors.purpleDarkP3.purple5,
purple6: RadixColors.purpleDarkP3.purple6,
purple7: RadixColors.purpleDarkP3.purple7,
purple8: RadixColors.purpleDarkP3.purple8,
purple9: RadixColors.purpleDarkP3.purple9,
purple10: RadixColors.purpleDarkP3.purple10,
purple11: RadixColors.purpleDarkP3.purple11,
purple12: RadixColors.purpleDarkP3.purple12,
pink1: RadixColors.pinkDarkP3.pink1,
pink2: RadixColors.pinkDarkP3.pink2,
pink3: RadixColors.pinkDarkP3.pink3,
pink4: RadixColors.pinkDarkP3.pink4,
pink5: RadixColors.pinkDarkP3.pink5,
pink6: RadixColors.pinkDarkP3.pink6,
pink7: RadixColors.pinkDarkP3.pink7,
pink8: RadixColors.pinkDarkP3.pink8,
pink9: RadixColors.pinkDarkP3.pink9,
pink10: RadixColors.pinkDarkP3.pink10,
pink11: RadixColors.pinkDarkP3.pink11,
pink12: RadixColors.pinkDarkP3.pink12,
red1: RadixColors.redDarkP3.red1,
red2: RadixColors.redDarkP3.red2,
red3: RadixColors.redDarkP3.red3,
red4: RadixColors.redDarkP3.red4,
red5: RadixColors.redDarkP3.red5,
red6: RadixColors.redDarkP3.red6,
red7: RadixColors.redDarkP3.red7,
red8: RadixColors.redDarkP3.red8,
red9: RadixColors.redDarkP3.red9,
red10: RadixColors.redDarkP3.red10,
red11: RadixColors.redDarkP3.red11,
red12: RadixColors.redDarkP3.red12,
orange1: RadixColors.orangeDarkP3.orange1,
orange2: RadixColors.orangeDarkP3.orange2,
orange3: RadixColors.orangeDarkP3.orange3,
orange4: RadixColors.orangeDarkP3.orange4,
orange5: RadixColors.orangeDarkP3.orange5,
orange6: RadixColors.orangeDarkP3.orange6,
orange7: RadixColors.orangeDarkP3.orange7,
orange8: RadixColors.orangeDarkP3.orange8,
orange9: RadixColors.orangeDarkP3.orange9,
orange10: RadixColors.orangeDarkP3.orange10,
orange11: RadixColors.orangeDarkP3.orange11,
orange12: RadixColors.orangeDarkP3.orange12,
gray1: GRAY_SCALE_DARK.gray1,
gray2: GRAY_SCALE_DARK.gray2,
gray3: GRAY_SCALE_DARK.gray3,
gray4: GRAY_SCALE_DARK.gray4,
gray5: GRAY_SCALE_DARK.gray5,
gray6: GRAY_SCALE_DARK.gray6,
gray7: GRAY_SCALE_DARK.gray7,
gray8: GRAY_SCALE_DARK.gray8,
gray9: GRAY_SCALE_DARK.gray9,
gray10: GRAY_SCALE_DARK.gray10,
gray11: GRAY_SCALE_DARK.gray11,
gray12: GRAY_SCALE_DARK.gray12,
mauve1: RadixColors.mauveDarkP3.mauve1,
mauve2: RadixColors.mauveDarkP3.mauve2,
mauve3: RadixColors.mauveDarkP3.mauve3,
mauve4: RadixColors.mauveDarkP3.mauve4,
mauve5: RadixColors.mauveDarkP3.mauve5,
mauve6: RadixColors.mauveDarkP3.mauve6,
mauve7: RadixColors.mauveDarkP3.mauve7,
mauve8: RadixColors.mauveDarkP3.mauve8,
mauve9: RadixColors.mauveDarkP3.mauve9,
mauve10: RadixColors.mauveDarkP3.mauve10,
mauve11: RadixColors.mauveDarkP3.mauve11,
mauve12: RadixColors.mauveDarkP3.mauve12,
slate1: RadixColors.slateDarkP3.slate1,
slate2: RadixColors.slateDarkP3.slate2,
slate3: RadixColors.slateDarkP3.slate3,
slate4: RadixColors.slateDarkP3.slate4,
slate5: RadixColors.slateDarkP3.slate5,
slate6: RadixColors.slateDarkP3.slate6,
slate7: RadixColors.slateDarkP3.slate7,
slate8: RadixColors.slateDarkP3.slate8,
slate9: RadixColors.slateDarkP3.slate9,
slate10: RadixColors.slateDarkP3.slate10,
slate11: RadixColors.slateDarkP3.slate11,
slate12: RadixColors.slateDarkP3.slate12,
sage1: RadixColors.sageDarkP3.sage1,
sage2: RadixColors.sageDarkP3.sage2,
sage3: RadixColors.sageDarkP3.sage3,
sage4: RadixColors.sageDarkP3.sage4,
sage5: RadixColors.sageDarkP3.sage5,
sage6: RadixColors.sageDarkP3.sage6,
sage7: RadixColors.sageDarkP3.sage7,
sage8: RadixColors.sageDarkP3.sage8,
sage9: RadixColors.sageDarkP3.sage9,
sage10: RadixColors.sageDarkP3.sage10,
sage11: RadixColors.sageDarkP3.sage11,
sage12: RadixColors.sageDarkP3.sage12,
olive1: RadixColors.oliveDarkP3.olive1,
olive2: RadixColors.oliveDarkP3.olive2,
olive3: RadixColors.oliveDarkP3.olive3,
olive4: RadixColors.oliveDarkP3.olive4,
olive5: RadixColors.oliveDarkP3.olive5,
olive6: RadixColors.oliveDarkP3.olive6,
olive7: RadixColors.oliveDarkP3.olive7,
olive8: RadixColors.oliveDarkP3.olive8,
olive9: RadixColors.oliveDarkP3.olive9,
olive10: RadixColors.oliveDarkP3.olive10,
olive11: RadixColors.oliveDarkP3.olive11,
olive12: RadixColors.oliveDarkP3.olive12,
sand1: RadixColors.sandDarkP3.sand1,
sand2: RadixColors.sandDarkP3.sand2,
sand3: RadixColors.sandDarkP3.sand3,
sand4: RadixColors.sandDarkP3.sand4,
sand5: RadixColors.sandDarkP3.sand5,
sand6: RadixColors.sandDarkP3.sand6,
sand7: RadixColors.sandDarkP3.sand7,
sand8: RadixColors.sandDarkP3.sand8,
sand9: RadixColors.sandDarkP3.sand9,
sand10: RadixColors.sandDarkP3.sand10,
sand11: RadixColors.sandDarkP3.sand11,
sand12: RadixColors.sandDarkP3.sand12,
tomato1: RadixColors.tomatoDarkP3.tomato1,
tomato2: RadixColors.tomatoDarkP3.tomato2,
tomato3: RadixColors.tomatoDarkP3.tomato3,
tomato4: RadixColors.tomatoDarkP3.tomato4,
tomato5: RadixColors.tomatoDarkP3.tomato5,
tomato6: RadixColors.tomatoDarkP3.tomato6,
tomato7: RadixColors.tomatoDarkP3.tomato7,
tomato8: RadixColors.tomatoDarkP3.tomato8,
tomato9: RadixColors.tomatoDarkP3.tomato9,
tomato10: RadixColors.tomatoDarkP3.tomato10,
tomato11: RadixColors.tomatoDarkP3.tomato11,
tomato12: RadixColors.tomatoDarkP3.tomato12,
ruby1: RadixColors.rubyDarkP3.ruby1,
ruby2: RadixColors.rubyDarkP3.ruby2,
ruby3: RadixColors.rubyDarkP3.ruby3,
ruby4: RadixColors.rubyDarkP3.ruby4,
ruby5: RadixColors.rubyDarkP3.ruby5,
ruby6: RadixColors.rubyDarkP3.ruby6,
ruby7: RadixColors.rubyDarkP3.ruby7,
ruby8: RadixColors.rubyDarkP3.ruby8,
ruby9: RadixColors.rubyDarkP3.ruby9,
ruby10: RadixColors.rubyDarkP3.ruby10,
ruby11: RadixColors.rubyDarkP3.ruby11,
ruby12: RadixColors.rubyDarkP3.ruby12,
crimson1: RadixColors.crimsonDarkP3.crimson1,
crimson2: RadixColors.crimsonDarkP3.crimson2,
crimson3: RadixColors.crimsonDarkP3.crimson3,
crimson4: RadixColors.crimsonDarkP3.crimson4,
crimson5: RadixColors.crimsonDarkP3.crimson5,
crimson6: RadixColors.crimsonDarkP3.crimson6,
crimson7: RadixColors.crimsonDarkP3.crimson7,
crimson8: RadixColors.crimsonDarkP3.crimson8,
crimson9: RadixColors.crimsonDarkP3.crimson9,
crimson10: RadixColors.crimsonDarkP3.crimson10,
crimson11: RadixColors.crimsonDarkP3.crimson11,
crimson12: RadixColors.crimsonDarkP3.crimson12,
plum1: RadixColors.plumDarkP3.plum1,
plum2: RadixColors.plumDarkP3.plum2,
plum3: RadixColors.plumDarkP3.plum3,
plum4: RadixColors.plumDarkP3.plum4,
plum5: RadixColors.plumDarkP3.plum5,
plum6: RadixColors.plumDarkP3.plum6,
plum7: RadixColors.plumDarkP3.plum7,
plum8: RadixColors.plumDarkP3.plum8,
plum9: RadixColors.plumDarkP3.plum9,
plum10: RadixColors.plumDarkP3.plum10,
plum11: RadixColors.plumDarkP3.plum11,
plum12: RadixColors.plumDarkP3.plum12,
violet1: RadixColors.violetDarkP3.violet1,
violet2: RadixColors.violetDarkP3.violet2,
violet3: RadixColors.violetDarkP3.violet3,
violet4: RadixColors.violetDarkP3.violet4,
violet5: RadixColors.violetDarkP3.violet5,
violet6: RadixColors.violetDarkP3.violet6,
violet7: RadixColors.violetDarkP3.violet7,
violet8: RadixColors.violetDarkP3.violet8,
violet9: RadixColors.violetDarkP3.violet9,
violet10: RadixColors.violetDarkP3.violet10,
violet11: RadixColors.violetDarkP3.violet11,
violet12: RadixColors.violetDarkP3.violet12,
iris1: RadixColors.irisDarkP3.iris1,
iris2: RadixColors.irisDarkP3.iris2,
iris3: RadixColors.irisDarkP3.iris3,
iris4: RadixColors.irisDarkP3.iris4,
iris5: RadixColors.irisDarkP3.iris5,
iris6: RadixColors.irisDarkP3.iris6,
iris7: RadixColors.irisDarkP3.iris7,
iris8: RadixColors.irisDarkP3.iris8,
iris9: RadixColors.irisDarkP3.iris9,
iris10: RadixColors.irisDarkP3.iris10,
iris11: RadixColors.irisDarkP3.iris11,
iris12: RadixColors.irisDarkP3.iris12,
cyan1: RadixColors.cyanDarkP3.cyan1,
cyan2: RadixColors.cyanDarkP3.cyan2,
cyan3: RadixColors.cyanDarkP3.cyan3,
cyan4: RadixColors.cyanDarkP3.cyan4,
cyan5: RadixColors.cyanDarkP3.cyan5,
cyan6: RadixColors.cyanDarkP3.cyan6,
cyan7: RadixColors.cyanDarkP3.cyan7,
cyan8: RadixColors.cyanDarkP3.cyan8,
cyan9: RadixColors.cyanDarkP3.cyan9,
cyan10: RadixColors.cyanDarkP3.cyan10,
cyan11: RadixColors.cyanDarkP3.cyan11,
cyan12: RadixColors.cyanDarkP3.cyan12,
jade1: RadixColors.jadeDarkP3.jade1,
jade2: RadixColors.jadeDarkP3.jade2,
jade3: RadixColors.jadeDarkP3.jade3,
jade4: RadixColors.jadeDarkP3.jade4,
jade5: RadixColors.jadeDarkP3.jade5,
jade6: RadixColors.jadeDarkP3.jade6,
jade7: RadixColors.jadeDarkP3.jade7,
jade8: RadixColors.jadeDarkP3.jade8,
jade9: RadixColors.jadeDarkP3.jade9,
jade10: RadixColors.jadeDarkP3.jade10,
jade11: RadixColors.jadeDarkP3.jade11,
jade12: RadixColors.jadeDarkP3.jade12,
grass1: RadixColors.grassDarkP3.grass1,
grass2: RadixColors.grassDarkP3.grass2,
grass3: RadixColors.grassDarkP3.grass3,
grass4: RadixColors.grassDarkP3.grass4,
grass5: RadixColors.grassDarkP3.grass5,
grass6: RadixColors.grassDarkP3.grass6,
grass7: RadixColors.grassDarkP3.grass7,
grass8: RadixColors.grassDarkP3.grass8,
grass9: RadixColors.grassDarkP3.grass9,
grass10: RadixColors.grassDarkP3.grass10,
grass11: RadixColors.grassDarkP3.grass11,
grass12: RadixColors.grassDarkP3.grass12,
mint1: RadixColors.mintDarkP3.mint1,
mint2: RadixColors.mintDarkP3.mint2,
mint3: RadixColors.mintDarkP3.mint3,
mint4: RadixColors.mintDarkP3.mint4,
mint5: RadixColors.mintDarkP3.mint5,
mint6: RadixColors.mintDarkP3.mint6,
mint7: RadixColors.mintDarkP3.mint7,
mint8: RadixColors.mintDarkP3.mint8,
mint9: RadixColors.mintDarkP3.mint9,
mint10: RadixColors.mintDarkP3.mint10,
mint11: RadixColors.mintDarkP3.mint11,
mint12: RadixColors.mintDarkP3.mint12,
lime1: RadixColors.limeDarkP3.lime1,
lime2: RadixColors.limeDarkP3.lime2,
lime3: RadixColors.limeDarkP3.lime3,
lime4: RadixColors.limeDarkP3.lime4,
lime5: RadixColors.limeDarkP3.lime5,
lime6: RadixColors.limeDarkP3.lime6,
lime7: RadixColors.limeDarkP3.lime7,
lime8: RadixColors.limeDarkP3.lime8,
lime9: RadixColors.limeDarkP3.lime9,
lime10: RadixColors.limeDarkP3.lime10,
lime11: RadixColors.limeDarkP3.lime11,
lime12: RadixColors.limeDarkP3.lime12,
bronze1: RadixColors.bronzeDarkP3.bronze1,
bronze2: RadixColors.bronzeDarkP3.bronze2,
bronze3: RadixColors.bronzeDarkP3.bronze3,
bronze4: RadixColors.bronzeDarkP3.bronze4,
bronze5: RadixColors.bronzeDarkP3.bronze5,
bronze6: RadixColors.bronzeDarkP3.bronze6,
bronze7: RadixColors.bronzeDarkP3.bronze7,
bronze8: RadixColors.bronzeDarkP3.bronze8,
bronze9: RadixColors.bronzeDarkP3.bronze9,
bronze10: RadixColors.bronzeDarkP3.bronze10,
bronze11: RadixColors.bronzeDarkP3.bronze11,
bronze12: RadixColors.bronzeDarkP3.bronze12,
gold1: RadixColors.goldDarkP3.gold1,
gold2: RadixColors.goldDarkP3.gold2,
gold3: RadixColors.goldDarkP3.gold3,
gold4: RadixColors.goldDarkP3.gold4,
gold5: RadixColors.goldDarkP3.gold5,
gold6: RadixColors.goldDarkP3.gold6,
gold7: RadixColors.goldDarkP3.gold7,
gold8: RadixColors.goldDarkP3.gold8,
gold9: RadixColors.goldDarkP3.gold9,
gold10: RadixColors.goldDarkP3.gold10,
gold11: RadixColors.goldDarkP3.gold11,
gold12: RadixColors.goldDarkP3.gold12,
brown1: RadixColors.brownDarkP3.brown1,
brown2: RadixColors.brownDarkP3.brown2,
brown3: RadixColors.brownDarkP3.brown3,
brown4: RadixColors.brownDarkP3.brown4,
brown5: RadixColors.brownDarkP3.brown5,
brown6: RadixColors.brownDarkP3.brown6,
brown7: RadixColors.brownDarkP3.brown7,
brown8: RadixColors.brownDarkP3.brown8,
brown9: RadixColors.brownDarkP3.brown9,
brown10: RadixColors.brownDarkP3.brown10,
brown11: RadixColors.brownDarkP3.brown11,
brown12: RadixColors.brownDarkP3.brown12,
amber1: RadixColors.amberDarkP3.amber1,
amber2: RadixColors.amberDarkP3.amber2,
amber3: RadixColors.amberDarkP3.amber3,
amber4: RadixColors.amberDarkP3.amber4,
amber5: RadixColors.amberDarkP3.amber5,
amber6: RadixColors.amberDarkP3.amber6,
amber7: RadixColors.amberDarkP3.amber7,
amber8: RadixColors.amberDarkP3.amber8,
amber9: RadixColors.amberDarkP3.amber9,
amber10: RadixColors.amberDarkP3.amber10,
amber11: RadixColors.amberDarkP3.amber11,
amber12: RadixColors.amberDarkP3.amber12,
};
@@ -1,394 +0,0 @@
import * as RadixColors from '@radix-ui/colors';
import { GRAY_SCALE_LIGHT } from './GrayScaleLight';
export const SECONDARY_COLORS_LIGHT = {
yellow1: RadixColors.yellowP3.yellow1,
yellow2: RadixColors.yellowP3.yellow2,
yellow3: RadixColors.yellowP3.yellow3,
yellow4: RadixColors.yellowP3.yellow4,
yellow5: RadixColors.yellowP3.yellow5,
yellow6: RadixColors.yellowP3.yellow6,
yellow7: RadixColors.yellowP3.yellow7,
yellow8: RadixColors.yellowP3.yellow8,
yellow9: RadixColors.yellowP3.yellow9,
yellow10: RadixColors.yellowP3.yellow10,
yellow11: RadixColors.yellowP3.yellow11,
yellow12: RadixColors.yellowP3.yellow12,
green1: RadixColors.greenP3.green1,
green2: RadixColors.greenP3.green2,
green3: RadixColors.greenP3.green3,
green4: RadixColors.greenP3.green4,
green5: RadixColors.greenP3.green5,
green6: RadixColors.greenP3.green6,
green7: RadixColors.greenP3.green7,
green8: RadixColors.greenP3.green8,
green9: RadixColors.greenP3.green9,
green10: RadixColors.greenP3.green10,
green11: RadixColors.greenP3.green11,
green12: RadixColors.greenP3.green12,
turquoise1: RadixColors.tealP3.teal1,
turquoise2: RadixColors.tealP3.teal2,
turquoise3: RadixColors.tealP3.teal3,
turquoise4: RadixColors.tealP3.teal4,
turquoise5: RadixColors.tealP3.teal5,
turquoise6: RadixColors.tealP3.teal6,
turquoise7: RadixColors.tealP3.teal7,
turquoise8: RadixColors.tealP3.teal8,
turquoise9: RadixColors.tealP3.teal9,
turquoise10: RadixColors.tealP3.teal10,
turquoise11: RadixColors.tealP3.teal11,
turquoise12: RadixColors.tealP3.teal12,
sky1: RadixColors.skyP3.sky1,
sky2: RadixColors.skyP3.sky2,
sky3: RadixColors.skyP3.sky3,
sky4: RadixColors.skyP3.sky4,
sky5: RadixColors.skyP3.sky5,
sky6: RadixColors.skyP3.sky6,
sky7: RadixColors.skyP3.sky7,
sky8: RadixColors.skyP3.sky8,
sky9: RadixColors.skyP3.sky9,
sky10: RadixColors.skyP3.sky10,
sky11: RadixColors.skyP3.sky11,
sky12: RadixColors.skyP3.sky12,
blue1: RadixColors.indigoP3.indigo1,
blue2: RadixColors.indigoP3.indigo2,
blue3: RadixColors.indigoP3.indigo3,
blue4: RadixColors.indigoP3.indigo4,
blue5: RadixColors.indigoP3.indigo5,
blue6: RadixColors.indigoP3.indigo6,
blue7: RadixColors.indigoP3.indigo7,
blue8: RadixColors.indigoP3.indigo8,
blue9: RadixColors.indigoP3.indigo9,
blue10: RadixColors.indigoP3.indigo10,
blue11: RadixColors.indigoP3.indigo11,
blue12: RadixColors.indigoP3.indigo12,
purple1: RadixColors.purpleP3.purple1,
purple2: RadixColors.purpleP3.purple2,
purple3: RadixColors.purpleP3.purple3,
purple4: RadixColors.purpleP3.purple4,
purple5: RadixColors.purpleP3.purple5,
purple6: RadixColors.purpleP3.purple6,
purple7: RadixColors.purpleP3.purple7,
purple8: RadixColors.purpleP3.purple8,
purple9: RadixColors.purpleP3.purple9,
purple10: RadixColors.purpleP3.purple10,
purple11: RadixColors.purpleP3.purple11,
purple12: RadixColors.purpleP3.purple12,
pink1: RadixColors.pinkP3.pink1,
pink2: RadixColors.pinkP3.pink2,
pink3: RadixColors.pinkP3.pink3,
pink4: RadixColors.pinkP3.pink4,
pink5: RadixColors.pinkP3.pink5,
pink6: RadixColors.pinkP3.pink6,
pink7: RadixColors.pinkP3.pink7,
pink8: RadixColors.pinkP3.pink8,
pink9: RadixColors.pinkP3.pink9,
pink10: RadixColors.pinkP3.pink10,
pink11: RadixColors.pinkP3.pink11,
pink12: RadixColors.pinkP3.pink12,
red1: RadixColors.redP3.red1,
red2: RadixColors.redP3.red2,
red3: RadixColors.redP3.red3,
red4: RadixColors.redP3.red4,
red5: RadixColors.redP3.red5,
red6: RadixColors.redP3.red6,
red7: RadixColors.redP3.red7,
red8: RadixColors.redP3.red8,
red9: RadixColors.redP3.red9,
red10: RadixColors.redP3.red10,
red11: RadixColors.redP3.red11,
red12: RadixColors.redP3.red12,
orange1: RadixColors.orangeP3.orange1,
orange2: RadixColors.orangeP3.orange2,
orange3: RadixColors.orangeP3.orange3,
orange4: RadixColors.orangeP3.orange4,
orange5: RadixColors.orangeP3.orange5,
orange6: RadixColors.orangeP3.orange6,
orange7: RadixColors.orangeP3.orange7,
orange8: RadixColors.orangeP3.orange8,
orange9: RadixColors.orangeP3.orange9,
orange10: RadixColors.orangeP3.orange10,
orange11: RadixColors.orangeP3.orange11,
orange12: RadixColors.orangeP3.orange12,
gray1: GRAY_SCALE_LIGHT.gray1,
gray2: GRAY_SCALE_LIGHT.gray2,
gray3: GRAY_SCALE_LIGHT.gray3,
gray4: GRAY_SCALE_LIGHT.gray4,
gray5: GRAY_SCALE_LIGHT.gray5,
gray6: GRAY_SCALE_LIGHT.gray6,
gray7: GRAY_SCALE_LIGHT.gray7,
gray8: GRAY_SCALE_LIGHT.gray8,
gray9: GRAY_SCALE_LIGHT.gray9,
gray10: GRAY_SCALE_LIGHT.gray10,
gray11: GRAY_SCALE_LIGHT.gray11,
gray12: GRAY_SCALE_LIGHT.gray12,
mauve1: RadixColors.mauveP3.mauve1,
mauve2: RadixColors.mauveP3.mauve2,
mauve3: RadixColors.mauveP3.mauve3,
mauve4: RadixColors.mauveP3.mauve4,
mauve5: RadixColors.mauveP3.mauve5,
mauve6: RadixColors.mauveP3.mauve6,
mauve7: RadixColors.mauveP3.mauve7,
mauve8: RadixColors.mauveP3.mauve8,
mauve9: RadixColors.mauveP3.mauve9,
mauve10: RadixColors.mauveP3.mauve10,
mauve11: RadixColors.mauveP3.mauve11,
mauve12: RadixColors.mauveP3.mauve12,
slate1: RadixColors.slateP3.slate1,
slate2: RadixColors.slateP3.slate2,
slate3: RadixColors.slateP3.slate3,
slate4: RadixColors.slateP3.slate4,
slate5: RadixColors.slateP3.slate5,
slate6: RadixColors.slateP3.slate6,
slate7: RadixColors.slateP3.slate7,
slate8: RadixColors.slateP3.slate8,
slate9: RadixColors.slateP3.slate9,
slate10: RadixColors.slateP3.slate10,
slate11: RadixColors.slateP3.slate11,
slate12: RadixColors.slateP3.slate12,
sage1: RadixColors.sageP3.sage1,
sage2: RadixColors.sageP3.sage2,
sage3: RadixColors.sageP3.sage3,
sage4: RadixColors.sageP3.sage4,
sage5: RadixColors.sageP3.sage5,
sage6: RadixColors.sageP3.sage6,
sage7: RadixColors.sageP3.sage7,
sage8: RadixColors.sageP3.sage8,
sage9: RadixColors.sageP3.sage9,
sage10: RadixColors.sageP3.sage10,
sage11: RadixColors.sageP3.sage11,
sage12: RadixColors.sageP3.sage12,
olive1: RadixColors.oliveP3.olive1,
olive2: RadixColors.oliveP3.olive2,
olive3: RadixColors.oliveP3.olive3,
olive4: RadixColors.oliveP3.olive4,
olive5: RadixColors.oliveP3.olive5,
olive6: RadixColors.oliveP3.olive6,
olive7: RadixColors.oliveP3.olive7,
olive8: RadixColors.oliveP3.olive8,
olive9: RadixColors.oliveP3.olive9,
olive10: RadixColors.oliveP3.olive10,
olive11: RadixColors.oliveP3.olive11,
olive12: RadixColors.oliveP3.olive12,
sand1: RadixColors.sandP3.sand1,
sand2: RadixColors.sandP3.sand2,
sand3: RadixColors.sandP3.sand3,
sand4: RadixColors.sandP3.sand4,
sand5: RadixColors.sandP3.sand5,
sand6: RadixColors.sandP3.sand6,
sand7: RadixColors.sandP3.sand7,
sand8: RadixColors.sandP3.sand8,
sand9: RadixColors.sandP3.sand9,
sand10: RadixColors.sandP3.sand10,
sand11: RadixColors.sandP3.sand11,
sand12: RadixColors.sandP3.sand12,
tomato1: RadixColors.tomatoP3.tomato1,
tomato2: RadixColors.tomatoP3.tomato2,
tomato3: RadixColors.tomatoP3.tomato3,
tomato4: RadixColors.tomatoP3.tomato4,
tomato5: RadixColors.tomatoP3.tomato5,
tomato6: RadixColors.tomatoP3.tomato6,
tomato7: RadixColors.tomatoP3.tomato7,
tomato8: RadixColors.tomatoP3.tomato8,
tomato9: RadixColors.tomatoP3.tomato9,
tomato10: RadixColors.tomatoP3.tomato10,
tomato11: RadixColors.tomatoP3.tomato11,
tomato12: RadixColors.tomatoP3.tomato12,
ruby1: RadixColors.rubyP3.ruby1,
ruby2: RadixColors.rubyP3.ruby2,
ruby3: RadixColors.rubyP3.ruby3,
ruby4: RadixColors.rubyP3.ruby4,
ruby5: RadixColors.rubyP3.ruby5,
ruby6: RadixColors.rubyP3.ruby6,
ruby7: RadixColors.rubyP3.ruby7,
ruby8: RadixColors.rubyP3.ruby8,
ruby9: RadixColors.rubyP3.ruby9,
ruby10: RadixColors.rubyP3.ruby10,
ruby11: RadixColors.rubyP3.ruby11,
ruby12: RadixColors.rubyP3.ruby12,
crimson1: RadixColors.crimsonP3.crimson1,
crimson2: RadixColors.crimsonP3.crimson2,
crimson3: RadixColors.crimsonP3.crimson3,
crimson4: RadixColors.crimsonP3.crimson4,
crimson5: RadixColors.crimsonP3.crimson5,
crimson6: RadixColors.crimsonP3.crimson6,
crimson7: RadixColors.crimsonP3.crimson7,
crimson8: RadixColors.crimsonP3.crimson8,
crimson9: RadixColors.crimsonP3.crimson9,
crimson10: RadixColors.crimsonP3.crimson10,
crimson11: RadixColors.crimsonP3.crimson11,
crimson12: RadixColors.crimsonP3.crimson12,
plum1: RadixColors.plumP3.plum1,
plum2: RadixColors.plumP3.plum2,
plum3: RadixColors.plumP3.plum3,
plum4: RadixColors.plumP3.plum4,
plum5: RadixColors.plumP3.plum5,
plum6: RadixColors.plumP3.plum6,
plum7: RadixColors.plumP3.plum7,
plum8: RadixColors.plumP3.plum8,
plum9: RadixColors.plumP3.plum9,
plum10: RadixColors.plumP3.plum10,
plum11: RadixColors.plumP3.plum11,
plum12: RadixColors.plumP3.plum12,
violet1: RadixColors.violetP3.violet1,
violet2: RadixColors.violetP3.violet2,
violet3: RadixColors.violetP3.violet3,
violet4: RadixColors.violetP3.violet4,
violet5: RadixColors.violetP3.violet5,
violet6: RadixColors.violetP3.violet6,
violet7: RadixColors.violetP3.violet7,
violet8: RadixColors.violetP3.violet8,
violet9: RadixColors.violetP3.violet9,
violet10: RadixColors.violetP3.violet10,
violet11: RadixColors.violetP3.violet11,
violet12: RadixColors.violetP3.violet12,
iris1: RadixColors.irisP3.iris1,
iris2: RadixColors.irisP3.iris2,
iris3: RadixColors.irisP3.iris3,
iris4: RadixColors.irisP3.iris4,
iris5: RadixColors.irisP3.iris5,
iris6: RadixColors.irisP3.iris6,
iris7: RadixColors.irisP3.iris7,
iris8: RadixColors.irisP3.iris8,
iris9: RadixColors.irisP3.iris9,
iris10: RadixColors.irisP3.iris10,
iris11: RadixColors.irisP3.iris11,
iris12: RadixColors.irisP3.iris12,
cyan1: RadixColors.cyanP3.cyan1,
cyan2: RadixColors.cyanP3.cyan2,
cyan3: RadixColors.cyanP3.cyan3,
cyan4: RadixColors.cyanP3.cyan4,
cyan5: RadixColors.cyanP3.cyan5,
cyan6: RadixColors.cyanP3.cyan6,
cyan7: RadixColors.cyanP3.cyan7,
cyan8: RadixColors.cyanP3.cyan8,
cyan9: RadixColors.cyanP3.cyan9,
cyan10: RadixColors.cyanP3.cyan10,
cyan11: RadixColors.cyanP3.cyan11,
cyan12: RadixColors.cyanP3.cyan12,
jade1: RadixColors.jadeP3.jade1,
jade2: RadixColors.jadeP3.jade2,
jade3: RadixColors.jadeP3.jade3,
jade4: RadixColors.jadeP3.jade4,
jade5: RadixColors.jadeP3.jade5,
jade6: RadixColors.jadeP3.jade6,
jade7: RadixColors.jadeP3.jade7,
jade8: RadixColors.jadeP3.jade8,
jade9: RadixColors.jadeP3.jade9,
jade10: RadixColors.jadeP3.jade10,
jade11: RadixColors.jadeP3.jade11,
jade12: RadixColors.jadeP3.jade12,
grass1: RadixColors.grassP3.grass1,
grass2: RadixColors.grassP3.grass2,
grass3: RadixColors.grassP3.grass3,
grass4: RadixColors.grassP3.grass4,
grass5: RadixColors.grassP3.grass5,
grass6: RadixColors.grassP3.grass6,
grass7: RadixColors.grassP3.grass7,
grass8: RadixColors.grassP3.grass8,
grass9: RadixColors.grassP3.grass9,
grass10: RadixColors.grassP3.grass10,
grass11: RadixColors.grassP3.grass11,
grass12: RadixColors.grassP3.grass12,
mint1: RadixColors.mintP3.mint1,
mint2: RadixColors.mintP3.mint2,
mint3: RadixColors.mintP3.mint3,
mint4: RadixColors.mintP3.mint4,
mint5: RadixColors.mintP3.mint5,
mint6: RadixColors.mintP3.mint6,
mint7: RadixColors.mintP3.mint7,
mint8: RadixColors.mintP3.mint8,
mint9: RadixColors.mintP3.mint9,
mint10: RadixColors.mintP3.mint10,
mint11: RadixColors.mintP3.mint11,
mint12: RadixColors.mintP3.mint12,
lime1: RadixColors.limeP3.lime1,
lime2: RadixColors.limeP3.lime2,
lime3: RadixColors.limeP3.lime3,
lime4: RadixColors.limeP3.lime4,
lime5: RadixColors.limeP3.lime5,
lime6: RadixColors.limeP3.lime6,
lime7: RadixColors.limeP3.lime7,
lime8: RadixColors.limeP3.lime8,
lime9: RadixColors.limeP3.lime9,
lime10: RadixColors.limeP3.lime10,
lime11: RadixColors.limeP3.lime11,
lime12: RadixColors.limeP3.lime12,
bronze1: RadixColors.bronzeP3.bronze1,
bronze2: RadixColors.bronzeP3.bronze2,
bronze3: RadixColors.bronzeP3.bronze3,
bronze4: RadixColors.bronzeP3.bronze4,
bronze5: RadixColors.bronzeP3.bronze5,
bronze6: RadixColors.bronzeP3.bronze6,
bronze7: RadixColors.bronzeP3.bronze7,
bronze8: RadixColors.bronzeP3.bronze8,
bronze9: RadixColors.bronzeP3.bronze9,
bronze10: RadixColors.bronzeP3.bronze10,
bronze11: RadixColors.bronzeP3.bronze11,
bronze12: RadixColors.bronzeP3.bronze12,
gold1: RadixColors.goldP3.gold1,
gold2: RadixColors.goldP3.gold2,
gold3: RadixColors.goldP3.gold3,
gold4: RadixColors.goldP3.gold4,
gold5: RadixColors.goldP3.gold5,
gold6: RadixColors.goldP3.gold6,
gold7: RadixColors.goldP3.gold7,
gold8: RadixColors.goldP3.gold8,
gold9: RadixColors.goldP3.gold9,
gold10: RadixColors.goldP3.gold10,
gold11: RadixColors.goldP3.gold11,
gold12: RadixColors.goldP3.gold12,
brown1: RadixColors.brownP3.brown1,
brown2: RadixColors.brownP3.brown2,
brown3: RadixColors.brownP3.brown3,
brown4: RadixColors.brownP3.brown4,
brown5: RadixColors.brownP3.brown5,
brown6: RadixColors.brownP3.brown6,
brown7: RadixColors.brownP3.brown7,
brown8: RadixColors.brownP3.brown8,
brown9: RadixColors.brownP3.brown9,
brown10: RadixColors.brownP3.brown10,
brown11: RadixColors.brownP3.brown11,
brown12: RadixColors.brownP3.brown12,
amber1: RadixColors.amberP3.amber1,
amber2: RadixColors.amberP3.amber2,
amber3: RadixColors.amberP3.amber3,
amber4: RadixColors.amberP3.amber4,
amber5: RadixColors.amberP3.amber5,
amber6: RadixColors.amberP3.amber6,
amber7: RadixColors.amberP3.amber7,
amber8: RadixColors.amberP3.amber8,
amber9: RadixColors.amberP3.amber9,
amber10: RadixColors.amberP3.amber10,
amber11: RadixColors.amberP3.amber11,
amber12: RadixColors.amberP3.amber12,
};
@@ -1,26 +0,0 @@
import { BACKGROUND_DARK } from '@new-ui/theme/constants/BackgroundDark';
import { FONT_DARK } from '@new-ui/theme/constants/FontDark';
import { MAIN_COLORS_DARK } from '@new-ui/theme/constants/MainColorsDark';
export const SNACK_BAR_DARK = {
success: {
color: MAIN_COLORS_DARK.turquoise,
backgroundColor: BACKGROUND_DARK.transparent.success,
},
error: {
color: MAIN_COLORS_DARK.red,
backgroundColor: BACKGROUND_DARK.transparent.danger,
},
warning: {
color: MAIN_COLORS_DARK.orange,
backgroundColor: BACKGROUND_DARK.transparent.orange,
},
info: {
color: MAIN_COLORS_DARK.blue,
backgroundColor: BACKGROUND_DARK.transparent.blue,
},
default: {
color: FONT_DARK.color.primary,
backgroundColor: BACKGROUND_DARK.transparent.light,
},
};
@@ -1,26 +0,0 @@
import { BACKGROUND_LIGHT } from '@new-ui/theme/constants/BackgroundLight';
import { FONT_LIGHT } from '@new-ui/theme/constants/FontLight';
import { MAIN_COLORS_LIGHT } from '@new-ui/theme/constants/MainColorsLight';
export const SNACK_BAR_LIGHT = {
success: {
color: MAIN_COLORS_LIGHT.turquoise,
backgroundColor: BACKGROUND_LIGHT.transparent.success,
},
error: {
color: MAIN_COLORS_LIGHT.red,
backgroundColor: BACKGROUND_LIGHT.transparent.danger,
},
warning: {
color: MAIN_COLORS_LIGHT.orange,
backgroundColor: BACKGROUND_LIGHT.transparent.orange,
},
info: {
color: MAIN_COLORS_LIGHT.blue,
backgroundColor: BACKGROUND_LIGHT.transparent.blue,
},
default: {
color: FONT_LIGHT.color.primary,
backgroundColor: BACKGROUND_LIGHT.transparent.light,
},
};
@@ -1,68 +0,0 @@
import { COLOR_DARK } from '@new-ui/theme/constants/ColorsDark';
export const TAG_DARK = {
text: {
gray: COLOR_DARK.gray11,
mauve: COLOR_DARK.mauve11,
slate: COLOR_DARK.slate11,
sage: COLOR_DARK.sage11,
olive: COLOR_DARK.olive11,
sand: COLOR_DARK.sand11,
tomato: COLOR_DARK.tomato11,
red: COLOR_DARK.red11,
ruby: COLOR_DARK.ruby11,
crimson: COLOR_DARK.crimson11,
pink: COLOR_DARK.pink11,
plum: COLOR_DARK.plum11,
purple: COLOR_DARK.purple11,
violet: COLOR_DARK.violet11,
iris: COLOR_DARK.iris11,
cyan: COLOR_DARK.cyan11,
turquoise: COLOR_DARK.turquoise11,
sky: COLOR_DARK.sky11,
blue: COLOR_DARK.blue11,
jade: COLOR_DARK.jade11,
green: COLOR_DARK.green11,
grass: COLOR_DARK.grass11,
mint: COLOR_DARK.mint11,
lime: COLOR_DARK.lime11,
bronze: COLOR_DARK.bronze11,
gold: COLOR_DARK.gold11,
brown: COLOR_DARK.brown11,
orange: COLOR_DARK.orange11,
amber: COLOR_DARK.amber11,
yellow: COLOR_DARK.yellow11,
},
background: {
gray: COLOR_DARK.gray3,
mauve: COLOR_DARK.mauve3,
slate: COLOR_DARK.slate3,
sage: COLOR_DARK.sage3,
olive: COLOR_DARK.olive3,
sand: COLOR_DARK.sand3,
tomato: COLOR_DARK.tomato3,
red: COLOR_DARK.red3,
ruby: COLOR_DARK.ruby3,
crimson: COLOR_DARK.crimson3,
pink: COLOR_DARK.pink3,
plum: COLOR_DARK.plum3,
purple: COLOR_DARK.purple3,
violet: COLOR_DARK.violet3,
iris: COLOR_DARK.iris3,
cyan: COLOR_DARK.cyan3,
turquoise: COLOR_DARK.turquoise3,
sky: COLOR_DARK.sky3,
blue: COLOR_DARK.blue3,
jade: COLOR_DARK.jade3,
green: COLOR_DARK.green3,
grass: COLOR_DARK.grass3,
mint: COLOR_DARK.mint3,
lime: COLOR_DARK.lime3,
bronze: COLOR_DARK.bronze3,
gold: COLOR_DARK.gold3,
brown: COLOR_DARK.brown3,
orange: COLOR_DARK.orange3,
amber: COLOR_DARK.amber3,
yellow: COLOR_DARK.yellow3,
},
};
@@ -1,68 +0,0 @@
import { COLOR_LIGHT } from '@new-ui/theme/constants/ColorsLight';
export const TAG_LIGHT = {
text: {
gray: COLOR_LIGHT.gray11,
mauve: COLOR_LIGHT.mauve11,
slate: COLOR_LIGHT.slate11,
sage: COLOR_LIGHT.sage11,
olive: COLOR_LIGHT.olive11,
sand: COLOR_LIGHT.sand11,
tomato: COLOR_LIGHT.tomato11,
red: COLOR_LIGHT.red11,
ruby: COLOR_LIGHT.ruby11,
crimson: COLOR_LIGHT.crimson11,
pink: COLOR_LIGHT.pink11,
plum: COLOR_LIGHT.plum11,
purple: COLOR_LIGHT.purple11,
violet: COLOR_LIGHT.violet11,
iris: COLOR_LIGHT.iris11,
cyan: COLOR_LIGHT.cyan11,
turquoise: COLOR_LIGHT.turquoise11,
sky: COLOR_LIGHT.sky11,
blue: COLOR_LIGHT.blue11,
jade: COLOR_LIGHT.jade11,
green: COLOR_LIGHT.green11,
grass: COLOR_LIGHT.grass11,
mint: COLOR_LIGHT.mint11,
lime: COLOR_LIGHT.lime11,
bronze: COLOR_LIGHT.bronze11,
gold: COLOR_LIGHT.gold11,
brown: COLOR_LIGHT.brown11,
orange: COLOR_LIGHT.orange11,
amber: COLOR_LIGHT.amber11,
yellow: COLOR_LIGHT.yellow11,
},
background: {
gray: COLOR_LIGHT.gray3,
mauve: COLOR_LIGHT.mauve3,
slate: COLOR_LIGHT.slate3,
sage: COLOR_LIGHT.sage3,
olive: COLOR_LIGHT.olive3,
sand: COLOR_LIGHT.sand3,
tomato: COLOR_LIGHT.tomato3,
red: COLOR_LIGHT.red3,
ruby: COLOR_LIGHT.ruby3,
crimson: COLOR_LIGHT.crimson3,
pink: COLOR_LIGHT.pink3,
plum: COLOR_LIGHT.plum3,
purple: COLOR_LIGHT.purple3,
violet: COLOR_LIGHT.violet3,
iris: COLOR_LIGHT.iris3,
cyan: COLOR_LIGHT.cyan3,
turquoise: COLOR_LIGHT.turquoise3,
sky: COLOR_LIGHT.sky3,
blue: COLOR_LIGHT.blue3,
jade: COLOR_LIGHT.jade3,
green: COLOR_LIGHT.green3,
grass: COLOR_LIGHT.grass3,
mint: COLOR_LIGHT.mint3,
lime: COLOR_LIGHT.lime3,
bronze: COLOR_LIGHT.bronze3,
gold: COLOR_LIGHT.gold3,
brown: COLOR_LIGHT.brown3,
orange: COLOR_LIGHT.orange3,
amber: COLOR_LIGHT.amber3,
yellow: COLOR_LIGHT.yellow3,
},
};
@@ -1,13 +0,0 @@
export const TEXT = {
lineHeight: {
lg: 1.5,
md: 1.1,
},
iconSizeMedium: 16,
iconSizeSmall: 14,
iconStrikeLight: 1.6,
iconStrikeMedium: 2,
iconStrikeBold: 2.5,
};
@@ -1,27 +0,0 @@
import { ACCENT_DARK } from '@new-ui/theme/constants/AccentDark';
import { ANIMATION } from './Animation';
import { ICON } from './Icon';
import { MODAL } from './Modal';
import { TEXT } from './Text';
export const THEME_COMMON = {
icon: ICON,
modal: MODAL,
text: TEXT,
animation: ANIMATION,
spacingMultiplicator: 4,
spacing: (...args: number[]) =>
args.map((multiplicator) => `${multiplicator * 4}px`).join(' '),
betweenSiblingsGap: `2px`,
table: {
horizontalCellMargin: '8px',
checkboxColumnWidth: '32px',
horizontalCellPadding: '8px',
},
sidePanelWidth: '500px',
clickableElementBackgroundTransition: 'background 0.1s ease',
lastLayerZIndex: 2147483647,
buttons: {
secondaryTextColor: ACCENT_DARK.accent11,
},
};
@@ -1,33 +0,0 @@
import { BLUR_DARK } from '@new-ui/theme/constants/BlurDark';
import { ILLUSTRATION_ICON_DARK } from '@new-ui/theme/constants/IllustrationIconDark';
import { COLOR_DARK } from './ColorsDark';
import { GRAY_SCALE_DARK } from './GrayScaleDark';
import { SNACK_BAR_DARK } from './SnackBarDark';
import { ACCENT_DARK } from './AccentDark';
import { BACKGROUND_DARK } from './BackgroundDark';
import { BORDER_DARK } from './BorderDark';
import { BOX_SHADOW_DARK } from './BoxShadowDark';
import { CODE_DARK } from './CodeDark';
import { FONT_DARK } from './FontDark';
import { TAG_DARK } from './TagDark';
import { THEME_COMMON } from './ThemeCommon';
import type { THEME_LIGHT } from './ThemeLight';
export const THEME_DARK: typeof THEME_LIGHT = {
...THEME_COMMON,
...{
accent: ACCENT_DARK,
background: BACKGROUND_DARK,
blur: BLUR_DARK,
border: BORDER_DARK,
boxShadow: BOX_SHADOW_DARK,
font: FONT_DARK,
name: 'dark',
snackBar: SNACK_BAR_DARK,
tag: TAG_DARK,
code: CODE_DARK,
IllustrationIcon: ILLUSTRATION_ICON_DARK,
grayScale: GRAY_SCALE_DARK,
color: COLOR_DARK,
},
};
@@ -1,32 +0,0 @@
import { BLUR_LIGHT } from '@new-ui/theme/constants/BlurLight';
import { COLOR_LIGHT } from '@new-ui/theme/constants/ColorsLight';
import { GRAY_SCALE_LIGHT } from '@new-ui/theme/constants/GrayScaleLight';
import { ILLUSTRATION_ICON_LIGHT } from '@new-ui/theme/constants/IllustrationIconLight';
import { SNACK_BAR_LIGHT } from '@new-ui/theme/constants/SnackBarLight';
import { ACCENT_LIGHT } from './AccentLight';
import { BACKGROUND_LIGHT } from './BackgroundLight';
import { BORDER_LIGHT } from './BorderLight';
import { BOX_SHADOW_LIGHT } from './BoxShadowLight';
import { CODE_LIGHT } from './CodeLight';
import { FONT_LIGHT } from './FontLight';
import { TAG_LIGHT } from './TagLight';
import { THEME_COMMON } from './ThemeCommon';
export const THEME_LIGHT = {
...THEME_COMMON,
...{
accent: ACCENT_LIGHT,
background: BACKGROUND_LIGHT,
blur: BLUR_LIGHT,
border: BORDER_LIGHT,
boxShadow: BOX_SHADOW_LIGHT,
font: FONT_LIGHT,
name: 'light',
snackBar: SNACK_BAR_LIGHT,
tag: TAG_LIGHT,
code: CODE_LIGHT,
IllustrationIcon: ILLUSTRATION_ICON_LIGHT,
grayScale: GRAY_SCALE_LIGHT,
color: COLOR_LIGHT,
},
};

Some files were not shown because too many files have changed in this diff Show More