mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-12 22:56:58 +01:00
PAP-70: project icon infra + ProjectTile renderer + picker (PAP-68 part 3)
Adds the project icon system mirroring the agent icon pattern:
- shared: PROJECT_ICON_NAMES + ProjectIconName (default "folder", curated
Lucide set), exported from index; tighten project validator icon field
from loose string to z.enum(PROJECT_ICON_NAMES).
- ui: project-icons.ts (PROJECT_ICONS map + getProjectIcon defaulting to
folder) and ProjectIconPicker (Popover + search + grid), mirroring the
agent equivalents.
- ProjectTile gains an optional `icon` prop, rendering getProjectIcon(icon)
instead of a hard-coded Folder (default unchanged). Color behavior intact.
- Pass icon={project.icon ?? null} at all three tile sites: Projects list,
SidebarProjects, and the detail header (threaded through ColorPicker).
- Tests: ProjectTile renders chosen icon / falls back to folder for unknown.
- Backfill required Project.icon on test/storybook fixtures left un-updated
by part 1, restoring a green UI typecheck.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
744f9f7428
commit
ee196badee
22 files changed
+266
-16
No files matched your search
@@ -124,6 +124,56 @@ export const AGENT_ICON_NAMES = [
|
||||
] as const;
|
||||
export type AgentIconName = (typeof AGENT_ICON_NAMES)[number];
|
||||
|
||||
/**
|
||||
* Curated Lucide icon set for projects (PAP-68 part 3).
|
||||
*
|
||||
* The first entry, `"folder"`, is the default for any project without an
|
||||
* explicit icon. The remaining entries reuse much of the agent icon set plus a
|
||||
* handful of folder/structure icons that read well at small tile sizes.
|
||||
*/
|
||||
export const PROJECT_ICON_NAMES = [
|
||||
"folder",
|
||||
"rocket",
|
||||
"code",
|
||||
"terminal",
|
||||
"database",
|
||||
"globe",
|
||||
"package",
|
||||
"boxes",
|
||||
"box",
|
||||
"layers",
|
||||
"briefcase",
|
||||
"compass",
|
||||
"target",
|
||||
"flame",
|
||||
"zap",
|
||||
"star",
|
||||
"bug",
|
||||
"wrench",
|
||||
"hammer",
|
||||
"lightbulb",
|
||||
"sparkles",
|
||||
"shield",
|
||||
"lock",
|
||||
"search",
|
||||
"cog",
|
||||
"brain",
|
||||
"cpu",
|
||||
"git-branch",
|
||||
"file-code",
|
||||
"puzzle",
|
||||
"gem",
|
||||
"atom",
|
||||
"heart",
|
||||
"mail",
|
||||
"message-square",
|
||||
"crown",
|
||||
"radar",
|
||||
"telescope",
|
||||
"hexagon",
|
||||
] as const;
|
||||
export type ProjectIconName = (typeof PROJECT_ICON_NAMES)[number];
|
||||
|
||||
export const ISSUE_STATUSES = [
|
||||
"backlog",
|
||||
"todo",
|
||||
|
||||
@@ -41,6 +41,7 @@ export {
|
||||
WORKSPACE_BRANCH_ROUTINE_VARIABLE,
|
||||
MODEL_PROFILE_KEYS,
|
||||
AGENT_ICON_NAMES,
|
||||
PROJECT_ICON_NAMES,
|
||||
ISSUE_STATUSES,
|
||||
INBOX_MINE_ISSUE_STATUSES,
|
||||
INBOX_MINE_ISSUE_STATUS_FILTER,
|
||||
@@ -169,6 +170,7 @@ export {
|
||||
type AgentRole,
|
||||
type ModelProfileKey,
|
||||
type AgentIconName,
|
||||
type ProjectIconName,
|
||||
type IssueStatus,
|
||||
type IssuePriority,
|
||||
type IssueWorkMode,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { z } from "zod";
|
||||
import { PROJECT_STATUSES } from "../constants.js";
|
||||
import { PROJECT_STATUSES, PROJECT_ICON_NAMES } from "../constants.js";
|
||||
import { envConfigSchema } from "./secret.js";
|
||||
import { trustAuthorizationPolicySchema } from "./trust-policy.js";
|
||||
|
||||
@@ -107,9 +107,7 @@ const projectFields = {
|
||||
leadAgentId: z.string().uuid().optional().nullable(),
|
||||
targetDate: z.string().optional().nullable(),
|
||||
color: z.string().optional().nullable(),
|
||||
// TODO(PAP-68 part 3): tighten to `z.enum(PROJECT_ICON_NAMES)` once the icon
|
||||
// name enum lands. Loosely typed as a string until then.
|
||||
icon: z.string().optional().nullable(),
|
||||
icon: z.enum(PROJECT_ICON_NAMES).optional().nullable(),
|
||||
env: envConfigSchema.optional().nullable(),
|
||||
executionWorkspacePolicy: projectExecutionWorkspacePolicySchema.optional().nullable(),
|
||||
archivedAt: z.string().datetime().optional().nullable(),
|
||||
|
||||
Reference in new issue
Block a user