[WEB-5614] chore: platform design token enhancements (#8373)

This commit is contained in:
Anmol Singh Bhatia
2025-12-18 16:45:04 +05:30
committed by GitHub
parent 78f4a7294b
commit 67416935b4
20 changed files with 61 additions and 62 deletions

View File

@@ -102,7 +102,7 @@ export const IssuesHeader = observer(function IssuesHeader() {
)}
</Header.LeftItem>
<Header.RightItem>
<div className="hidden gap-3 md:flex">
<div className="hidden gap-2 md:flex">
<HeaderFilters
projectId={projectId}
currentProjectDetails={currentProjectDetails}

View File

@@ -40,7 +40,7 @@ export const TopNavigationRoot = observer(function TopNavigationRoot() {
return (
<div
className={cn("flex items-center min-h-11 w-full px-3.5 bg-canvas z-[27] transition-all duration-300", {
className={cn("flex items-center min-h-10 w-full px-3.5 bg-canvas z-[27] transition-all duration-300", {
"px-2": !showLabel,
})}
>

View File

@@ -19,7 +19,7 @@ const IconWrapper = React.memo(function IconWrapper({ icon }: { icon: React.Reac
IconWrapper.displayName = "IconWrapper";
const LabelWrapper = React.memo(function LabelWrapper({ label }: { label: React.ReactNode }) {
return <div className="relative line-clamp-1 block max-w-[150px] overflow-hidden truncate">{label}</div>;
return <div className="relative line-clamp-1 block max-w-[150px] overflow-hidden truncate text-primary">{label}</div>;
});
LabelWrapper.displayName = "LabelWrapper";

View File

@@ -86,7 +86,7 @@ export const DashboardWidgets = observer(function DashboardWidgets() {
{!isWikiApp && <NoProjectsEmptyState />}
{isAnyWidgetEnabled ? (
<div className="flex flex-col divide-y-[1px] divide-subtle">
<div className="flex flex-col">
{orderedWidgets.map((key) => {
const WidgetComponent = HOME_WIDGETS_LIST[key]?.component;
const isEnabled = widgetsMap[key]?.is_enabled;

View File

@@ -4,7 +4,7 @@ import { EmptyStateCompact } from "@plane/propel/empty-state";
export function LinksEmptyState() {
const { t } = useTranslation();
return (
<div className="flex items-center justify-center py-10 bg-layer-1 w-full">
<div className="flex items-center justify-center py-10 bg-layer-1 w-full rounded-lg">
<EmptyStateCompact
assetKey="link"
assetClassName="w-20 h-20"

View File

@@ -3,12 +3,12 @@ import React from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { useParams } from "next/navigation";
import { Check, Hotel, Users } from "lucide-react";
import { Check, Hotel } from "lucide-react";
// plane ui
import { EUserPermissions, EUserPermissionsLevel, PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
import { useLocalStorage } from "@plane/hooks";
import { useTranslation } from "@plane/i18n";
import { ProjectIcon, CloseIcon } from "@plane/propel/icons";
import { MembersPropertyIcon, ProjectIcon, CloseIcon } from "@plane/propel/icons";
import { cn, getFileURL } from "@plane/utils";
// helpers
// hooks
@@ -66,7 +66,7 @@ export const NoProjectsEmptyState = observer(function NoProjectsEmptyState() {
id: "invite-team",
title: "home.empty.invite_team.title",
description: "home.empty.invite_team.description",
icon: <Users className="size-4" />,
icon: <MembersPropertyIcon className="size-4" />,
flag: "visited_members",
cta: {
text: "home.empty.invite_team.cta",
@@ -103,7 +103,7 @@ export const NoProjectsEmptyState = observer(function NoProjectsEmptyState() {
</Link>
) : (
<Link href={`/${workspaceSlug}/profile/${currentUser?.id}`}>
<span className="relative flex size-4 items-center justify-center rounded-full bg-gray-700 p-4 capitalize text-on-color text-13">
<span className="relative flex size-4 items-center justify-center rounded-full bg-[#028375] p-4 capitalize text-on-color text-13">
{(currentUser?.email ?? currentUser?.display_name ?? "?")[0]}
</span>
</Link>
@@ -150,7 +150,7 @@ export const NoProjectsEmptyState = observer(function NoProjectsEmptyState() {
{EMPTY_STATE_DATA.map((item) => {
const isStateComplete = isComplete(item.flag);
return (
<div key={item.id} className="flex flex-col p-4 bg-surface-1 rounded-xl border border-subtle/40">
<div key={item.id} className="flex flex-col p-4 bg-layer-2 rounded-xl border border-subtle">
<div
className={cn("grid place-items-center bg-surface-2 rounded-full size-9 mb-3 text-placeholder", {
"text-accent-primary bg-accent-primary/10": !isStateComplete,
@@ -187,7 +187,7 @@ export const NoProjectsEmptyState = observer(function NoProjectsEmptyState() {
) : (
<button
type="button"
className="text-accent-primary hover:text-accent-secondary text-13 font-medium"
className="text-accent-primary hover:text-accent-secondary text-13 font-medium text-left"
onClick={item.cta.onClick}
>
{t(item.cta.text)}

View File

@@ -33,7 +33,7 @@ export function RecentsEmptyState({ type }: { type: string }) {
const { assetKey, text } = getDisplayContent(type);
return (
<div className="flex items-center justify-center py-10 bg-layer-1 w-full">
<div className="flex items-center justify-center py-10 bg-layer-1 w-full rounded-lg">
<EmptyStateCompact assetKey={assetKey} assetClassName="size-20" title={t(text)} />
</div>
);

View File

@@ -4,7 +4,7 @@ import { EmptyStateCompact } from "@plane/propel/empty-state";
export function StickiesEmptyState() {
const { t } = useTranslation();
return (
<div className="flex items-center justify-center py-10 bg-layer-1 w-full">
<div className="flex items-center justify-center py-10 bg-layer-1 w-full rounded-lg">
<EmptyStateCompact assetKey="note" assetClassName="size-20" title={t("stickies.empty_state.simple")} />
</div>
);

View File

@@ -1,11 +1,11 @@
"use client";
import { observer } from "mobx-react";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { TContextMenuItem } from "@plane/ui";
import { CustomMenu } from "@plane/ui";
import { copyUrlToClipboard, cn } from "@plane/utils";
import { useLayoutMenuItems } from "@/components/common/quick-actions-helper";
import { Ellipsis, MoreHorizontal } from "lucide-react";
import { IconButton } from "@plane/propel/icon-button";
type Props = {
workspaceSlug: string;
@@ -13,7 +13,7 @@ type Props = {
storeType: "PROJECT" | "EPIC";
};
export const LayoutQuickActions: React.FC<Props> = observer((props) => {
export const LayoutQuickActions = observer(function LayoutQuickActions(props: Props) {
const { workspaceSlug, projectId, storeType } = props;
const layoutLink = `${workspaceSlug}/projects/${projectId}/${storeType === "EPIC" ? "epics" : "issues"}`;
@@ -49,6 +49,7 @@ export const LayoutQuickActions: React.FC<Props> = observer((props) => {
closeOnSelect
maxHeight="lg"
className="flex-shrink-0 flex items-center justify-center size-[26px] rounded"
customButton={<IconButton size="lg" variant="tertiary" icon={Ellipsis} />}
>
{MENU_ITEMS.map((item) => {
if (item.shouldRender === false) return null;

View File

@@ -220,7 +220,7 @@ export const IssuePeekOverviewHeader = observer(function IssuePeekOverviewHeader
</div>
<div className="flex items-center gap-x-4">
<NameDescriptionUpdateStatus isSubmitting={isSubmitting} />
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
{currentUser && !isArchived && (
<IssueSubscription workspaceSlug={workspaceSlug} projectId={projectId} issueId={issueId} />
)}

View File

@@ -35,7 +35,6 @@ export const WorkspaceDraftEmptyState = observer(function WorkspaceDraftEmptySta
title={t("workspace_empty_state.drafts.title")}
description={t("workspace_empty_state.drafts.description")}
assetKey="draft"
assetClassName="size-20"
actions={[
{
label: t("workspace_empty_state.drafts.cta_primary"),

View File

@@ -176,7 +176,7 @@ export const CustomizeNavigationDialog = observer(function CustomizeNavigationDi
<ModalCore isOpen={isOpen} handleClose={onClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<div className="flex flex-col max-h-[90vh] bg-surface-1 rounded-lg">
{/* Header */}
<div className="flex justify-between px-6 py-4">
<div className="flex justify-between px-6 pt-4">
<div>
<h2 className="text-18 font-semibold text-primary">{t("customize_navigation")}</h2>
<p className="mt-1 text-13 text-tertiary">
@@ -213,7 +213,7 @@ export const CustomizeNavigationDialog = observer(function CustomizeNavigationDi
/>
<div className="flex items-center gap-2 flex-1">
{getSidebarNavigationItemIcon(item.key)}
<label className="text-13 text-secondary flex-1 cursor-pointer">
<label className="text-13 text-primary flex-1 cursor-pointer">
{t(item.labelTranslationKey)}
</label>
</div>
@@ -244,7 +244,7 @@ export const CustomizeNavigationDialog = observer(function CustomizeNavigationDi
/>
<div className="flex items-center gap-2 flex-1">
{icon}
<span className="text-13 text-secondary">{t(item.labelTranslationKey)}</span>
<span className="text-13 text-primary">{t(item.labelTranslationKey)}</span>
</div>
</div>
);
@@ -271,8 +271,8 @@ export const CustomizeNavigationDialog = observer(function CustomizeNavigationDi
className="size-4 text-accent-primary focus:ring-accent-strong mt-1"
/>
<div className="flex-1">
<div className="text-13 text-secondary">{t("accordion_navigation_control")}</div>
<div className="text-11 text-tertiary">
<div className="text-13 text-primary">{t("accordion_navigation_control")}</div>
<div className="text-11 text-secondary">
Feature tabs will appear as nested items under project and acts as accordion.
</div>
</div>
@@ -288,8 +288,8 @@ export const CustomizeNavigationDialog = observer(function CustomizeNavigationDi
className="size-4 text-accent-primary focus:ring-accent-strong mt-1"
/>
<div className="flex-1">
<div className="text-13 text-secondary">{t("horizontal_navigation_bar")}</div>
<div className="text-11 text-tertiary">
<div className="text-13 text-primary">{t("horizontal_navigation_bar")}</div>
<div className="text-11 text-secondary">
Feature tabs will appear as horizontal tabs inside a project.
</div>
</div>
@@ -297,20 +297,20 @@ export const CustomizeNavigationDialog = observer(function CustomizeNavigationDi
</div>
{/* Limited Projects Checkbox */}
<div className="space-y-2">
<div className="space-y-1">
<label className="flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-surface-2 cursor-pointer">
<Checkbox
checked={projectPreferences.showLimitedProjects}
onChange={(e) => updateShowLimitedProjects(e.target.checked)}
/>
<span className="text-13 text-secondary">{t("show_limited_projects_on_sidebar")}</span>
<span className="text-13 text-primary">{t("show_limited_projects_on_sidebar")}</span>
</label>
{projectPreferences.showLimitedProjects && (
<div className="pl-8">
<div className="flex flex-col gap-1 w-full">
<div className="flex flex-col gap-2 w-full">
<label className="text-11 text-tertiary w-full">{t("enter_number_of_projects")}</label>
<div className="flex flex-col gap-2 w-full pb-1.5">
<label className="text-11 text-secondary w-full">{t("enter_number_of_projects")}</label>
<input
type="number"
min="1"

View File

@@ -13,7 +13,7 @@ export function SidebarNavItem(props: TSidebarNavItem) {
className={cn(
"cursor-pointer relative group w-full flex items-center justify-between gap-1.5 rounded-md px-2 py-1 outline-none",
{
"text-secondary !bg-layer-transparent-active": isActive,
"text-primary !bg-layer-transparent-active": isActive,
"text-secondary hover:bg-layer-transparent-hover active:bg-layer-transparent-active": !isActive,
},
className

View File

@@ -3,6 +3,7 @@ import { PanelLeft } from "lucide-react";
// hooks
import { useAppTheme } from "@/hooks/store/use-app-theme";
import { isSidebarToggleVisible } from "@/plane-web/components/desktop";
import { IconButton } from "@plane/propel/icon-button";
export const AppSidebarToggleButton = observer(function AppSidebarToggleButton() {
// store hooks
@@ -10,14 +11,14 @@ export const AppSidebarToggleButton = observer(function AppSidebarToggleButton()
if (!isSidebarToggleVisible()) return null;
return (
<button
className="flex items-center justify-center size-6 rounded-md text-secondary hover:text-accent-primary hover:bg-surface-2"
<IconButton
size="base"
variant="ghost"
icon={PanelLeft}
onClick={() => {
if (sidebarPeek) toggleSidebarPeek(false);
toggleSidebar();
}}
>
<PanelLeft className="size-4" />
</button>
/>
);
});

View File

@@ -12,6 +12,7 @@ import useSize from "@/hooks/use-window-size";
// plane web components
import { WorkspaceEditionBadge } from "@/plane-web/components/workspace/edition-badge";
import { AppSidebarToggleButton } from "./sidebar-toggle-button";
import { IconButton } from "@plane/propel/icon-button";
type TSidebarWrapperProps = {
title: string;
@@ -51,13 +52,12 @@ export const SidebarWrapper = observer(function SidebarWrapper(props: TSidebarWr
<span className="text-16 text-primary font-medium pt-1">{title}</span>
{title === "Projects" && (
<div className="flex items-center gap-2">
<button
type="button"
className="flex items-center justify-center size-6 rounded-md text-secondary hover:text-accent-primary hover:bg-surface-2"
<IconButton
size="base"
variant="ghost"
icon={PreferencesIcon}
onClick={() => setIsCustomizeNavDialogOpen(true)}
>
<PreferencesIcon className="size-4" />
</button>
/>
<AppSidebarToggleButton />
</div>
)}

View File

@@ -10,6 +10,7 @@ import { PopoverMenu } from "@plane/ui";
import { usePlatformOS } from "@/hooks/use-platform-os";
// local imports
import { NotificationFilterOptionItem } from "./menu-option-item";
import { IconButton } from "@plane/propel/icon-button";
export const NotificationFilter = observer(function NotificationFilter() {
// hooks
@@ -26,9 +27,7 @@ export const NotificationFilter = observer(function NotificationFilter() {
data={translatedFilterTypeOptions}
button={
<Tooltip tooltipContent={t("notification.options.filters")} isMobile={isMobile} position="bottom">
<div className="flex-shrink-0 w-5 h-5 flex justify-center items-center overflow-hidden cursor-pointer transition-all hover:bg-layer-1 rounded-xs outline-none">
<ListFilter className="h-3 w-3" />
</div>
<IconButton size="base" variant="ghost" icon={ListFilter} />
</Tooltip>
}
keyExtractor={(item: { label: string; value: ENotificationFilterType }) => item.value}

View File

@@ -1,6 +1,6 @@
import type { ReactNode } from "react";
import { observer } from "mobx-react";
import { Check, CheckCircle, Clock } from "lucide-react";
import { Check, CheckCircle, Clock, MoreVertical } from "lucide-react";
// plane imports
import { useTranslation } from "@plane/i18n";
import { ArchiveIcon } from "@plane/propel/icons";
@@ -10,6 +10,7 @@ import { PopoverMenu } from "@plane/ui";
import { useWorkspaceNotifications } from "@/hooks/store/notifications";
// local imports
import { NotificationMenuOptionItem } from "./menu-item";
import { IconButton } from "@plane/propel/icon-button";
export type TPopoverMenuOptions = {
key: string;
@@ -72,7 +73,7 @@ export const NotificationHeaderMenuOption = observer(function NotificationHeader
return (
<PopoverMenu
data={popoverMenuOptions}
buttonClassName="flex-shrink-0 w-5 h-5 flex justify-center items-center overflow-hidden cursor-pointer transition-all hover:bg-layer-1 bg-surface-1 rounded-xs outline-none"
button={<IconButton size="base" variant="ghost" icon={MoreVertical} />}
keyExtractor={(item: TPopoverMenuOptions) => item.key}
panelClassName="p-0 py-2 rounded-md border border-subtle bg-surface-1 space-y-1"
render={(item: TPopoverMenuOptions) => <NotificationMenuOptionItem {...item} />}

View File

@@ -18,6 +18,7 @@ import { usePlatformOS } from "@/hooks/use-platform-os";
// local imports
import { NotificationFilter } from "../../filters/menu";
import { NotificationHeaderMenuOption } from "./menu-option";
import { IconButton } from "@plane/propel/icon-button";
type TNotificationSidebarHeaderOptions = {
workspaceSlug: string;
@@ -55,32 +56,29 @@ export const NotificationSidebarHeaderOptions = observer(function NotificationSi
<div className="relative flex justify-center items-center gap-2 text-body-xs-medium">
{/* mark all notifications as read*/}
<Tooltip tooltipContent={t("notification.options.mark_all_as_read")} isMobile={isMobile} position="bottom">
<div
className="flex-shrink-0 w-5 h-5 flex justify-center items-center overflow-hidden cursor-pointer transition-all hover:bg-layer-1 rounded-xs"
<IconButton
size="base"
variant="ghost"
data-ph-element={NOTIFICATION_TRACKER_ELEMENTS.MARK_ALL_AS_READ_BUTTON}
icon={loader === ENotificationLoader.MARK_ALL_AS_READY ? Spinner : CheckCheck}
onClick={() => {
captureSuccess({
eventName: NOTIFICATION_TRACKER_EVENTS.all_marked_read,
});
handleMarkAllNotificationsAsRead();
}}
>
{loader === ENotificationLoader.MARK_ALL_AS_READY ? (
<Spinner height="14px" width="14px" />
) : (
<CheckCheck className="h-3 w-3" />
)}
</div>
/>
</Tooltip>
{/* refetch current notifications */}
<Tooltip tooltipContent={t("notification.options.refresh")} isMobile={isMobile} position="bottom">
<div
className="flex-shrink-0 w-5 h-5 flex justify-center items-center overflow-hidden cursor-pointer transition-all hover:bg-layer-1 rounded-xs"
<IconButton
size="base"
variant="ghost"
icon={RefreshCw}
className={loader === ENotificationLoader.MUTATION_LOADER ? "animate-spin" : ""}
onClick={refreshNotifications}
>
<RefreshCw className={`h-3 w-3 ${loader === ENotificationLoader.MUTATION_LOADER ? "animate-spin" : ""}`} />
</div>
/>
</Tooltip>
{/* notification filters */}

View File

@@ -27,7 +27,7 @@ export const NotificationSidebarHeader = observer(function NotificationSidebarHe
component={
<BreadcrumbLink
label={t("notification.label")}
icon={<InboxIcon className="h-4 w-4 text-tertiary" />}
icon={<InboxIcon className="h-4 w-4 text-primary" />}
disableTooltip
/>
}