@burdenoff/microfe-vibecontrols 2026.601.20 → 2026.601.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,8 +4,8 @@ import { Edit as n, FileText as r, Globe as i, Lock as a, MoreVertical as o, Pin
4
4
  import { AnimatePresence as f, motion as p } from "framer-motion";
5
5
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
6
6
  //#region src/components/notes/NoteCard.tsx
7
- function g({ note: g, onOpen: _, onEdit: v, onDelete: y, onPin: b, onUnpin: x, onShare: S }) {
8
- let { t: C } = t(), [w, T] = e(!1);
7
+ function g({ note: g, onOpen: _, onEdit: v, onDelete: y, onPin: b, onUnpin: x, onShare: S, onShareAccess: C }) {
8
+ let { t: w } = t(), [T, E] = e(!1);
9
9
  return /* @__PURE__ */ h(p.div, {
10
10
  whileHover: {
11
11
  y: -2,
@@ -62,11 +62,11 @@ function g({ note: g, onOpen: _, onEdit: v, onDelete: y, onPin: b, onUnpin: x, o
62
62
  children: [/* @__PURE__ */ m("button", {
63
63
  type: "button",
64
64
  onClick: (e) => {
65
- e.stopPropagation(), T(!w);
65
+ e.stopPropagation(), E(!T);
66
66
  },
67
67
  className: "p-1 rounded hover:bg-bg-sunken transition-colors",
68
68
  children: /* @__PURE__ */ m(o, { className: "size-4 text-text-secondary" })
69
- }), /* @__PURE__ */ m(f, { children: w && /* @__PURE__ */ h(p.div, {
69
+ }), /* @__PURE__ */ m(f, { children: T && /* @__PURE__ */ h(p.div, {
70
70
  initial: {
71
71
  opacity: 0,
72
72
  scale: .95,
@@ -88,7 +88,7 @@ function g({ note: g, onOpen: _, onEdit: v, onDelete: y, onPin: b, onUnpin: x, o
88
88
  v && /* @__PURE__ */ h(p.button, {
89
89
  whileTap: { scale: .97 },
90
90
  onClick: (e) => {
91
- e.stopPropagation(), v(g), T(!1);
91
+ e.stopPropagation(), v(g), E(!1);
92
92
  },
93
93
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg",
94
94
  children: [/* @__PURE__ */ m(n, { className: "size-4" }), "Edit"]
@@ -96,7 +96,7 @@ function g({ note: g, onOpen: _, onEdit: v, onDelete: y, onPin: b, onUnpin: x, o
96
96
  S && g.visibility === "PRIVATE" && /* @__PURE__ */ h(p.button, {
97
97
  whileTap: { scale: .97 },
98
98
  onClick: (e) => {
99
- e.stopPropagation(), S(g), T(!1);
99
+ e.stopPropagation(), S(g), E(!1);
100
100
  },
101
101
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
102
102
  children: [/* @__PURE__ */ m(l, { className: "size-4" }), "Share with workspace"]
@@ -104,15 +104,24 @@ function g({ note: g, onOpen: _, onEdit: v, onDelete: y, onPin: b, onUnpin: x, o
104
104
  S && g.visibility === "WORKSPACE" && /* @__PURE__ */ h(p.button, {
105
105
  whileTap: { scale: .97 },
106
106
  onClick: (e) => {
107
- e.stopPropagation(), S(g), T(!1);
107
+ e.stopPropagation(), S(g), E(!1);
108
108
  },
109
109
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
110
110
  children: [/* @__PURE__ */ m(a, { className: "size-4" }), "Make private"]
111
111
  }),
112
+ C && /* @__PURE__ */ h(p.button, {
113
+ whileTap: { scale: .97 },
114
+ "data-testid": "note-share-access",
115
+ onClick: (e) => {
116
+ e.stopPropagation(), C(g), E(!1);
117
+ },
118
+ className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
119
+ children: [/* @__PURE__ */ m(l, { className: "size-4" }), "Share access…"]
120
+ }),
112
121
  g.isPinned && x && /* @__PURE__ */ h(p.button, {
113
122
  whileTap: { scale: .97 },
114
123
  onClick: (e) => {
115
- e.stopPropagation(), x(g), T(!1);
124
+ e.stopPropagation(), x(g), E(!1);
116
125
  },
117
126
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
118
127
  children: [/* @__PURE__ */ m(c, { className: "size-4" }), "Unpin"]
@@ -120,7 +129,7 @@ function g({ note: g, onOpen: _, onEdit: v, onDelete: y, onPin: b, onUnpin: x, o
120
129
  !g.isPinned && b && /* @__PURE__ */ h(p.button, {
121
130
  whileTap: { scale: .97 },
122
131
  onClick: (e) => {
123
- e.stopPropagation(), b(g), T(!1);
132
+ e.stopPropagation(), b(g), E(!1);
124
133
  },
125
134
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
126
135
  children: [/* @__PURE__ */ m(s, { className: "size-4" }), "Pin"]
@@ -128,7 +137,7 @@ function g({ note: g, onOpen: _, onEdit: v, onDelete: y, onPin: b, onUnpin: x, o
128
137
  y && /* @__PURE__ */ h(p.button, {
129
138
  whileTap: { scale: .97 },
130
139
  onClick: (e) => {
131
- e.stopPropagation(), y(g), T(!1);
140
+ e.stopPropagation(), y(g), E(!1);
132
141
  },
133
142
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-b-lg",
134
143
  children: [/* @__PURE__ */ m(d, { className: "size-4" }), "Delete"]
@@ -1 +1 @@
1
- {"version":3,"file":"NoteCard.js","names":[],"sources":["../../../src/components/notes/NoteCard.tsx"],"sourcesContent":["import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n FileText,\n Pin,\n Tag,\n MoreVertical,\n Edit,\n Trash2,\n PinOff,\n Lock,\n Globe,\n Share2,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport type { Note } from './types';\n\ninterface NoteCardProps {\n note: Note;\n onOpen?: (note: Note) => void;\n onEdit?: (note: Note) => void;\n onDelete?: (note: Note) => void;\n onPin?: (note: Note) => void;\n onUnpin?: (note: Note) => void;\n onShare?: (note: Note) => void;\n}\n\nexport function NoteCard({\n note,\n onOpen,\n onEdit,\n onDelete,\n onPin,\n onUnpin,\n onShare,\n}: NoteCardProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [showMenu, setShowMenu] = useState(false);\n\n const formatDate = (dateStr: string) => {\n return new Date(dateStr).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n });\n };\n\n const getPreview = (content: string) => {\n // Remove markdown headers and get first 100 chars\n const text = content\n .replace(/^#+\\s+/gm, '')\n .replace(/\\n/g, ' ')\n .trim();\n return text.length > 100 ? text.slice(0, 100) + '...' : text;\n };\n\n return (\n <motion.div\n whileHover={{ y: -2, transition: { duration: 0.15, ease: [0.4, 0, 0.2, 1] } }}\n whileTap={{ scale: 0.98 }}\n className=\"bg-bg-surface border border-border-default rounded-lg p-4 hover:border-border-strong hover:shadow-md transition-all cursor-pointer\"\n onClick={() => onOpen?.(note)}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3 min-w-0\">\n <div className=\"flex-shrink-0 size-10 rounded-lg bg-status-warning-bg flex items-center justify-center\">\n <FileText className=\"size-5 text-status-warning-text\" />\n </div>\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-semibold text-text-primary truncate\">{note.title}</h3>\n {note.isPinned && <Pin className=\"size-4 text-status-warning-text flex-shrink-0\" />}\n {note.visibility === 'PRIVATE' ? (\n <span title=\"Private note\">\n <Lock className=\"size-3.5 text-text-muted flex-shrink-0\" />\n </span>\n ) : (\n <span title=\"Workspace note\">\n <Globe className=\"size-3.5 text-text-muted flex-shrink-0\" />\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-secondary\">{formatDate(note.updatedAt)}</p>\n </div>\n </div>\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"size-4 text-text-secondary\" />\n </button>\n <AnimatePresence>\n {showMenu && (\n <motion.div\n initial={{ opacity: 0, scale: 0.95, y: -4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: -4 }}\n transition={{ duration: 0.15 }}\n className=\"absolute right-0 mt-1 w-36 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10\"\n >\n {onEdit && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onEdit(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Edit className=\"size-4\" />\n Edit\n </motion.button>\n )}\n {onShare && note.visibility === 'PRIVATE' && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Share2 className=\"size-4\" />\n Share with workspace\n </motion.button>\n )}\n {onShare && note.visibility === 'WORKSPACE' && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Lock className=\"size-4\" />\n Make private\n </motion.button>\n )}\n {note.isPinned && onUnpin && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onUnpin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <PinOff className=\"size-4\" />\n Unpin\n </motion.button>\n )}\n {!note.isPinned && onPin && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onPin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Pin className=\"size-4\" />\n Pin\n </motion.button>\n )}\n {onDelete && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onDelete(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-b-lg\"\n >\n <Trash2 className=\"size-4\" />\n Delete\n </motion.button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n </div>\n\n <p className=\"mt-3 text-sm text-text-secondary line-clamp-2\">{getPreview(note.content)}</p>\n\n {/* Render tagAssignments if available, otherwise fall back to legacy string tags */}\n {note.tagAssignments && note.tagAssignments.length > 0 ? (\n <div className=\"mt-3 flex flex-wrap gap-1\">\n {note.tagAssignments.slice(0, 3).map((assignment) => (\n <span\n key={assignment.id}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-action-primary-bg/10 text-action-primary-bg rounded\"\n style={\n assignment.tag?.color\n ? { borderLeft: `3px solid ${assignment.tag.color}` }\n : undefined\n }\n >\n <Tag className=\"size-3\" />\n {assignment.tag?.label ?? assignment.tagId.slice(0, 8)}\n </span>\n ))}\n {note.tagAssignments.length > 3 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tagAssignments.length - 3}\n </span>\n )}\n </div>\n ) : note.tags && note.tags.length > 0 ? (\n <div className=\"mt-3 flex flex-wrap gap-1\">\n {note.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-3\" />\n {tag}\n </span>\n ))}\n {note.tags.length > 3 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tags.length - 3}\n </span>\n )}\n </div>\n ) : null}\n </motion.div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"NoteCard.js","names":[],"sources":["../../../src/components/notes/NoteCard.tsx"],"sourcesContent":["import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n FileText,\n Pin,\n Tag,\n MoreVertical,\n Edit,\n Trash2,\n PinOff,\n Lock,\n Globe,\n Share2,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport type { Note } from './types';\n\ninterface NoteCardProps {\n note: Note;\n onOpen?: (note: Note) => void;\n onEdit?: (note: Note) => void;\n onDelete?: (note: Note) => void;\n onPin?: (note: Note) => void;\n onUnpin?: (note: Note) => void;\n onShare?: (note: Note) => void;\n /**\n * Generic-sharing entry point: opens the full Share dialog (users / link /\n * vibe). Distinct from `onShare`, which only toggles PRIVATE/WORKSPACE\n * visibility. Provided only when the caller has share permission + the\n * `vibecontrols.sharing.note` flag is on.\n */\n onShareAccess?: (note: Note) => void;\n}\n\nexport function NoteCard({\n note,\n onOpen,\n onEdit,\n onDelete,\n onPin,\n onUnpin,\n onShare,\n onShareAccess,\n}: NoteCardProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [showMenu, setShowMenu] = useState(false);\n\n const formatDate = (dateStr: string) => {\n return new Date(dateStr).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n });\n };\n\n const getPreview = (content: string) => {\n // Remove markdown headers and get first 100 chars\n const text = content\n .replace(/^#+\\s+/gm, '')\n .replace(/\\n/g, ' ')\n .trim();\n return text.length > 100 ? text.slice(0, 100) + '...' : text;\n };\n\n return (\n <motion.div\n whileHover={{ y: -2, transition: { duration: 0.15, ease: [0.4, 0, 0.2, 1] } }}\n whileTap={{ scale: 0.98 }}\n className=\"bg-bg-surface border border-border-default rounded-lg p-4 hover:border-border-strong hover:shadow-md transition-all cursor-pointer\"\n onClick={() => onOpen?.(note)}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3 min-w-0\">\n <div className=\"flex-shrink-0 size-10 rounded-lg bg-status-warning-bg flex items-center justify-center\">\n <FileText className=\"size-5 text-status-warning-text\" />\n </div>\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-semibold text-text-primary truncate\">{note.title}</h3>\n {note.isPinned && <Pin className=\"size-4 text-status-warning-text flex-shrink-0\" />}\n {note.visibility === 'PRIVATE' ? (\n <span title=\"Private note\">\n <Lock className=\"size-3.5 text-text-muted flex-shrink-0\" />\n </span>\n ) : (\n <span title=\"Workspace note\">\n <Globe className=\"size-3.5 text-text-muted flex-shrink-0\" />\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-secondary\">{formatDate(note.updatedAt)}</p>\n </div>\n </div>\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"size-4 text-text-secondary\" />\n </button>\n <AnimatePresence>\n {showMenu && (\n <motion.div\n initial={{ opacity: 0, scale: 0.95, y: -4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: -4 }}\n transition={{ duration: 0.15 }}\n className=\"absolute right-0 mt-1 w-36 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10\"\n >\n {onEdit && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onEdit(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Edit className=\"size-4\" />\n Edit\n </motion.button>\n )}\n {onShare && note.visibility === 'PRIVATE' && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Share2 className=\"size-4\" />\n Share with workspace\n </motion.button>\n )}\n {onShare && note.visibility === 'WORKSPACE' && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Lock className=\"size-4\" />\n Make private\n </motion.button>\n )}\n {onShareAccess && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n data-testid=\"note-share-access\"\n onClick={(e) => {\n e.stopPropagation();\n onShareAccess(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Share2 className=\"size-4\" />\n Share access…\n </motion.button>\n )}\n {note.isPinned && onUnpin && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onUnpin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <PinOff className=\"size-4\" />\n Unpin\n </motion.button>\n )}\n {!note.isPinned && onPin && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onPin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Pin className=\"size-4\" />\n Pin\n </motion.button>\n )}\n {onDelete && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onDelete(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-b-lg\"\n >\n <Trash2 className=\"size-4\" />\n Delete\n </motion.button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n </div>\n\n <p className=\"mt-3 text-sm text-text-secondary line-clamp-2\">{getPreview(note.content)}</p>\n\n {/* Render tagAssignments if available, otherwise fall back to legacy string tags */}\n {note.tagAssignments && note.tagAssignments.length > 0 ? (\n <div className=\"mt-3 flex flex-wrap gap-1\">\n {note.tagAssignments.slice(0, 3).map((assignment) => (\n <span\n key={assignment.id}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-action-primary-bg/10 text-action-primary-bg rounded\"\n style={\n assignment.tag?.color\n ? { borderLeft: `3px solid ${assignment.tag.color}` }\n : undefined\n }\n >\n <Tag className=\"size-3\" />\n {assignment.tag?.label ?? assignment.tagId.slice(0, 8)}\n </span>\n ))}\n {note.tagAssignments.length > 3 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tagAssignments.length - 3}\n </span>\n )}\n </div>\n ) : note.tags && note.tags.length > 0 ? (\n <div className=\"mt-3 flex flex-wrap gap-1\">\n {note.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-3\" />\n {tag}\n </span>\n ))}\n {note.tags.length > 3 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tags.length - 3}\n </span>\n )}\n </div>\n ) : null}\n </motion.div>\n );\n}\n"],"mappings":"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"}
@@ -4,8 +4,8 @@ import { useState as n } from "react";
4
4
  import { Edit as r, FileText as i, Globe as a, Lock as o, MoreVertical as s, Pin as c, PinOff as l, Plus as u, Share2 as d, Tag as f, Trash2 as p } from "lucide-react";
5
5
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
6
6
  //#region src/components/notes/NoteList.tsx
7
- function g({ note: e, onOpen: t, onEdit: u, onDelete: g, onPin: _, onUnpin: v, onShare: y }) {
8
- let [b, x] = n(!1);
7
+ function g({ note: e, onOpen: t, onEdit: u, onDelete: g, onPin: _, onUnpin: v, onShare: y, onShareAccess: b }) {
8
+ let [x, S] = n(!1);
9
9
  return /* @__PURE__ */ h("tr", {
10
10
  className: "border-b border-border-subtle hover:bg-bg-sunken/50 cursor-pointer transition-colors",
11
11
  onClick: () => t?.(e),
@@ -90,22 +90,22 @@ function g({ note: e, onOpen: t, onEdit: u, onDelete: g, onPin: _, onUnpin: v, o
90
90
  className: "px-4 py-3",
91
91
  children: /* @__PURE__ */ m("div", {
92
92
  className: "flex items-center gap-1 justify-end",
93
- children: (u || g || _ || v || y) && /* @__PURE__ */ h("div", {
93
+ children: (u || g || _ || v || y || b) && /* @__PURE__ */ h("div", {
94
94
  className: "relative",
95
95
  children: [/* @__PURE__ */ m("button", {
96
96
  type: "button",
97
97
  onClick: (e) => {
98
- e.stopPropagation(), x(!b);
98
+ e.stopPropagation(), S(!x);
99
99
  },
100
100
  className: "p-1.5 rounded hover:bg-bg-sunken transition-colors",
101
101
  children: /* @__PURE__ */ m(s, { className: "size-3.5 text-text-secondary" })
102
- }), b && /* @__PURE__ */ h("div", {
102
+ }), x && /* @__PURE__ */ h("div", {
103
103
  className: "absolute right-0 mt-1 w-44 bg-bg-surface border border-border-default rounded-lg shadow-lg z-50",
104
104
  children: [
105
105
  u && /* @__PURE__ */ h("button", {
106
106
  type: "button",
107
107
  onClick: (t) => {
108
- t.stopPropagation(), u(e), x(!1);
108
+ t.stopPropagation(), u(e), S(!1);
109
109
  },
110
110
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg",
111
111
  children: [/* @__PURE__ */ m(r, { className: "size-4" }), "Edit"]
@@ -113,7 +113,7 @@ function g({ note: e, onOpen: t, onEdit: u, onDelete: g, onPin: _, onUnpin: v, o
113
113
  y && e.visibility === "PRIVATE" && /* @__PURE__ */ h("button", {
114
114
  type: "button",
115
115
  onClick: (t) => {
116
- t.stopPropagation(), y(e), x(!1);
116
+ t.stopPropagation(), y(e), S(!1);
117
117
  },
118
118
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
119
119
  children: [/* @__PURE__ */ m(d, { className: "size-4" }), "Share with workspace"]
@@ -121,15 +121,24 @@ function g({ note: e, onOpen: t, onEdit: u, onDelete: g, onPin: _, onUnpin: v, o
121
121
  y && e.visibility === "WORKSPACE" && /* @__PURE__ */ h("button", {
122
122
  type: "button",
123
123
  onClick: (t) => {
124
- t.stopPropagation(), y(e), x(!1);
124
+ t.stopPropagation(), y(e), S(!1);
125
125
  },
126
126
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
127
127
  children: [/* @__PURE__ */ m(o, { className: "size-4" }), "Make private"]
128
128
  }),
129
+ b && /* @__PURE__ */ h("button", {
130
+ type: "button",
131
+ "data-testid": "note-share-access",
132
+ onClick: (t) => {
133
+ t.stopPropagation(), b(e), S(!1);
134
+ },
135
+ className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
136
+ children: [/* @__PURE__ */ m(d, { className: "size-4" }), "Share access…"]
137
+ }),
129
138
  e.isPinned && v && /* @__PURE__ */ h("button", {
130
139
  type: "button",
131
140
  onClick: (t) => {
132
- t.stopPropagation(), v(e), x(!1);
141
+ t.stopPropagation(), v(e), S(!1);
133
142
  },
134
143
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
135
144
  children: [/* @__PURE__ */ m(l, { className: "size-4" }), "Unpin"]
@@ -137,7 +146,7 @@ function g({ note: e, onOpen: t, onEdit: u, onDelete: g, onPin: _, onUnpin: v, o
137
146
  !e.isPinned && _ && /* @__PURE__ */ h("button", {
138
147
  type: "button",
139
148
  onClick: (t) => {
140
- t.stopPropagation(), _(e), x(!1);
149
+ t.stopPropagation(), _(e), S(!1);
141
150
  },
142
151
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
143
152
  children: [/* @__PURE__ */ m(c, { className: "size-4" }), "Pin"]
@@ -145,7 +154,7 @@ function g({ note: e, onOpen: t, onEdit: u, onDelete: g, onPin: _, onUnpin: v, o
145
154
  g && /* @__PURE__ */ h("button", {
146
155
  type: "button",
147
156
  onClick: (t) => {
148
- t.stopPropagation(), g(e), x(!1);
157
+ t.stopPropagation(), g(e), S(!1);
149
158
  },
150
159
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-b-lg",
151
160
  children: [/* @__PURE__ */ m(p, { className: "size-4" }), "Delete"]
@@ -158,20 +167,20 @@ function g({ note: e, onOpen: t, onEdit: u, onDelete: g, onPin: _, onUnpin: v, o
158
167
  ]
159
168
  });
160
169
  }
161
- function _({ notes: n, onOpen: r, onEdit: a, onDelete: o, onPin: s, onUnpin: c, onShare: l, onCreateNew: d, isLoading: f }) {
162
- let p = e();
163
- if (!f && n.length === 0) return /* @__PURE__ */ m(t, {
170
+ function _({ notes: n, onOpen: r, onEdit: a, onDelete: o, onPin: s, onUnpin: c, onShare: l, onShareAccess: d, onCreateNew: f, isLoading: p }) {
171
+ let _ = e();
172
+ if (!p && n.length === 0) return /* @__PURE__ */ m(t, {
164
173
  icon: /* @__PURE__ */ m(i, { className: "size-8 text-text-secondary" }),
165
- title: p("vibecontrols.notes.emptyTitle", "No notes yet"),
166
- description: p("vibecontrols.notes.emptyDescription", "Notes help you document your development process. Create your first note to get started."),
167
- action: d && /* @__PURE__ */ h("button", {
174
+ title: _("vibecontrols.notes.emptyTitle", "No notes yet"),
175
+ description: _("vibecontrols.notes.emptyDescription", "Notes help you document your development process. Create your first note to get started."),
176
+ action: f && /* @__PURE__ */ h("button", {
168
177
  type: "button",
169
- onClick: d,
178
+ onClick: f,
170
179
  className: "inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors",
171
- children: [/* @__PURE__ */ m(u, { className: "size-4" }), p("vibecontrols.notes.createNote", "Create Note")]
180
+ children: [/* @__PURE__ */ m(u, { className: "size-4" }), _("vibecontrols.notes.createNote", "Create Note")]
172
181
  })
173
182
  });
174
- let _ = [...n].sort((e, t) => e.isPinned && !t.isPinned ? -1 : !e.isPinned && t.isPinned ? 1 : new Date(t.updatedAt).getTime() - new Date(e.updatedAt).getTime());
183
+ let v = [...n].sort((e, t) => e.isPinned && !t.isPinned ? -1 : !e.isPinned && t.isPinned ? 1 : new Date(t.updatedAt).getTime() - new Date(e.updatedAt).getTime());
175
184
  return /* @__PURE__ */ m("div", {
176
185
  className: "border border-border-default rounded-lg",
177
186
  children: /* @__PURE__ */ m("div", {
@@ -183,33 +192,34 @@ function _({ notes: n, onOpen: r, onEdit: a, onDelete: o, onPin: s, onUnpin: c,
183
192
  children: [
184
193
  /* @__PURE__ */ m("th", {
185
194
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider rounded-tl-lg",
186
- children: p("vibecontrols.notes.columnTitle", "Title")
195
+ children: _("vibecontrols.notes.columnTitle", "Title")
187
196
  }),
188
197
  /* @__PURE__ */ m("th", {
189
198
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
190
- children: p("vibecontrols.notes.columnVibe", "Vibe")
199
+ children: _("vibecontrols.notes.columnVibe", "Vibe")
191
200
  }),
192
201
  /* @__PURE__ */ m("th", {
193
202
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
194
- children: p("vibecontrols.notes.columnTags", "Tags")
203
+ children: _("vibecontrols.notes.columnTags", "Tags")
195
204
  }),
196
205
  /* @__PURE__ */ m("th", {
197
206
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
198
- children: p("vibecontrols.notes.columnUpdated", "Updated")
207
+ children: _("vibecontrols.notes.columnUpdated", "Updated")
199
208
  }),
200
209
  /* @__PURE__ */ m("th", {
201
210
  className: "px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider rounded-tr-lg",
202
- children: p("vibecontrols.notes.columnActions", "Actions")
211
+ children: _("vibecontrols.notes.columnActions", "Actions")
203
212
  })
204
213
  ]
205
- }) }), /* @__PURE__ */ m("tbody", { children: _.map((e) => /* @__PURE__ */ m(g, {
214
+ }) }), /* @__PURE__ */ m("tbody", { children: v.map((e) => /* @__PURE__ */ m(g, {
206
215
  note: e,
207
216
  onOpen: r,
208
217
  onEdit: a,
209
218
  onDelete: o,
210
219
  onPin: s,
211
220
  onUnpin: c,
212
- onShare: l
221
+ onShare: l,
222
+ onShareAccess: d
213
223
  }, e.id)) })]
214
224
  })
215
225
  })
@@ -1 +1 @@
1
- {"version":3,"file":"NoteList.js","names":[],"sources":["../../../src/components/notes/NoteList.tsx"],"sourcesContent":["import type { Note } from './types';\nimport { EmptyState } from '../shared/EmptyState';\nimport {\n FileText,\n Plus,\n Pin,\n Tag,\n MoreVertical,\n Edit,\n Trash2,\n PinOff,\n Lock,\n Globe,\n Share2,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface NoteListProps {\n notes: Note[];\n onOpen?: (note: Note) => void;\n onEdit?: (note: Note) => void;\n onDelete?: (note: Note) => void;\n onPin?: (note: Note) => void;\n onUnpin?: (note: Note) => void;\n onShare?: (note: Note) => void;\n onCreateNew?: () => void;\n isLoading?: boolean;\n}\n\nfunction NoteRow({\n note,\n onOpen,\n onEdit,\n onDelete,\n onPin,\n onUnpin,\n onShare,\n}: {\n note: Note;\n onOpen?: (note: Note) => void;\n onEdit?: (note: Note) => void;\n onDelete?: (note: Note) => void;\n onPin?: (note: Note) => void;\n onUnpin?: (note: Note) => void;\n onShare?: (note: Note) => void;\n}) {\n const [showMenu, setShowMenu] = useState(false);\n\n const formatDate = (dateStr: string) => {\n return new Date(dateStr).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n });\n };\n\n const getPreview = (content: string) => {\n const text = content\n .replace(/^#+\\s+/gm, '')\n .replace(/\\n/g, ' ')\n .trim();\n return text.length > 80 ? text.slice(0, 80) + '...' : text;\n };\n\n return (\n <tr\n className=\"border-b border-border-subtle hover:bg-bg-sunken/50 cursor-pointer transition-colors\"\n onClick={() => onOpen?.(note)}\n >\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <FileText className=\"size-4 text-status-warning-text shrink-0\" />\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{note.title}</p>\n {note.isPinned && <Pin className=\"size-3 text-status-warning-text shrink-0\" />}\n {note.visibility === 'PRIVATE' ? (\n <span title=\"Private\">\n <Lock className=\"size-3 text-text-muted shrink-0\" />\n </span>\n ) : (\n <span title=\"Workspace\">\n <Globe className=\"size-3 text-text-muted shrink-0\" />\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-muted truncate max-w-[300px]\">\n {getPreview(note.content)}\n </p>\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-sm text-text-secondary truncate block max-w-[100px]\">\n {note.vibe?.name || '-'}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n {/* Render tagAssignments if available, otherwise fall back to legacy string tags */}\n {note.tagAssignments && note.tagAssignments.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {note.tagAssignments.slice(0, 2).map((assignment) => (\n <span\n key={assignment.id}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-action-primary-bg/10 text-action-primary-bg rounded\"\n style={\n assignment.tag?.color\n ? { borderLeft: `2px solid ${assignment.tag.color}` }\n : undefined\n }\n >\n <Tag className=\"size-2.5\" />\n {assignment.tag?.label ?? assignment.tagId.slice(0, 8)}\n </span>\n ))}\n {note.tagAssignments.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tagAssignments.length - 2}\n </span>\n )}\n </div>\n ) : note.tags && note.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {note.tags.slice(0, 2).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-2.5\" />\n {tag}\n </span>\n ))}\n {note.tags.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tags.length - 2}\n </span>\n )}\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-xs text-text-muted\">{formatDate(note.updatedAt)}</span>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1 justify-end\">\n {(onEdit || onDelete || onPin || onUnpin || onShare) && (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"size-3.5 text-text-secondary\" />\n </button>\n {showMenu && (\n <div className=\"absolute right-0 mt-1 w-44 bg-bg-surface border border-border-default rounded-lg shadow-lg z-50\">\n {onEdit && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onEdit(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Edit className=\"size-4\" />\n Edit\n </button>\n )}\n {onShare && note.visibility === 'PRIVATE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Share2 className=\"size-4\" />\n Share with workspace\n </button>\n )}\n {onShare && note.visibility === 'WORKSPACE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Lock className=\"size-4\" />\n Make private\n </button>\n )}\n {note.isPinned && onUnpin && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onUnpin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <PinOff className=\"size-4\" />\n Unpin\n </button>\n )}\n {!note.isPinned && onPin && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onPin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Pin className=\"size-4\" />\n Pin\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-b-lg\"\n >\n <Trash2 className=\"size-4\" />\n Delete\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\nexport function NoteList({\n notes,\n onOpen,\n onEdit,\n onDelete,\n onPin,\n onUnpin,\n onShare,\n onCreateNew,\n isLoading,\n}: NoteListProps) {\n const tr = useTr();\n if (!isLoading && notes.length === 0) {\n return (\n <EmptyState\n icon={<FileText className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.notes.emptyTitle', 'No notes yet')}\n description={tr(\n 'vibecontrols.notes.emptyDescription',\n 'Notes help you document your development process. Create your first note to get started.'\n )}\n action={\n onCreateNew && (\n <button\n type=\"button\"\n onClick={onCreateNew}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.notes.createNote', 'Create Note')}\n </button>\n )\n }\n />\n );\n }\n\n // Sort: pinned first, then by updated date\n const sortedNotes = [...notes].sort((a, b) => {\n if (a.isPinned && !b.isPinned) return -1;\n if (!a.isPinned && b.isPinned) return 1;\n return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();\n });\n\n return (\n <div className=\"border border-border-default rounded-lg\">\n <div className=\"overflow-x-auto rounded-lg\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"bg-bg-sunken border-b border-border-default\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider rounded-tl-lg\">\n {tr('vibecontrols.notes.columnTitle', 'Title')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnVibe', 'Vibe')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnTags', 'Tags')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnUpdated', 'Updated')}\n </th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider rounded-tr-lg\">\n {tr('vibecontrols.notes.columnActions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {sortedNotes.map((note) => (\n <NoteRow\n key={note.id}\n note={note}\n onOpen={onOpen}\n onEdit={onEdit}\n onDelete={onDelete}\n onPin={onPin}\n onUnpin={onUnpin}\n onShare={onShare}\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"NoteList.js","names":[],"sources":["../../../src/components/notes/NoteList.tsx"],"sourcesContent":["import type { Note } from './types';\nimport { EmptyState } from '../shared/EmptyState';\nimport {\n FileText,\n Plus,\n Pin,\n Tag,\n MoreVertical,\n Edit,\n Trash2,\n PinOff,\n Lock,\n Globe,\n Share2,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface NoteListProps {\n notes: Note[];\n onOpen?: (note: Note) => void;\n onEdit?: (note: Note) => void;\n onDelete?: (note: Note) => void;\n onPin?: (note: Note) => void;\n onUnpin?: (note: Note) => void;\n onShare?: (note: Note) => void;\n /** Generic-sharing entry point (full Share dialog); see NoteCard.onShareAccess. */\n onShareAccess?: (note: Note) => void;\n onCreateNew?: () => void;\n isLoading?: boolean;\n}\n\nfunction NoteRow({\n note,\n onOpen,\n onEdit,\n onDelete,\n onPin,\n onUnpin,\n onShare,\n onShareAccess,\n}: {\n note: Note;\n onOpen?: (note: Note) => void;\n onEdit?: (note: Note) => void;\n onDelete?: (note: Note) => void;\n onPin?: (note: Note) => void;\n onUnpin?: (note: Note) => void;\n onShare?: (note: Note) => void;\n onShareAccess?: (note: Note) => void;\n}) {\n const [showMenu, setShowMenu] = useState(false);\n\n const formatDate = (dateStr: string) => {\n return new Date(dateStr).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n });\n };\n\n const getPreview = (content: string) => {\n const text = content\n .replace(/^#+\\s+/gm, '')\n .replace(/\\n/g, ' ')\n .trim();\n return text.length > 80 ? text.slice(0, 80) + '...' : text;\n };\n\n return (\n <tr\n className=\"border-b border-border-subtle hover:bg-bg-sunken/50 cursor-pointer transition-colors\"\n onClick={() => onOpen?.(note)}\n >\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <FileText className=\"size-4 text-status-warning-text shrink-0\" />\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{note.title}</p>\n {note.isPinned && <Pin className=\"size-3 text-status-warning-text shrink-0\" />}\n {note.visibility === 'PRIVATE' ? (\n <span title=\"Private\">\n <Lock className=\"size-3 text-text-muted shrink-0\" />\n </span>\n ) : (\n <span title=\"Workspace\">\n <Globe className=\"size-3 text-text-muted shrink-0\" />\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-muted truncate max-w-[300px]\">\n {getPreview(note.content)}\n </p>\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-sm text-text-secondary truncate block max-w-[100px]\">\n {note.vibe?.name || '-'}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n {/* Render tagAssignments if available, otherwise fall back to legacy string tags */}\n {note.tagAssignments && note.tagAssignments.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {note.tagAssignments.slice(0, 2).map((assignment) => (\n <span\n key={assignment.id}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-action-primary-bg/10 text-action-primary-bg rounded\"\n style={\n assignment.tag?.color\n ? { borderLeft: `2px solid ${assignment.tag.color}` }\n : undefined\n }\n >\n <Tag className=\"size-2.5\" />\n {assignment.tag?.label ?? assignment.tagId.slice(0, 8)}\n </span>\n ))}\n {note.tagAssignments.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tagAssignments.length - 2}\n </span>\n )}\n </div>\n ) : note.tags && note.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {note.tags.slice(0, 2).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-2.5\" />\n {tag}\n </span>\n ))}\n {note.tags.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tags.length - 2}\n </span>\n )}\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-xs text-text-muted\">{formatDate(note.updatedAt)}</span>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1 justify-end\">\n {(onEdit || onDelete || onPin || onUnpin || onShare || onShareAccess) && (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"size-3.5 text-text-secondary\" />\n </button>\n {showMenu && (\n <div className=\"absolute right-0 mt-1 w-44 bg-bg-surface border border-border-default rounded-lg shadow-lg z-50\">\n {onEdit && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onEdit(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Edit className=\"size-4\" />\n Edit\n </button>\n )}\n {onShare && note.visibility === 'PRIVATE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Share2 className=\"size-4\" />\n Share with workspace\n </button>\n )}\n {onShare && note.visibility === 'WORKSPACE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Lock className=\"size-4\" />\n Make private\n </button>\n )}\n {onShareAccess && (\n <button\n type=\"button\"\n data-testid=\"note-share-access\"\n onClick={(e) => {\n e.stopPropagation();\n onShareAccess(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Share2 className=\"size-4\" />\n Share access…\n </button>\n )}\n {note.isPinned && onUnpin && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onUnpin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <PinOff className=\"size-4\" />\n Unpin\n </button>\n )}\n {!note.isPinned && onPin && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onPin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Pin className=\"size-4\" />\n Pin\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-b-lg\"\n >\n <Trash2 className=\"size-4\" />\n Delete\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\nexport function NoteList({\n notes,\n onOpen,\n onEdit,\n onDelete,\n onPin,\n onUnpin,\n onShare,\n onShareAccess,\n onCreateNew,\n isLoading,\n}: NoteListProps) {\n const tr = useTr();\n if (!isLoading && notes.length === 0) {\n return (\n <EmptyState\n icon={<FileText className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.notes.emptyTitle', 'No notes yet')}\n description={tr(\n 'vibecontrols.notes.emptyDescription',\n 'Notes help you document your development process. Create your first note to get started.'\n )}\n action={\n onCreateNew && (\n <button\n type=\"button\"\n onClick={onCreateNew}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.notes.createNote', 'Create Note')}\n </button>\n )\n }\n />\n );\n }\n\n // Sort: pinned first, then by updated date\n const sortedNotes = [...notes].sort((a, b) => {\n if (a.isPinned && !b.isPinned) return -1;\n if (!a.isPinned && b.isPinned) return 1;\n return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();\n });\n\n return (\n <div className=\"border border-border-default rounded-lg\">\n <div className=\"overflow-x-auto rounded-lg\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"bg-bg-sunken border-b border-border-default\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider rounded-tl-lg\">\n {tr('vibecontrols.notes.columnTitle', 'Title')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnVibe', 'Vibe')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnTags', 'Tags')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnUpdated', 'Updated')}\n </th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider rounded-tr-lg\">\n {tr('vibecontrols.notes.columnActions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {sortedNotes.map((note) => (\n <NoteRow\n key={note.id}\n note={note}\n onOpen={onOpen}\n onEdit={onEdit}\n onDelete={onDelete}\n onPin={onPin}\n onUnpin={onUnpin}\n onShare={onShare}\n onShareAccess={onShareAccess}\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}