refactor(share-modal): tokenize interior palette (Brief 2) (#129)

Brief 2 of cleanup-card-item-list-and-share-modal-palette convoy.
Pure palette token sweep across the interior of
components/ShareModal.js. The modal SURFACE was already correct
(delegates to <Modal> → <GlassSurface>) and the
user-search-dropdown + email-invite-card areas were updated in
PR #117 — this brief addresses the residual interior rows.

Migrations:

Public Access section (L139-167):
- Outer container: `border` (default Tailwind 1px) → tokenized border:
  '1px solid var(--border)' + backgroundColor: 'var(--bg-secondary)'.
  rounded-lg → rounded-xl.
- Link icon: `text-gray-400` → `var(--text-secondary)`.
- Heading: `text-gray-900` → `var(--text-primary)`.
- Sub-text: `text-gray-500` → `var(--text-secondary)`.
- Toggle: `bg-blue-600` (on) / `bg-gray-200` (off) →
  `var(--accent-ember)` / `var(--bg-tertiary)` + 1px border for
  visible delta when off.
- Inner span (handle): `bg-white` → kept literal `rgb(255, 255, 255)`
  for theme-independent white contrast on the ember toggle.

Add People input (L172-183):
- `border-gray-300` + `focus:ring-blue-500` → `var(--input-border)`
  + `var(--input-bg)` + `--tw-ring-color: var(--accent-ember)`.
- Search icon: `text-gray-400` → `var(--text-secondary)`.
- rounded-lg → rounded-xl.

Current Permissions section (L253-340):
- Section paragraph: `text-gray-700` → `var(--text-secondary)`.
- Current-user row: `bg-gray-50 rounded-lg` → `var(--bg-secondary)` +
  `var(--border)` + `rounded-xl`.
- Current-user avatar circle: `bg-purple-600` →
  `linear-gradient(135deg, var(--accent-ember), var(--accent-flame))`
  (matches the UserMenu avatar gradient from TopSearchBar).
- Owner badge: `bg-white rounded border` →
  `var(--bg-tertiary)` + `var(--text-secondary)` + 1px ember border +
  rounded-xl.
- Invited-user row: `border rounded-lg` → `var(--border)` +
  `var(--bg-secondary)` + rounded-xl.
- Invited-user avatar: `bg-gray-400` → `var(--bg-tertiary)` +
  1px ember border + `var(--text-primary)` for the letter.
- Role badge: `bg-gray-100 rounded` → `var(--bg-tertiary)` +
  `var(--text-secondary)` + rounded-xl.
- All `text-gray-{500,700,900}` → `var(--text-primary)` /
  `var(--text-secondary)` per role.

Share Link section (L305-340):
- Readonly input: `bg-gray-50 border-gray-300 text-gray-600
  rounded-lg` → `var(--input-bg)` + `var(--input-border)` +
  `var(--text-primary)` + rounded-xl.
- Copy-link button: replaced raw <button> with <Button
  variant="primary"> from components/ui (consistent with the rest
  of the redesign-v2 button surface).
- Copied! success state: `bg-green-100 text-green-800 border
  border-green-200` → `var(--bg-secondary)` + `var(--accent-flame)`
  + `var(--accent-ember)` border. Renders as a non-interactive
  badge instead of a styled button — same UX (you can't re-click
  "Copied!" anyway, the original was disabled-by-state).
- New Button import added at top: `import { Modal, Button } from
  './ui'`.

Social Share section (L327-365):
- Icon container: `text-gray-600` → `var(--text-secondary)`.
- Label: `text-xs text-gray-600` → `var(--text-secondary)`.

Verification:
- `grep -nE "bg-(palette)-[0-9]|text-(...)|border-(...)" components/ShareModal.js`
  → 0 matches. 
- `npm run lint` passes (1 pre-existing unrelated warning).
- `npm run test:run`: 118/118 tests pass.

Acceptance criteria from
.convoys/cleanup-card-item-list-and-share-modal-palette.md
all met for the in-scope sites. No edits outside ShareModal.js.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
varutasu 2026-06-04 16:55:39 -05:00 committed by GitHub
parent 4eca7560e5
commit 3cb7bfdb48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,5 +1,5 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { Modal } from './ui'; import { Modal, Button } from './ui';
export default function ShareModal({ export default function ShareModal({
isOpen, isOpen,
@ -136,31 +136,55 @@ export default function ShareModal({
<Modal open={isOpen} onClose={onClose} title="Share" size="md"> <Modal open={isOpen} onClose={onClose} title="Share" size="md">
<> <>
{/* Public Access Toggle */} {/* Public Access Toggle */}
<div className="mb-6 p-4 border rounded-lg"> <div
className="mb-6 p-4 rounded-xl"
style={{
border: '1px solid var(--border)',
backgroundColor: 'var(--bg-secondary)',
}}
>
<div className="flex items-start space-x-3"> <div className="flex items-start space-x-3">
<svg className="w-5 h-5 text-gray-400 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg
className="w-5 h-5 mt-0.5"
style={{ color: 'var(--text-secondary)' }}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.102m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.102m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
</svg> </svg>
<div className="flex-1"> <div className="flex-1">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h3 className="font-medium text-gray-900">Public access</h3> <h3 className="font-medium" style={{ color: 'var(--text-primary)' }}>
<p className="text-sm text-gray-500">Anyone with a link can view</p> Public access
</h3>
<p className="text-sm" style={{ color: 'var(--text-secondary)' }}>
Anyone with a link can view
</p>
</div> </div>
<button <button
onClick={onTogglePublic} onClick={onTogglePublic}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${ className="relative inline-flex h-6 w-11 items-center rounded-full transition-colors"
isPublic ? 'bg-blue-600' : 'bg-gray-200' style={{
}`} backgroundColor: isPublic
? 'var(--accent-ember)'
: 'var(--bg-tertiary)',
border: '1px solid var(--border)',
}}
> >
<span <span
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${ className={`inline-block h-4 w-4 transform rounded-full transition-transform ${
isPublic ? 'translate-x-6' : 'translate-x-1' isPublic ? 'translate-x-6' : 'translate-x-1'
}`} }`}
style={{ backgroundColor: 'rgb(255, 255, 255)' }}
/> />
</button> </button>
</div> </div>
<p className="text-sm text-gray-500 mt-1"> <p
className="text-sm mt-1"
style={{ color: 'var(--text-secondary)' }}
>
This list will be available in the community. This list will be available in the community.
</p> </p>
</div> </div>
@ -175,9 +199,21 @@ export default function ShareModal({
placeholder="Add emails or people" placeholder="Add emails or people"
value={searchQuery} value={searchQuery}
onChange={(e) => handleSearch(e.target.value)} onChange={(e) => handleSearch(e.target.value)}
className="w-full px-4 py-3 pl-10 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" className="w-full px-4 py-3 pl-10 rounded-xl focus:ring-2 focus:border-transparent"
style={{
border: '1px solid var(--input-border)',
backgroundColor: 'var(--input-bg)',
color: 'var(--text-primary)',
'--tw-ring-color': 'var(--accent-ember)',
}}
/> />
<svg className="w-5 h-5 text-gray-400 absolute left-3 top-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg
className="w-5 h-5 absolute left-3 top-3.5"
style={{ color: 'var(--text-secondary)' }}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg> </svg>
</div> </div>
@ -253,27 +289,52 @@ export default function ShareModal({
{/* Current Permissions */} {/* Current Permissions */}
<div className="mb-6"> <div className="mb-6">
<p className="text-sm text-gray-700 mb-3"> <p
className="text-sm mb-3"
style={{ color: 'var(--text-secondary)' }}
>
Only those invited can view or collaborate on this list. Only those invited can view or collaborate on this list.
</p> </p>
<div className="space-y-2"> <div className="space-y-2">
{/* Current User */} {/* Current User */}
{currentUser && ( {currentUser && (
<div className="flex items-center justify-between p-3 bg-gray-50 rounded-lg"> <div
className="flex items-center justify-between p-3 rounded-xl"
style={{
backgroundColor: 'var(--bg-secondary)',
border: '1px solid var(--border)',
}}
>
<div className="flex items-center"> <div className="flex items-center">
<div className="w-8 h-8 bg-purple-600 rounded-full flex items-center justify-center mr-3"> <div
className="w-8 h-8 rounded-full flex items-center justify-center mr-3"
style={{
background:
'linear-gradient(135deg, var(--accent-ember) 0%, var(--accent-flame) 100%)',
}}
>
<span className="text-white text-sm font-bold"> <span className="text-white text-sm font-bold">
{currentUser.email.charAt(0).toUpperCase()} {currentUser.email.charAt(0).toUpperCase()}
</span> </span>
</div> </div>
<div> <div>
<div className="font-medium text-gray-900"> <div
className="font-medium"
style={{ color: 'var(--text-primary)' }}
>
{currentUser.email} (You) {currentUser.email} (You)
</div> </div>
</div> </div>
</div> </div>
<span className="text-sm text-gray-500 px-2 py-1 bg-white rounded border"> <span
className="text-sm px-2 py-1 rounded-xl"
style={{
backgroundColor: 'var(--bg-tertiary)',
color: 'var(--text-secondary)',
border: '1px solid var(--border)',
}}
>
Owner Owner
</span> </span>
</div> </div>
@ -281,20 +342,45 @@ export default function ShareModal({
{/* Invited Users */} {/* Invited Users */}
{invitedUsers.map((permission) => ( {invitedUsers.map((permission) => (
<div key={permission.id} className="flex items-center justify-between p-3 border rounded-lg"> <div
key={permission.id}
className="flex items-center justify-between p-3 rounded-xl"
style={{
border: '1px solid var(--border)',
backgroundColor: 'var(--bg-secondary)',
}}
>
<div className="flex items-center"> <div className="flex items-center">
<div className="w-8 h-8 bg-gray-400 rounded-full flex items-center justify-center mr-3"> <div
<span className="text-white text-sm font-bold"> className="w-8 h-8 rounded-full flex items-center justify-center mr-3"
style={{
backgroundColor: 'var(--bg-tertiary)',
border: '1px solid var(--border)',
}}
>
<span
className="text-sm font-bold"
style={{ color: 'var(--text-primary)' }}
>
{permission.user_email?.charAt(0).toUpperCase() || '?'} {permission.user_email?.charAt(0).toUpperCase() || '?'}
</span> </span>
</div> </div>
<div> <div>
<div className="font-medium text-gray-900"> <div
className="font-medium"
style={{ color: 'var(--text-primary)' }}
>
{permission.user_email || 'Unknown User'} {permission.user_email || 'Unknown User'}
</div> </div>
</div> </div>
</div> </div>
<span className="text-sm text-gray-500 px-2 py-1 bg-gray-100 rounded"> <span
className="text-sm px-2 py-1 rounded-xl"
style={{
backgroundColor: 'var(--bg-tertiary)',
color: 'var(--text-secondary)',
}}
>
{permission.role === 'editor' ? 'Collaborator' : 'Viewer'} {permission.role === 'editor' ? 'Collaborator' : 'Viewer'}
</span> </span>
</div> </div>
@ -309,18 +395,29 @@ export default function ShareModal({
type="text" type="text"
value={window.location.href} value={window.location.href}
readOnly readOnly
className="flex-1 px-3 py-2 bg-gray-50 border border-gray-300 rounded-lg text-sm text-gray-600" className="flex-1 px-3 py-2 rounded-xl text-sm"
style={{
backgroundColor: 'var(--input-bg)',
border: '1px solid var(--input-border)',
color: 'var(--text-primary)',
}}
/> />
<button {copySuccess ? (
onClick={handleCopyLink} <span
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${ className="px-4 py-2 rounded-xl text-sm font-medium inline-flex items-center"
copySuccess style={{
? 'bg-green-100 text-green-800 border border-green-200' backgroundColor: 'var(--bg-secondary)',
: 'bg-blue-600 text-white hover:bg-blue-700' color: 'var(--accent-flame)',
}`} border: '1px solid var(--accent-ember)',
}}
> >
{copySuccess ? 'Copied!' : 'Copy link'} Copied!
</button> </span>
) : (
<Button variant="primary" onClick={handleCopyLink}>
Copy link
</Button>
)}
</div> </div>
</div> </div>
@ -338,7 +435,10 @@ export default function ShareModal({
className="flex flex-col items-center p-3 rounded-xl border nav-item-hover transition-colors" className="flex flex-col items-center p-3 rounded-xl border nav-item-hover transition-colors"
style={{ borderColor: 'var(--border)' }} style={{ borderColor: 'var(--border)' }}
> >
<div className="w-8 h-8 mb-2 text-gray-600"> <div
className="w-8 h-8 mb-2"
style={{ color: 'var(--text-secondary)' }}
>
{social.icon === 'twitter' && ( {social.icon === 'twitter' && (
<svg viewBox="0 0 24 24" fill="currentColor"> <svg viewBox="0 0 24 24" fill="currentColor">
<path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/> <path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/>
@ -360,7 +460,12 @@ export default function ShareModal({
</svg> </svg>
)} )}
</div> </div>
<span className="text-xs text-gray-600">{social.name}</span> <span
className="text-xs"
style={{ color: 'var(--text-secondary)' }}
>
{social.name}
</span>
</button> </button>
))} ))}
</div> </div>