Fix remaining list/collection copy gaps from review.

Sweep community, settings, share modal, scanner create-list modal,
and invite flows for vocabulary consistency before merge.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Randall Stillwell 2026-05-29 09:51:57 -05:00
parent a6d72e19b7
commit 0b670c1a11
15 changed files with 32 additions and 30 deletions

View file

@ -133,7 +133,7 @@ export default function CollectionSelectionModal({
<div className="p-6 border-b border-gray-200 dark:border-gray-700"> <div className="p-6 border-b border-gray-200 dark:border-gray-700">
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h2 className="text-2xl font-bold text-gray-900 dark:text-white"> <h2 className="text-2xl font-bold text-gray-900 dark:text-white">
{VOCAB.ADD_TO_LIST}s {VOCAB.ADD_TO_LISTS}
</h2> </h2>
<button <button
onClick={onClose} onClick={onClose}

View file

@ -791,7 +791,7 @@ export default function Layout({ children, user = null, showSearch = false }) {
<div className="relative"> <div className="relative">
<input <input
type="text" type="text"
placeholder="Search cards, decks, or collections..." placeholder="Search cards, decks, or lists..."
className="search-bar pr-12" className="search-bar pr-12"
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}

View file

@ -1,6 +1,6 @@
import Link from 'next/link'; import Link from 'next/link';
export default function LoginCTA({ message = "Sign up to create your own collections and more!" }) { export default function LoginCTA({ message = 'Sign up to create your own lists and more!' }) {
return ( return (
<div className="fixed bottom-6 right-6 z-50"> <div className="fixed bottom-6 right-6 z-50">
<div <div

View file

@ -202,7 +202,7 @@ export default function ScannerDestinationPicker({
{destination?.type === 'collection' && filteredCollections.length === 0 && ( {destination?.type === 'collection' && filteredCollections.length === 0 && (
<p className="mt-3 text-sm" style={{ color: 'var(--text-secondary)' }}> <p className="mt-3 text-sm" style={{ color: 'var(--text-secondary)' }}>
No collections match this game filter. No lists match this game filter.
</p> </p>
)} )}

View file

@ -113,7 +113,7 @@ export default function ShareModal({
const handleSocialShare = (platform) => { const handleSocialShare = (platform) => {
const url = window.location.href; const url = window.location.href;
const title = `Check out this collection on Deck Hearth`; const title = 'Check out this list on Deck Hearth';
const shareUrls = { const shareUrls = {
twitter: `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`, twitter: `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`,
@ -176,7 +176,7 @@ export default function ShareModal({
</button> </button>
</div> </div>
<p className="text-sm text-gray-500 mt-1"> <p className="text-sm text-gray-500 mt-1">
This collection will be available in the community. This list will be available in the community.
</p> </p>
</div> </div>
</div> </div>
@ -244,7 +244,7 @@ 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 text-gray-700 mb-3">
Only those invited can view or collaborate on this collection. Only those invited can view or collaborate on this list.
</p> </p>
<div className="space-y-2"> <div className="space-y-2">

View file

@ -13,6 +13,7 @@ export const VOCAB = {
ADD_TO_MY_COLLECTION: 'Add to My Collection', ADD_TO_MY_COLLECTION: 'Add to My Collection',
REMOVE_FROM_MY_COLLECTION: 'Remove from My Collection', REMOVE_FROM_MY_COLLECTION: 'Remove from My Collection',
ADD_TO_LIST: 'Add to List', ADD_TO_LIST: 'Add to List',
ADD_TO_LISTS: 'Add to Lists',
SYNCED_BINDER: 'Synced binder', SYNCED_BINDER: 'Synced binder',
SYSTEM_COLLECTION_SYNC_HINT: 'Automatically syncs with My Collection', SYSTEM_COLLECTION_SYNC_HINT: 'Automatically syncs with My Collection',
}; };

View file

@ -5,7 +5,7 @@ import { useAuth } from '../../lib/use-auth';
import CollectionSelectionModal from '../../components/CollectionSelectionModal'; import CollectionSelectionModal from '../../components/CollectionSelectionModal';
import { ManaCost, ColorIdentity, AdvancedManaCost } from '../../components/ManaSymbols'; import { ManaCost, ColorIdentity, AdvancedManaCost } from '../../components/ManaSymbols';
import ManaSymbolSettings from '../../components/ManaSymbolSettings'; import ManaSymbolSettings from '../../components/ManaSymbolSettings';
import { VOCAB } from '../../lib/collection-vocabulary.js'; import { VOCAB, collectionDisplayName } from '../../lib/collection-vocabulary.js';
export default function CardDetail() { export default function CardDetail() {
const router = useRouter(); const router = useRouter();
@ -542,7 +542,7 @@ export default function CardDetail() {
{cardCollections.map(collection => ( {cardCollections.map(collection => (
<div key={collection.id} className="flex items-center gap-2 text-sm"> <div key={collection.id} className="flex items-center gap-2 text-sm">
<span>📁</span> <span>📁</span>
<span>{collection.name}</span> <span>{collectionDisplayName(collection)}</span>
</div> </div>
))} ))}
{cardDecks.map(deck => ( {cardDecks.map(deck => (

View file

@ -178,7 +178,7 @@ export default function CollectionView() {
setShowEditModal(false); setShowEditModal(false);
} else { } else {
const error = await response.json(); const error = await response.json();
alert(error.error || 'Failed to update collection'); alert(error.error || 'Failed to update list');
} }
} catch (error) { } catch (error) {
console.error('Error updating collection:', error); console.error('Error updating collection:', error);
@ -199,7 +199,7 @@ export default function CollectionView() {
router.push('/collections'); router.push('/collections');
} else { } else {
const error = await response.json(); const error = await response.json();
alert(error.error || 'Failed to delete collection'); alert(error.error || 'Failed to delete list');
} }
} catch (error) { } catch (error) {
console.error('Error deleting collection:', error); console.error('Error deleting collection:', error);
@ -907,7 +907,7 @@ export default function CollectionView() {
className="input-field w-full" className="input-field w-full"
value={editForm.name} value={editForm.name}
onChange={(e) => setEditForm({...editForm, name: e.target.value})} onChange={(e) => setEditForm({...editForm, name: e.target.value})}
placeholder="Enter collection name" placeholder="Enter list name"
/> />
</div> </div>
<div> <div>
@ -919,7 +919,7 @@ export default function CollectionView() {
rows="3" rows="3"
value={editForm.description} value={editForm.description}
onChange={(e) => setEditForm({...editForm, description: e.target.value})} onChange={(e) => setEditForm({...editForm, description: e.target.value})}
placeholder="Describe your collection" placeholder="Describe your list"
/> />
</div> </div>
<div> <div>
@ -1038,7 +1038,7 @@ export default function CollectionView() {
{/* Show login CTA for non-authenticated users */} {/* Show login CTA for non-authenticated users */}
{!user && collection?.isPublic && ( {!user && collection?.isPublic && (
<LoginCTA message="Sign up to create your own collections and collaborate with others!" /> <LoginCTA message="Sign up to create your own lists and collaborate with others!" />
)} )}
</Layout> </Layout>
); );

View file

@ -4,6 +4,7 @@ import Link from 'next/link';
import Layout from '../../components/Layout'; import Layout from '../../components/Layout';
import PermissionIndicator from '../../components/PermissionIndicator'; import PermissionIndicator from '../../components/PermissionIndicator';
import { useAuth } from '../../lib/use-auth'; import { useAuth } from '../../lib/use-auth';
import { VOCAB } from '../../lib/collection-vocabulary.js';
export default function CommunityCollections() { export default function CommunityCollections() {
const router = useRouter(); const router = useRouter();
@ -201,7 +202,7 @@ export default function CommunityCollections() {
Community Lists Community Lists
</h1> </h1>
<p className="mt-2" style={{ color: 'var(--text-secondary)' }}> <p className="mt-2" style={{ color: 'var(--text-secondary)' }}>
Discover public collections shared by the community Discover public lists shared by the community
</p> </p>
</div> </div>
</div> </div>
@ -211,7 +212,7 @@ export default function CommunityCollections() {
<div className="flex-1 max-w-md"> <div className="flex-1 max-w-md">
<input <input
type="text" type="text"
placeholder="Search collections..." placeholder="Search lists..."
className="input-field w-full" className="input-field w-full"
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
@ -239,12 +240,12 @@ export default function CommunityCollections() {
<div className="text-center py-12"> <div className="text-center py-12">
<div className="text-6xl mb-4">🌍</div> <div className="text-6xl mb-4">🌍</div>
<h3 className="text-xl font-semibold mb-2" style={{ color: 'var(--text-primary)' }}> <h3 className="text-xl font-semibold mb-2" style={{ color: 'var(--text-primary)' }}>
{searchQuery ? 'No collections found' : 'No public collections yet'} {searchQuery ? 'No lists found' : 'No public lists yet'}
</h3> </h3>
<p className="text-sm mb-6" style={{ color: 'var(--text-secondary)' }}> <p className="text-sm mb-6" style={{ color: 'var(--text-secondary)' }}>
{searchQuery {searchQuery
? 'Try adjusting your search terms' ? 'Try adjusting your search terms'
: 'Be the first to share a public collection with the community!' : 'Be the first to share a public list with the community!'
} }
</p> </p>
{!searchQuery && ( {!searchQuery && (

View file

@ -223,7 +223,7 @@ export default function Home() {
</div> </div>
<h3 className="text-xl font-bold mb-2 gradient-text-flame">{collection.name}</h3> <h3 className="text-xl font-bold mb-2 gradient-text-flame">{collection.name}</h3>
<p className="text-sm mb-4 line-clamp-2" style={{ color: 'var(--text-secondary)' }}> <p className="text-sm mb-4 line-clamp-2" style={{ color: 'var(--text-secondary)' }}>
{collection.description || 'A carefully curated collection'} {collection.description || 'A carefully curated list'}
</p> </p>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<span className="text-sm font-medium" style={{ color: 'var(--text-primary)' }}> <span className="text-sm font-medium" style={{ color: 'var(--text-primary)' }}>

View file

@ -69,7 +69,7 @@ export default function AcceptInvite() {
Invitation Accepted! Invitation Accepted!
</h2> </h2>
<p className="mb-6" style={{ color: 'var(--text-secondary)' }}> <p className="mb-6" style={{ color: 'var(--text-secondary)' }}>
You now have access to the collection "{result.collection.name}". You now have access to the list "{result.collection.name}".
</p> </p>
<div className="space-y-3"> <div className="space-y-3">
<button <button

View file

@ -70,7 +70,7 @@ export default function DeclineInvite() {
</h2> </h2>
<p className="mb-6" style={{ color: 'var(--text-secondary)' }}> <p className="mb-6" style={{ color: 'var(--text-secondary)' }}>
You have declined the invitation to "{result.collection.name}". You have declined the invitation to "{result.collection.name}".
You can always ask the collection owner for another invitation if you change your mind. You can always ask the list owner for another invitation if you change your mind.
</p> </p>
<div className="space-y-3"> <div className="space-y-3">
<button <button

View file

@ -435,7 +435,7 @@ export default function MyCards() {
</div> </div>
<h3 className="text-lg font-semibold mb-2" style={{ color: 'var(--text-primary)' }}>No cards in {VOCAB.MY_COLLECTION}</h3> <h3 className="text-lg font-semibold mb-2" style={{ color: 'var(--text-primary)' }}>No cards in {VOCAB.MY_COLLECTION}</h3>
<p className="mb-4" style={{ color: 'var(--text-secondary)' }}> <p className="mb-4" style={{ color: 'var(--text-secondary)' }}>
{searchQuery ? 'Try adjusting your search filters' : 'Start building your collection by browsing available cards'} {searchQuery ? 'Try adjusting your search filters' : `Start adding cards to ${VOCAB.MY_COLLECTION} by browsing available cards`}
</p> </p>
<Link href="/cards"> <Link href="/cards">
<button className="px-6 py-3 font-medium rounded-xl transition-all duration-200 hover:opacity-90" style={{ backgroundColor: 'var(--accent-ember)', color: 'white' }}> <button className="px-6 py-3 font-medium rounded-xl transition-all duration-200 hover:opacity-90" style={{ backgroundColor: 'var(--accent-ember)', color: 'white' }}>

View file

@ -770,15 +770,15 @@ export default function Scanner() {
aria-labelledby="create-collection-title" aria-labelledby="create-collection-title"
> >
<h3 id="create-collection-title" className="text-lg font-semibold mb-4" style={{ color: 'var(--text-primary)' }}> <h3 id="create-collection-title" className="text-lg font-semibold mb-4" style={{ color: 'var(--text-primary)' }}>
Create New Collection Create New List
</h3> </h3>
<label htmlFor="create-collection-name" className="sr-only"> <label htmlFor="create-collection-name" className="sr-only">
Collection name List name
</label> </label>
<input <input
id="create-collection-name" id="create-collection-name"
type="text" type="text"
placeholder="Collection name..." placeholder="List name..."
value={newCollectionName} value={newCollectionName}
onChange={(e) => setNewCollectionName(e.target.value)} onChange={(e) => setNewCollectionName(e.target.value)}
className="w-full px-4 py-2 rounded-lg border mb-4" className="w-full px-4 py-2 rounded-lg border mb-4"

View file

@ -156,7 +156,7 @@ export default function Settings() {
const handleDeleteAccount = async () => { const handleDeleteAccount = async () => {
const confirmed = window.confirm( const confirmed = window.confirm(
'Are you sure you want to delete your account? This action cannot be undone and will permanently delete all your cards, collections, and decks.' 'Are you sure you want to delete your account? This action cannot be undone and will permanently delete all your cards, lists, and decks.'
); );
if (!confirmed) return; if (!confirmed) return;
@ -316,7 +316,7 @@ export default function Settings() {
{/* Collection Visibility */} {/* Collection Visibility */}
<div> <div>
<label className="block text-sm font-medium mb-2" style={{ color: 'var(--text-primary)' }}> <label className="block text-sm font-medium mb-2" style={{ color: 'var(--text-primary)' }}>
Default Collection Visibility Default List Visibility
</label> </label>
<select <select
value={settings.collection_visibility} value={settings.collection_visibility}
@ -328,7 +328,7 @@ export default function Settings() {
<option value="unlisted">Unlisted</option> <option value="unlisted">Unlisted</option>
</select> </select>
<p className="text-xs mt-1" style={{ color: 'var(--text-secondary)' }}> <p className="text-xs mt-1" style={{ color: 'var(--text-secondary)' }}>
Controls who can see your new collections by default Controls who can see your new lists by default
</p> </p>
</div> </div>
@ -546,7 +546,7 @@ export default function Settings() {
Email Notifications Email Notifications
</p> </p>
<p className="text-sm" style={{ color: 'var(--text-secondary)' }}> <p className="text-sm" style={{ color: 'var(--text-secondary)' }}>
Receive notifications about your collections and cards Receive notifications about your lists and cards
</p> </p>
</div> </div>
<button <button