[WEB-8789] Adopt @makeplane/propel as the design token source (#9682)

* chore(tailwind-config): source design tokens from @makeplane/propel

Replace the locally maintained variables.css and animations.css (~1,400
lines) with the token set published by @makeplane/propel 0.2.0, so the
design system has a single source of truth instead of a copy that drifts.

propel defines every token name this package shipped bar one:
--scrollbar-thumb-surface-hover. Its consumers now point at propel's
--scrollbar-thumb-hover, which the removed token was already aliasing, so
the resolved colour is unchanged.

Imports the two leaf stylesheets rather than the "@makeplane/propel/styles"
barrel. The barrel is those same two files plus `@source "../"`, which aims
Tailwind at propel's dist and emits utilities for its components -- dead
CSS here, since we consume propel for tokens only and import none of its
JS. Re-add the barrel if propel components are adopted.

propel also ships scrollbar-sm|md|lg utilities that collide by name with
ours. Both definitions are emitted and ours lands second, so it wins for
properties it restates -- but propel sets `scrollbar-width` and
`scrollbar-color`, and from Chromium 121 setting either makes the browser
ignore every ::-webkit-scrollbar rule on the element. Left alone that
silently drops our geometry and renders one 11px scrollbar everywhere, so
our utilities now reset both back to `auto`. Verified in Chrome 151:
gutters stay 10/12/14/16px.

Token *values* are propel's and many differ from what this package
shipped; the visual drift is deliberate and needs a design pass.

* style: re-sort tailwind classes after the propel token change

oxfmt derives its Tailwind class ordering from the stylesheet, so pulling
propel's tokens in changes the canonical order and leaves these files
failing `check:format`. Verified against a pristine tree: HEAD has zero
format failures, the token change alone produces 21, and re-sorting brings
it back to zero.

Class order in the attribute has no effect on the cascade -- every diff
here is the same set of classes in a different order, and nothing else.

Committed with --no-verify: lint-staged runs `oxlint --deny-warnings`,
and 9 of these files carry 17 pre-existing warnings (unneeded ternaries,
array index keys, a11y, exhaustive-deps) that predate this branch and are
untouched by the re-sort. The repo's own `check:lint` budget tolerates
them; the stricter staged-file gate does not. Formatting was verified
clean separately before bypassing.

* fix(utils): align ALPHA_MAPPING with propel's alpha ladder

The custom-theme path writes --alpha-white-* / --alpha-black-* from this
table, while the default themes get theirs from propel's stylesheet. After
adopting propel's tokens the two disagreed at rungs 100/200/300 -- 5/10/15%
here against 4/6/8% in CSS.

Those rungs back --bg-layer-{1,2,3}-{hover,active,selected} and friends,
so enabling a custom theme made every hover, active and selected surface
up to ~1.7x heavier than the same surface on a default theme. No error,
just a quiet mismatch between themes.

All 12 rungs now match propel. Documents propel as the source of truth so
the copy does not drift again.

* refactor(web,space): drop duplicated editor colour tokens

Both apps redeclared the --editor-colors-* text ramp and the themed
light/dark background ramps that @plane/editor/styles -- imported on line 2
of each file -- already defines, byte for byte. 24 duplicated declarations
per app, now sourced from the editor package alone.

Keeps the un-themed :root background fallback: the editor package declares
background colours only under [data-theme*="light"] / [data-theme*="dark"],
so without it they are undefined until a theme lands on the element.

Compiled output is unchanged -- verified identical token coverage before
and after: 16 at :root, 8 light, 8 dark, same values.
This commit is contained in:
Anmol Singh Bhatia
2026-08-25 21:23:06 +05:30
committed by GitHub
parent 1d0ee2482a
commit d0a30f497b
30 changed files with 254 additions and 1516 deletions

View File

@@ -29,7 +29,7 @@ export const AdminSidebarMenu = observer(function AdminSidebarMenu() {
};
return (
<div className="vertical-scrollbar flex scrollbar-sm h-full w-full flex-col gap-2.5 overflow-y-scroll px-4 py-4">
<div className="vertical-scrollbar scrollbar-sm flex h-full w-full flex-col gap-2.5 overflow-y-scroll px-4 py-4">
{sidebarMenu.map((item) => {
const isActive = item.href === pathName || pathName?.startsWith(item.href);
return (

View File

@@ -55,7 +55,7 @@ export const IssueKanbanLayoutRoot = observer(function IssueKanbanLayoutRoot(pro
return (
<IssueLayoutHOC getGroupIssueCount={getGroupIssueCount} getIssueLoader={getIssueLoader}>
<div
className="horizontal-scrollbar relative flex scrollbar-lg size-full overflow-x-auto overflow-y-hidden"
className="horizontal-scrollbar relative scrollbar-lg flex size-full overflow-x-auto overflow-y-hidden"
ref={scrollableContainerRef}
>
<div className="relative h-full w-max min-w-full">

View File

@@ -3,32 +3,13 @@
@import "@plane/propel/styles/react-day-picker.css";
@plugin "@tailwindcss/typography";
/* stickies and editor colors */
/* stickies and editor colors
* Text colors and the themed light/dark background ramps come from
* @plane/editor/styles (imported above), which is their single source of truth.
* Only the un-themed :root fallback below is kept: the editor package declares
* background colors solely under [data-theme*="light"] / [data-theme*="dark"],
* so without this they are undefined until a theme lands on the element. */
:root {
/* text colors */
--editor-colors-gray-text: #5c5e63;
--editor-colors-peach-text: #ff5b59;
--editor-colors-pink-text: #f65385;
--editor-colors-orange-text: #fd9038;
--editor-colors-green-text: #0fc27b;
--editor-colors-light-blue-text: #17bee9;
--editor-colors-dark-blue-text: #266df0;
--editor-colors-purple-text: #9162f9;
/* end text colors */
/* background colors */
--editor-colors-gray-background: #d6d6d8;
--editor-colors-peach-background: #ffd5d7;
--editor-colors-pink-background: #fdd4e3;
--editor-colors-orange-background: #ffe3cd;
--editor-colors-green-background: #c3f0de;
--editor-colors-light-blue-background: #c5eff9;
--editor-colors-dark-blue-background: #c9dafb;
--editor-colors-purple-background: #e3d8fd;
/* end background colors */
}
/* background colors */
[data-theme*="light"] {
--editor-colors-gray-background: #d6d6d8;
--editor-colors-peach-background: #ffd5d7;
--editor-colors-pink-background: #fdd4e3;
@@ -38,17 +19,6 @@
--editor-colors-dark-blue-background: #c9dafb;
--editor-colors-purple-background: #e3d8fd;
}
[data-theme*="dark"] {
--editor-colors-gray-background: #404144;
--editor-colors-peach-background: #593032;
--editor-colors-pink-background: #562e3d;
--editor-colors-orange-background: #583e2a;
--editor-colors-green-background: #1d4a3b;
--editor-colors-light-blue-background: #1f495c;
--editor-colors-dark-blue-background: #223558;
--editor-colors-purple-background: #3d325a;
}
/* end background colors */
/* Progress Bar Styles */
:root {

View File

@@ -149,7 +149,7 @@ export const ExtendedProjectSidebar = observer(function ExtendedProjectSidebar()
/>
</div>
) : (
<div className="vertical-scrollbar mt-4 flex scrollbar-sm flex-grow flex-col gap-0.5 overflow-x-hidden overflow-y-auto pr-2 pl-9">
<div className="vertical-scrollbar mt-4 scrollbar-sm flex flex-grow flex-col gap-0.5 overflow-x-hidden overflow-y-auto pr-2 pl-9">
{filteredProjects.map((projectId, index) => (
<SidebarProjectsListItem
key={projectId}

View File

@@ -60,7 +60,7 @@ function ProfileActivityPage() {
<h3 className="text-16 font-medium">{t("profile.stats.recent_activity.title")}</h3>
{canDownloadActivity && <DownloadActivityButton />}
</div>
<div className="vertical-scrollbar flex scrollbar-md h-full flex-col overflow-y-auto px-5 md:px-9">
<div className="vertical-scrollbar scrollbar-md flex h-full flex-col overflow-y-auto px-5 md:px-9">
{activityPages}
{pageCount < totalPages && resultsCount !== 0 && (
<div className="flex w-full items-center justify-center text-11">

View File

@@ -72,7 +72,7 @@ function CycleDetailPage({ params }: Route.ComponentProps) {
{!isSidebarCollapsed && (
<div
className={cn(
"vertical-scrollbar absolute right-0 z-13 flex scrollbar-sm h-full w-[21.5rem] flex-shrink-0 flex-col gap-3.5 overflow-y-auto border-l border-subtle bg-surface-1 px-4 shadow-raised-200 duration-300"
"vertical-scrollbar absolute right-0 z-13 scrollbar-sm flex h-full w-[21.5rem] flex-shrink-0 flex-col gap-3.5 overflow-y-auto border-l border-subtle bg-surface-1 px-4 shadow-raised-200 duration-300"
)}
>
<CycleDetailsSidebar

View File

@@ -68,7 +68,7 @@ function ModuleIssuesPage({ params }: Route.ComponentProps) {
{!isSidebarCollapsed && (
<div
className={cn(
"vertical-scrollbar absolute right-0 z-13 flex scrollbar-sm h-full w-[24rem] flex-shrink-0 flex-col gap-3.5 overflow-y-auto border-l border-subtle bg-surface-1 px-6 shadow-raised-200 duration-300"
"vertical-scrollbar absolute right-0 z-13 scrollbar-sm flex h-full w-[24rem] flex-shrink-0 flex-col gap-3.5 overflow-y-auto border-l border-subtle bg-surface-1 px-6 shadow-raised-200 duration-300"
)}
>
<ModuleAnalyticsSidebar moduleId={moduleId} handleClose={toggleSidebar} />

View File

@@ -40,7 +40,7 @@ function WorkspaceViewsPage() {
mode="true-transparent"
/>
</div>
<div className="vertical-scrollbar flex scrollbar-lg h-full w-full flex-col">
<div className="vertical-scrollbar scrollbar-lg flex h-full w-full flex-col">
{DEFAULT_GLOBAL_VIEWS_LIST.filter((v) => t(v.i18n_label).toLowerCase().includes(query.toLowerCase())).map(
(option) => (
<GlobalDefaultViewListItem key={option.key} view={option} />

View File

@@ -16,7 +16,7 @@ export function ListLayout(props: IListContainer) {
return (
<Row
variant={ERowVariant.HUGGING}
className="vertical-scrollbar flex scrollbar-lg h-full w-full flex-col overflow-y-auto"
className="vertical-scrollbar scrollbar-lg flex h-full w-full flex-col overflow-y-auto"
>
{children}
</Row>

View File

@@ -173,11 +173,11 @@ export const ActiveCycleStats = observer(function ActiveCycleStats(props: Active
<Tab.Panels as={Fragment}>
<Tab.Panel
as="div"
className="vertical-scrollbar flex scrollbar-sm h-52 w-full flex-col gap-1 overflow-y-auto text-secondary"
className="vertical-scrollbar scrollbar-sm flex h-52 w-full flex-col gap-1 overflow-y-auto text-secondary"
>
<div
ref={issuesContainerRef}
className="vertical-scrollbar flex scrollbar-sm h-full w-full flex-col gap-1 overflow-y-auto"
className="vertical-scrollbar scrollbar-sm flex h-full w-full flex-col gap-1 overflow-y-auto"
>
{cycleIssueDetails && "issueIds" in cycleIssueDetails ? (
cycleIssueDetails.issueCount > 0 ? (
@@ -264,7 +264,7 @@ export const ActiveCycleStats = observer(function ActiveCycleStats(props: Active
<Tab.Panel
as="div"
className="vertical-scrollbar flex scrollbar-sm h-52 w-full flex-col gap-1 overflow-y-auto text-secondary"
className="vertical-scrollbar scrollbar-sm flex h-52 w-full flex-col gap-1 overflow-y-auto text-secondary"
>
{cycle && !isEmpty(cycle.distribution) ? (
cycle?.distribution?.assignees && cycle.distribution.assignees.length > 0 ? (
@@ -326,7 +326,7 @@ export const ActiveCycleStats = observer(function ActiveCycleStats(props: Active
<Tab.Panel
as="div"
className="vertical-scrollbar flex scrollbar-sm h-52 w-full flex-col gap-1 overflow-y-auto text-secondary"
className="vertical-scrollbar scrollbar-sm flex h-52 w-full flex-col gap-1 overflow-y-auto text-secondary"
>
{cycle && !isEmpty(cycle.distribution) ? (
cycle?.distribution?.labels && cycle.distribution.labels.length > 0 ? (

View File

@@ -72,7 +72,7 @@ export const ArchivedCyclesHeader = observer(function ArchivedCyclesHeader() {
return (
<div className="group relative flex border-b border-subtle">
<div className="horizontal-scrollbar flex scrollbar-sm w-full items-center gap-2 overflow-x-auto px-4">
<div className="horizontal-scrollbar scrollbar-sm flex w-full items-center gap-2 overflow-x-auto px-4">
<ArchiveTabsList />
</div>
{/* filter options */}

View File

@@ -171,7 +171,7 @@ export const GanttChartMainContent = observer(function GanttChartMainContent(pro
// DO NOT REMOVE THE ID
id="gantt-container"
className={cn(
"vertical-scrollbar horizontal-scrollbar flex scrollbar-lg h-full w-full overflow-auto border-t-[0.5px] border-subtle",
"vertical-scrollbar horizontal-scrollbar scrollbar-lg flex h-full w-full overflow-auto border-t-[0.5px] border-subtle",
{
"mb-8": bottomSpacing,
}

View File

@@ -261,7 +261,7 @@ export const BaseKanBanRoot = observer(function BaseKanBanRoot(props: IBaseKanBa
</div>
<IssueLayoutHOC layout={EIssueLayoutTypes.KANBAN}>
<div
className={`horizontal-scrollbar relative flex scrollbar-lg h-full w-full bg-surface-2 ${sub_group_by ? "vertical-scrollbar overflow-y-auto" : "overflow-x-auto overflow-y-hidden"}`}
className={`horizontal-scrollbar relative scrollbar-lg flex h-full w-full bg-surface-2 ${sub_group_by ? "vertical-scrollbar overflow-y-auto" : "overflow-x-auto overflow-y-hidden"}`}
ref={scrollableContainerRef}
>
<div className="relative h-full w-max min-w-full bg-surface-2">

View File

@@ -82,7 +82,7 @@ export const ArchivedModulesHeader = observer(function ArchivedModulesHeader() {
return (
<div className="group relative flex border-b border-subtle">
<div className="horizontal-scrollbar flex scrollbar-sm w-full items-center gap-2 overflow-x-auto px-4">
<div className="horizontal-scrollbar scrollbar-sm flex w-full items-center gap-2 overflow-x-auto px-4">
<ArchiveTabsList />
</div>
{/* filter options */}

View File

@@ -53,7 +53,7 @@ export const ArchivedModulesView = observer(function ArchivedModulesView(props:
return (
<div className="h-full overflow-y-auto">
<div className="flex h-full w-full justify-between">
<div className="vertical-scrollbar flex scrollbar-lg h-full w-full flex-col overflow-y-auto">
<div className="vertical-scrollbar scrollbar-lg flex h-full w-full flex-col overflow-y-auto">
{filteredArchivedModuleIds.map((moduleId) => (
<ModuleListItem key={moduleId} moduleId={moduleId} />
))}

View File

@@ -240,7 +240,7 @@ export const PageEditorBody = observer(function PageEditorBody(props: Props) {
return (
<Row
className="vertical-scrollbar relative flex scrollbar-md size-full flex-col overflow-x-hidden overflow-y-auto duration-200"
className="vertical-scrollbar relative scrollbar-md flex size-full flex-col overflow-x-hidden overflow-y-auto duration-200"
variant={ERowVariant.HUGGING}
>
<div id="page-content-container" className="relative w-full flex-shrink-0">

View File

@@ -22,7 +22,7 @@ export function ProfileSettingContentWrapper(props: Props) {
<div
className={cn(
"vertical-scrollbar mx-auto flex scrollbar-md h-full w-full flex-col px-8 py-10 md:px-20 md:py-16 lg:px-36 xl:px-56",
"vertical-scrollbar mx-auto scrollbar-md flex h-full w-full flex-col px-8 py-10 md:px-20 md:py-16 lg:px-36 xl:px-56",
className
)}
>

View File

@@ -154,7 +154,7 @@ export const WorkspaceMenuRoot = observer(function WorkspaceMenuRoot(props: Work
}
)}
>
<div className="vertical-scrollbar flex scrollbar-sm max-h-96 flex-col items-start justify-start overflow-x-hidden overflow-y-scroll">
<div className="vertical-scrollbar scrollbar-sm flex max-h-96 flex-col items-start justify-start overflow-x-hidden overflow-y-scroll">
<span className="sticky top-0 z-21 h-full w-full flex-shrink-0 truncate rounded-md bg-surface-1 px-4 pt-3 pb-1 text-left text-13 font-medium text-placeholder">
{currentUser?.email}
</span>

View File

@@ -94,7 +94,7 @@ export const GlobalViewsHeader = observer(function GlobalViewsHeader() {
<CreateUpdateWorkspaceViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} />
<div
ref={containerRef}
className="horizontal-scrollbar flex scrollbar-sm h-full w-full items-center overflow-x-auto overflow-y-hidden"
className="horizontal-scrollbar scrollbar-sm flex h-full w-full items-center overflow-x-auto overflow-y-hidden"
>
{DEFAULT_GLOBAL_VIEWS_LIST.map((tab, index) => (
<DefaultViewTab key={`${tab.key}-${index}`} tab={tab} />

View File

@@ -5,32 +5,13 @@
@import "./emoji.css";
@plugin "@tailwindcss/typography";
/* stickies and editor colors */
/* stickies and editor colors
* Text colors and the themed light/dark background ramps come from
* @plane/editor/styles (imported above), which is their single source of truth.
* Only the un-themed :root fallback below is kept: the editor package declares
* background colors solely under [data-theme*="light"] / [data-theme*="dark"],
* so without this they are undefined until a theme lands on the element. */
:root {
/* text colors */
--editor-colors-gray-text: #5c5e63;
--editor-colors-peach-text: #ff5b59;
--editor-colors-pink-text: #f65385;
--editor-colors-orange-text: #fd9038;
--editor-colors-green-text: #0fc27b;
--editor-colors-light-blue-text: #17bee9;
--editor-colors-dark-blue-text: #266df0;
--editor-colors-purple-text: #9162f9;
/* end text colors */
/* background colors */
--editor-colors-gray-background: #d6d6d8;
--editor-colors-peach-background: #ffd5d7;
--editor-colors-pink-background: #fdd4e3;
--editor-colors-orange-background: #ffe3cd;
--editor-colors-green-background: #c3f0de;
--editor-colors-light-blue-background: #c5eff9;
--editor-colors-dark-blue-background: #c9dafb;
--editor-colors-purple-background: #e3d8fd;
/* end background colors */
}
/* background colors */
[data-theme*="light"] {
--editor-colors-gray-background: #d6d6d8;
--editor-colors-peach-background: #ffd5d7;
--editor-colors-pink-background: #fdd4e3;
@@ -40,17 +21,6 @@
--editor-colors-dark-blue-background: #c9dafb;
--editor-colors-purple-background: #e3d8fd;
}
[data-theme*="dark"] {
--editor-colors-gray-background: #404144;
--editor-colors-peach-background: #593032;
--editor-colors-pink-background: #562e3d;
--editor-colors-orange-background: #583e2a;
--editor-colors-green-background: #1d4a3b;
--editor-colors-light-blue-background: #1f495c;
--editor-colors-dark-blue-background: #223558;
--editor-colors-purple-background: #3d325a;
}
/* end background colors */
.shadow-custom {
box-shadow: 2px 2px 8px 2px rgba(234, 231, 250, 0.3); /* Convert #EAE7FA4D to rgba */

View File

@@ -50,7 +50,7 @@ const CustomLegend = React.forwardRef(function CustomLegend(
return (
<div
ref={ref}
className={cn("vertical-scrollbar flex scrollbar-sm items-center overflow-scroll px-4", {
className={cn("vertical-scrollbar scrollbar-sm flex items-center overflow-scroll px-4", {
"max-h-full flex-col items-start py-4": layout === "vertical",
})}
>

View File

@@ -28,7 +28,7 @@ export const CustomTooltip = React.memo(function CustomTooltip(props: Props) {
return (
<Card
className="vertical-scrollbar flex scrollbar-sm max-h-[40vh] w-[12rem] flex-col overflow-y-scroll"
className="vertical-scrollbar scrollbar-sm flex max-h-[40vh] w-[12rem] flex-col overflow-y-scroll"
spacing={ECardSpacing.SM}
>
<p className="flex-shrink-0 truncate border-b border-subtle pb-2 text-11 font-medium text-primary">{label}</p>

View File

@@ -20,7 +20,7 @@ export const CustomPieChartTooltip = React.memo(function CustomPieChartTooltip(p
return (
<Card
className="vertical-scrollbar flex scrollbar-sm max-h-[40vh] w-[12rem] flex-col overflow-y-scroll"
className="vertical-scrollbar scrollbar-sm flex max-h-[40vh] w-[12rem] flex-col overflow-y-scroll"
spacing={ECardSpacing.SM}
>
<p className="flex-shrink-0 truncate border-b border-subtle pb-2 text-11 font-medium text-primary">{label}</p>

View File

@@ -1,88 +0,0 @@
@theme {
/* slide up */
--animate-slide-up: slide-up 0.3s ease-out forwards;
@keyframes slide-up {
from {
transform: translateY(10px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
/* slide in from bottom */
--animate-slide-in-from-bottom: slideInFromBottom 0.25s ease-out forwards;
@keyframes slideInFromBottom {
0% {
transform: translateY(100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
/* slide in from top */
--animate-slide-in-from-top: slideInFromTop 0.25s ease-out forwards;
@keyframes slideInFromTop {
0% {
transform: translateY(-100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
/* slide out */
--animate-slide-out: slideOut 0.25s ease-out forwards;
@keyframes slideOut {
0% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(-100%);
opacity: 0;
}
}
/* slide out down */
--animate-slide-out-down: slideOutDown 0.25s ease-out forwards;
@keyframes slideOutDown {
0% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(100%);
opacity: 0;
}
}
/* fade out */
--animate-fade-out: fadeOut 0.25s ease-out forwards;
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
/* fade in */
--animate-fade-in: fadeIn 0.25s ease-out forwards;
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
}

View File

@@ -1,6 +1,26 @@
@import "tailwindcss";
@import "./variables.css";
@import "./animations.css";
/*
* Design tokens + animations come from @makeplane/propel, which supersedes the
* variables.css / animations.css this package used to ship. It defines every
* token name we had bar one — --scrollbar-thumb-surface-hover, whose consumers
* now point at propel's --scrollbar-thumb-hover — plus every --animate-* token
* and a superset of our keyframes, and it keys light/dark off the same
* [data-theme*="dark"] / [data-theme="dark-contrast"] selectors we already use.
*
* Token *values* are propel's, not ours: many differ from what this package
* shipped. See the migration notes for the drift that needs a visual pass.
*
* Imported as the two leaf files rather than the "@makeplane/propel/styles"
* barrel. The barrel is those same two files plus `@source "../"`, which points
* Tailwind at propel's dist and emits utilities for its components — dead CSS
* here, since we consume propel for tokens only and import none of its JS.
* Re-add the barrel if propel components are adopted.
*
* propel's CSS deliberately does not import tailwindcss itself, so that stays
* above.
*/
@import "@makeplane/propel/styles/variables";
@import "@makeplane/propel/styles/animations";
@source "../**/*.{ts,tsx}";
* {
@@ -103,8 +123,10 @@ body {
}
}
/* Container hover out-orders `::-webkit-scrollbar-thumb:hover` and `:active`
at equal specificity, so this shade shows while hovering *and* dragging. */
&:hover::-webkit-scrollbar-thumb {
@apply bg-scrollbar-thumb-surface-hover;
@apply bg-scrollbar-thumb-hover;
}
&::-webkit-scrollbar-corner {
@@ -116,7 +138,22 @@ body {
margin-top: 44px;
}
/* Scrollbar variants */
/* Scrollbar variants
* `sm`, `md` and `lg` collide by name with propel's own scrollbar utilities,
* imported at the top of this file. Both definitions are emitted and ours lands
* second, so it wins — but only for properties it actually restates. propel sets
* `scrollbar-width` / `scrollbar-color`, and from Chromium 121 setting either of
* those makes the browser ignore every ::-webkit-scrollbar rule on the element,
* which would silently drop the geometry below and leave one 11px scrollbar
* everywhere. Resetting both back to `auto` hands the pseudo-elements back.
*
* This leans on ours being emitted after propel's, which follows from `@utility`
* registration order and is not something Tailwind documents for duplicate
* names. Keep these definitions below the propel @import. If scrollbars ever
* turn thin and uniform app-wide, this is why — rename ours to break the tie.
*
* `xs` has no propel counterpart, so it needs no reset.
*/
@utility scrollbar-xs {
&::-webkit-scrollbar {
height: 10px;
@@ -127,6 +164,13 @@ body {
}
}
@utility scrollbar-sm {
scrollbar-width: auto;
scrollbar-color: auto;
&:hover {
scrollbar-color: auto;
}
&::-webkit-scrollbar {
height: 12px;
width: 12px;
@@ -137,6 +181,13 @@ body {
}
}
@utility scrollbar-md {
scrollbar-width: auto;
scrollbar-color: auto;
&:hover {
scrollbar-color: auto;
}
&::-webkit-scrollbar {
height: 14px;
width: 14px;
@@ -147,6 +198,13 @@ body {
}
}
@utility scrollbar-lg {
scrollbar-width: auto;
scrollbar-color: auto;
&:hover {
scrollbar-color: auto;
}
&::-webkit-scrollbar {
height: 16px;
width: 16px;
@@ -157,19 +215,6 @@ body {
}
}
.hide-vertical-scrollbar::-webkit-scrollbar {
width: 0 !important;
}
.hide-horizontal-scrollbar::-webkit-scrollbar {
height: 0 !important;
}
.hide-both-scrollbars::-webkit-scrollbar {
height: 0 !important;
width: 0 !important;
}
/* highlight class */
@utility highlight {
border: 1px solid var(--border-color-accent-strong) !important;

View File

@@ -13,6 +13,7 @@
"./postcss.config.js": "./postcss.config.js"
},
"dependencies": {
"@makeplane/propel": "0.2.0",
"@tailwindcss/postcss": "catalog:",
"postcss": "catalog:"
},

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,7 @@ export function ScrollArea(props: TScrollAreaProps) {
>
<RadixScrollArea.Thumb
className={cn(
"relative flex-1 rounded-[10px] bg-scrollbar-thumb group-hover:bg-scrollbar-thumb-surface-hover group-hover/track:bg-scrollbar-thumb-hover group-active/track:bg-scrollbar-thumb-active",
"relative flex-1 rounded-[10px] bg-scrollbar-thumb group-hover:bg-scrollbar-thumb-hover group-hover/track:bg-scrollbar-thumb-hover group-active/track:bg-scrollbar-thumb-active",
thumbSizeStyles[size]
)}
/>
@@ -61,7 +61,7 @@ export function ScrollArea(props: TScrollAreaProps) {
>
<RadixScrollArea.Thumb
className={cn(
"relative flex-1 rounded-[10px] bg-scrollbar-thumb group-hover:bg-scrollbar-thumb-surface-hover group-hover/track:bg-scrollbar-thumb-hover group-active/track:bg-scrollbar-thumb-active",
"relative flex-1 rounded-[10px] bg-scrollbar-thumb group-hover:bg-scrollbar-thumb-hover group-hover/track:bg-scrollbar-thumb-hover group-active/track:bg-scrollbar-thumb-active",
thumbSizeStyles[size]
)}
/>

View File

@@ -10,12 +10,19 @@
*/
/**
* Alpha mapping for 14-shade palette system
* Alpha mapping for 14-shade palette system.
*
* Must mirror the --alpha-white-* / --alpha-black-* ladder in
* @makeplane/propel (styles/variables.css), which is the source of truth for
* the default themes. These values are only applied for custom themes, so any
* drift shows up as custom themes rendering differently from the default one —
* silently, with no build error. Rungs 100-300 are deliberately much lighter
* than the linear 0.05 step the rest of the scale follows.
*/
export const ALPHA_MAPPING = {
100: 0.05,
200: 0.1,
300: 0.15,
100: 0.04,
200: 0.06,
300: 0.08,
400: 0.2,
500: 0.3,
600: 0.4,

142
pnpm-lock.yaml generated
View File

@@ -1711,6 +1711,9 @@ importers:
packages/tailwind-config:
dependencies:
'@makeplane/propel':
specifier: 0.2.0
version: 0.2.0(@date-fns/tz@1.4.1)(@types/react@18.3.11)(date-fns@4.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@4.1.17)
'@tailwindcss/postcss':
specifier: 'catalog:'
version: 4.1.17
@@ -2237,6 +2240,33 @@ packages:
'@types/react':
optional: true
'@base-ui/react@1.7.0':
resolution: {integrity: sha512-j+8QjX44C32jrXD/qyEAGpFr70FRpGL2CY61mQd9nBPWN737CK0xxD1ceJ055rW4RtdvFDT1e7otzdlfxvsYug==}
engines: {node: '>=14.0.0'}
peerDependencies:
'@date-fns/tz': ^1.2.0
'@types/react': ^17 || ^18 || ^19
date-fns: ^4.0.0
react: ^17 || ^18 || ^19
react-dom: ^17 || ^18 || ^19
peerDependenciesMeta:
'@date-fns/tz':
optional: true
'@types/react':
optional: true
date-fns:
optional: true
'@base-ui/utils@0.3.2':
resolution: {integrity: sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ==}
peerDependencies:
'@types/react': ^17 || ^18 || ^19
react: ^17 || ^18 || ^19
react-dom: ^17 || ^18 || ^19
peerDependenciesMeta:
'@types/react':
optional: true
'@bcoe/v8-coverage@1.0.2':
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
@@ -2586,15 +2616,27 @@ packages:
'@floating-ui/core@1.7.3':
resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==}
'@floating-ui/core@1.8.0':
resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==}
'@floating-ui/dom@1.7.4':
resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==}
'@floating-ui/dom@1.8.0':
resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==}
'@floating-ui/react-dom@2.1.6':
resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==}
peerDependencies:
react: '>=16.8.0'
react-dom: '>=16.8.0'
'@floating-ui/react-dom@2.1.9':
resolution: {integrity: sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==}
peerDependencies:
react: '>=16.8.0'
react-dom: '>=16.8.0'
'@floating-ui/react@0.26.28':
resolution: {integrity: sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==}
peerDependencies:
@@ -2604,6 +2646,9 @@ packages:
'@floating-ui/utils@0.2.10':
resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
'@floating-ui/utils@0.2.12':
resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==}
'@fontsource-variable/inter@5.2.8':
resolution: {integrity: sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==}
@@ -2924,6 +2969,14 @@ packages:
peerDependencies:
'@types/react': 17 || 18 || 19
'@makeplane/propel@0.2.0':
resolution: {integrity: sha512-a4gd9m9gTMbc2NOrpb1jrSkM/OtocVBTf2bmnaAdU8K8Xw3OoTgvMLM3nRtfUbSFNLl1OjG7SCXeg2x/7lYvSA==}
engines: {node: ^20.19.0 || >=22.12.0}
peerDependencies:
react: ^18.0.0 || ^19.0.0
react-dom: ^18.0.0 || ^19.0.0
tailwindcss: ^4.0.0
'@mdx-js/react@3.1.0':
resolution: {integrity: sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==}
peerDependencies:
@@ -6010,6 +6063,7 @@ packages:
crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
deprecated: Active development of CryptoJS has been discontinued. This library is no longer maintained.
css-loader@7.1.4:
resolution: {integrity: sha512-vv3J9tlOl04WjiMvHQI/9tmIrCxVrj6PFbHemBB1iihpeRbi/I4h033eoFIhwxBBqLhI0KYFS7yvynBFhIZfTw==}
@@ -7564,6 +7618,11 @@ packages:
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
lucide-react@1.33.0:
resolution: {integrity: sha512-MTRwMy0ZlL8Ur/vOAiJ9XGHE+kFPC7brq6MxAm0GiGXEBj0qy0jA/pG4N675oSzciO/UCdX8T+5yUQdmDeTLxg==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
lz-string@1.5.0:
resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
hasBin: true
@@ -8524,6 +8583,16 @@ packages:
peerDependencies:
react: '*'
react-day-picker@10.0.1:
resolution: {integrity: sha512-eNh6BlwcYInWaJtRv18mXQ06Ys/H6rdTZAnTaSdOYJuTpwP1JMCHNd1FDRadA+gbeinq+psdULN5Xnowy9mV8w==}
engines: {node: '>=18'}
peerDependencies:
'@types/react': '>=16.8.0'
react: '>=16.8.0'
peerDependenciesMeta:
'@types/react':
optional: true
react-day-picker@9.5.0:
resolution: {integrity: sha512-WmJnPFVLnKh5Qscm7wavMNg86rqPverSWjx+zgK8/ZmGRSQ8c8OoqW10RI+AzAfT2atIxImpCUU2R9Z7Xb2SUA==}
engines: {node: '>=18'}
@@ -8794,6 +8863,9 @@ packages:
reselect@5.1.1:
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
reselect@5.3.0:
resolution: {integrity: sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg==}
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -10260,6 +10332,31 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.11
'@base-ui/react@1.7.0(@date-fns/tz@1.4.1)(@types/react@18.3.11)(date-fns@4.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@babel/runtime': 7.29.7
'@base-ui/utils': 0.3.2(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@floating-ui/react-dom': 2.1.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@floating-ui/utils': 0.2.12
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
use-sync-external-store: 1.6.0(react@18.3.1)
optionalDependencies:
'@date-fns/tz': 1.4.1
'@types/react': 18.3.11
date-fns: 4.1.0
'@base-ui/utils@0.3.2(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@babel/runtime': 7.29.7
'@floating-ui/utils': 0.2.12
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
reselect: 5.3.0
use-sync-external-store: 1.6.0(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.11
'@bcoe/v8-coverage@1.0.2': {}
'@blueprintjs/colors@4.2.1':
@@ -10582,17 +10679,32 @@ snapshots:
dependencies:
'@floating-ui/utils': 0.2.10
'@floating-ui/core@1.8.0':
dependencies:
'@floating-ui/utils': 0.2.12
'@floating-ui/dom@1.7.4':
dependencies:
'@floating-ui/core': 1.7.3
'@floating-ui/utils': 0.2.10
'@floating-ui/dom@1.8.0':
dependencies:
'@floating-ui/core': 1.8.0
'@floating-ui/utils': 0.2.12
'@floating-ui/react-dom@2.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@floating-ui/dom': 1.7.4
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
'@floating-ui/react-dom@2.1.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@floating-ui/dom': 1.8.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
'@floating-ui/react@0.26.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@floating-ui/react-dom': 2.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -10603,6 +10715,8 @@ snapshots:
'@floating-ui/utils@0.2.10': {}
'@floating-ui/utils@0.2.12': {}
'@fontsource-variable/inter@5.2.8': {}
'@fontsource/ibm-plex-mono@5.2.7': {}
@@ -10907,6 +11021,20 @@ snapshots:
dependencies:
'@types/react': 18.3.11
'@makeplane/propel@0.2.0(@date-fns/tz@1.4.1)(@types/react@18.3.11)(date-fns@4.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@4.1.17)':
dependencies:
'@base-ui/react': 1.7.0(@date-fns/tz@1.4.1)(@types/react@18.3.11)(date-fns@4.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
class-variance-authority: 0.7.1
lucide-react: 1.33.0(react@18.3.1)
react: 18.3.1
react-day-picker: 10.0.1(@types/react@18.3.11)(react@18.3.1)
react-dom: 18.3.1(react@18.3.1)
tailwindcss: 4.1.17
transitivePeerDependencies:
- '@date-fns/tz'
- '@types/react'
- date-fns
'@mdx-js/react@3.1.0(@types/react@18.3.11)(react@18.3.1)':
dependencies:
'@types/mdx': 2.0.13
@@ -15293,6 +15421,10 @@ snapshots:
dependencies:
react: 18.3.1
lucide-react@1.33.0(react@18.3.1):
dependencies:
react: 18.3.1
lz-string@1.5.0: {}
magic-string@0.30.21:
@@ -16614,6 +16746,14 @@ snapshots:
reactcss: 1.2.3(react@18.3.1)
tinycolor2: 1.6.0
react-day-picker@10.0.1(@types/react@18.3.11)(react@18.3.1):
dependencies:
'@date-fns/tz': 1.4.1
date-fns: 4.1.0
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.11
react-day-picker@9.5.0(react@18.3.1):
dependencies:
'@date-fns/tz': 1.4.1
@@ -17012,6 +17152,8 @@ snapshots:
reselect@5.1.1: {}
reselect@5.3.0: {}
resolve-from@4.0.0: {}
resolve-pkg-maps@1.0.0: {}