Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface ColorSelectorProps {
selectedColor?: string | null;
onSelectColor: (color: string) => void;
variant?: ColorSelectorVariant;
includeDefault?: boolean;
className?: string;
}

Expand Down Expand Up @@ -43,14 +44,18 @@ export function ColorSelector({
selectedColor,
onSelectColor,
variant = "inline",
includeDefault = false,
className,
}: ColorSelectorProps) {
const selectedValue = selectedColor ?? PROJECT_COLOR_DEFAULT;
const colorOptions = includeDefault
? [{ name: "Default", value: PROJECT_COLOR_DEFAULT }, ...PROJECT_COLORS]
: PROJECT_COLORS;

if (variant === "menu") {
return (
<>
{PROJECT_COLORS.map((color) => {
{colorOptions.map((color) => {
const isSelected = selectedValue === color.value;

return (
Expand All @@ -73,7 +78,7 @@ export function ColorSelector({

return (
<div className={cn("flex flex-wrap items-center gap-2", className)}>
{PROJECT_COLORS.map((color) => {
{colorOptions.map((color) => {
const isSelected = selectedValue === color.value;

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ export function DashboardSidebarProjectSection({
handleNewWorkspace,
handleOpenInFinder,
handleOpenSettings,
handleSetColor,
isRenaming,
projectColor,
renameSection,
renameValue,
setRenameValue,
Expand All @@ -63,16 +65,19 @@ export function DashboardSidebarProjectSection({
if (isSidebarCollapsed) {
return (
<DashboardSidebarProjectContextMenu
projectColor={projectColor}
onCreateSection={handleNewSection}
onOpenInFinder={handleOpenInFinder}
onOpenSettings={handleOpenSettings}
onRemoveFromSidebar={confirmRemoveFromSidebar}
onRename={startRename}
onSetColor={handleSetColor}
>
<div className={cn("border-b border-border last:border-b-0")}>
<DashboardSidebarCollapsedProjectContent
projectName={project.name}
iconUrl={project.iconUrl}
projectColor={projectColor}
isCollapsed={project.isCollapsed}
totalWorkspaceCount={totalWorkspaceCount}
workspaces={flattenedCollapsedWorkspaces}
Expand All @@ -88,15 +93,18 @@ export function DashboardSidebarProjectSection({
return (
<div className={cn("border-b border-border last:border-b-0")}>
<DashboardSidebarProjectContextMenu
projectColor={projectColor}
onCreateSection={handleNewSection}
onOpenInFinder={handleOpenInFinder}
onOpenSettings={handleOpenSettings}
onRemoveFromSidebar={confirmRemoveFromSidebar}
onRename={startRename}
onSetColor={handleSetColor}
>
<DashboardSidebarProjectRow
projectName={project.name}
iconUrl={project.iconUrl}
projectColor={projectColor}
totalWorkspaceCount={totalWorkspaceCount}
isCollapsed={project.isCollapsed}
isRenaming={isRenaming}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface DashboardSidebarCollapsedProjectContentProps
extends ComponentPropsWithoutRef<"div"> {
projectName: string;
iconUrl: string | null;
projectColor: string;
isCollapsed: boolean;
totalWorkspaceCount: number;
workspaces: DashboardSidebarWorkspace[];
Expand All @@ -26,6 +27,7 @@ export const DashboardSidebarCollapsedProjectContent = forwardRef<
{
projectName,
iconUrl,
projectColor,
isCollapsed,
totalWorkspaceCount,
workspaces,
Expand Down Expand Up @@ -56,7 +58,11 @@ export const DashboardSidebarCollapsedProjectContent = forwardRef<
"hover:bg-muted/50 transition-colors",
)}
>
<ProjectThumbnail projectName={projectName} iconUrl={iconUrl} />
<ProjectThumbnail
projectName={projectName}
iconUrl={iconUrl}
color={projectColor}
/>
</button>
</TooltipTrigger>
<TooltipContent side="right" className="flex flex-col gap-0.5">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,40 @@ import {
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuTrigger,
} from "@superset/ui/context-menu";
import {
LuFolderOpen,
LuFolderPlus,
LuPalette,
LuPencil,
LuSettings,
LuX,
} from "react-icons/lu";
import { ColorSelector } from "renderer/components/ColorSelector";

interface DashboardSidebarProjectContextMenuProps {
projectColor: string;
onCreateSection: () => void;
onOpenInFinder: () => void;
onOpenSettings: () => void;
onRemoveFromSidebar: () => void;
onRename: () => void;
onSetColor: (color: string) => void;
children: React.ReactNode;
}

export function DashboardSidebarProjectContextMenu({
projectColor,
onCreateSection,
onOpenInFinder,
onOpenSettings,
onRemoveFromSidebar,
onRename,
onSetColor,
children,
}: DashboardSidebarProjectContextMenuProps) {
return (
Expand All @@ -47,6 +56,20 @@ export function DashboardSidebarProjectContextMenu({
<LuSettings className="size-4 mr-2" />
Project Settings
</ContextMenuItem>
<ContextMenuSub>
<ContextMenuSubTrigger>
<LuPalette className="size-4 mr-2" />
Set Color
</ContextMenuSubTrigger>
<ContextMenuSubContent className="w-40 max-h-80 overflow-y-auto">
<ColorSelector
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Resolved
variant="menu"
includeDefault
selectedColor={projectColor}
onSelectColor={onSetColor}
/>
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuItem onSelect={onCreateSection}>
<LuFolderPlus className="size-4 mr-2" />
New group
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface DashboardSidebarProjectRowProps
extends ComponentPropsWithoutRef<"div"> {
projectName: string;
iconUrl: string | null;
projectColor: string;
totalWorkspaceCount: number;
isCollapsed: boolean;
isRenaming: boolean;
Expand All @@ -29,6 +30,7 @@ export const DashboardSidebarProjectRow = forwardRef<
{
projectName,
iconUrl,
projectColor,
totalWorkspaceCount,
isCollapsed,
isRenaming,
Expand Down Expand Up @@ -74,6 +76,7 @@ export const DashboardSidebarProjectRow = forwardRef<
<ProjectThumbnail
projectName={projectName}
iconUrl={iconUrl}
color={projectColor}
className="size-4 group-hover:hidden"
/>
<HiChevronRight
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { useDashboardSidebarSectionRename } from "renderer/routes/_authenticated
import { useDashboardSidebarState } from "renderer/routes/_authenticated/hooks/useDashboardSidebarState";
import { useOptimisticCollectionActions } from "renderer/routes/_authenticated/hooks/useOptimisticCollectionActions";
import { useOpenNewWorkspaceModal } from "renderer/stores/new-workspace-modal";
import { useV2ProjectLocalMetaStore } from "renderer/stores/v2-project-local-meta";
import { PROJECT_COLOR_DEFAULT } from "shared/constants/project-colors";
import type { DashboardSidebarProject } from "../../../../types";

interface UseDashboardSidebarProjectSectionActionsOptions {
Expand All @@ -19,6 +21,12 @@ export function useDashboardSidebarProjectSectionActions({
const navigate = useNavigate();
const { v2Projects: projectActions } = useOptimisticCollectionActions();
const { requestSectionRename } = useDashboardSidebarSectionRename();
const projectColor = useV2ProjectLocalMetaStore(
(state) => state.projects[project.id]?.color ?? PROJECT_COLOR_DEFAULT,
);
const setProjectColor = useV2ProjectLocalMetaStore(
(state) => state.setProjectColor,
);
const {
createSection,
deleteSection,
Expand Down Expand Up @@ -48,6 +56,10 @@ export function useDashboardSidebarProjectSectionActions({
projectActions.renameProject(project.id, trimmed);
};

const handleSetColor = (color: string) => {
setProjectColor(project.id, color);
};
Comment thread
AviPeltz marked this conversation as resolved.
Resolved

const handleOpenInFinder = () => {
toast.info("Open in Finder is coming soon");
};
Expand Down Expand Up @@ -95,7 +107,9 @@ export function useDashboardSidebarProjectSectionActions({
handleNewWorkspace,
handleOpenInFinder,
handleOpenSettings,
handleSetColor,
isRenaming,
projectColor,
renameSection,
renameValue,
setRenameValue,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
import { cn } from "@superset/ui/utils";
import { useState } from "react";
import {
hexToRgba,
isCustomProjectColor,
} from "shared/constants/project-colors";

interface ProjectThumbnailProps {
projectName: string;
iconUrl?: string | null;
color?: string | null;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null

className?: string;
}

export function ProjectThumbnail({
projectName,
iconUrl,
color,
className,
}: ProjectThumbnailProps) {
const [failedUrl, setFailedUrl] = useState<string | null>(null);

const firstLetter = projectName.charAt(0).toUpperCase();
const hasCustomColor = isCustomProjectColor(color);
const customBorderStyle = hasCustomColor
? { borderColor: hexToRgba(color, 0.6) }
: undefined;

if (iconUrl && failedUrl !== iconUrl) {
return (
<div
className={cn(
"relative size-6 rounded-sm overflow-hidden flex-shrink-0 bg-muted border border-foreground/10",
"relative size-6 rounded-sm overflow-hidden flex-shrink-0 bg-muted border",
hasCustomColor ? undefined : "border-foreground/10",
className,
)}
style={customBorderStyle}
>
<img
src={iconUrl}
Expand All @@ -34,13 +46,25 @@ export function ProjectThumbnail({
);
}

const fallbackStyle = hasCustomColor
? {
borderColor: hexToRgba(color, 0.6),
backgroundColor: hexToRgba(color, 0.15),
color,
}
: undefined;

return (
<div
className={cn(
"size-6 rounded-sm flex items-center justify-center flex-shrink-0",
"text-xs font-medium bg-muted text-muted-foreground border border-foreground/10",
"text-xs font-medium border",
hasCustomColor
? undefined
: "bg-muted text-muted-foreground border-foreground/10",
className,
)}
style={fallbackStyle}
>
{firstLetter}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { cn } from "@superset/ui/utils";
import { useState } from "react";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { PROJECT_COLOR_DEFAULT } from "shared/constants/project-colors";
import {
hexToRgba,
isCustomProjectColor,
PROJECT_COLOR_DEFAULT,
} from "shared/constants/project-colors";

interface ProjectThumbnailProps {
projectId: string;
Expand All @@ -17,23 +21,6 @@ function getGitHubAvatarUrl(owner: string): string {
return `https://github.com/${owner}.png?size=64`;
}

/**
* Converts a hex color to rgba with the specified alpha.
*/
function hexToRgba(hex: string, alpha: number): string {
const r = Number.parseInt(hex.slice(1, 3), 16);
const g = Number.parseInt(hex.slice(3, 5), 16);
const b = Number.parseInt(hex.slice(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}

/**
* Checks if a color value is a custom hex color (not the "default" value).
*/
function isCustomColor(color: string): boolean {
return color !== PROJECT_COLOR_DEFAULT && color.startsWith("#");
}

/**
* Determines whether the GitHub avatar should be displayed.
* Exported for unit testing.
Expand Down Expand Up @@ -72,7 +59,7 @@ export function ProjectThumbnail({

const owner = avatarData?.owner ?? githubOwner;
const firstLetter = projectName.charAt(0).toUpperCase();
const hasCustomColor = isCustomColor(projectColor);
const hasCustomColor = isCustomProjectColor(projectColor);
const shouldUseTransparentIconFrame = projectColor === PROJECT_COLOR_DEFAULT;

// Border: gray by default, custom color with slight transparency when set
Expand Down
Loading
Loading