diff --git a/list-manager/list-manager.css b/list-manager/list-manager.css
index dcb327d..396b022 100644
--- a/list-manager/list-manager.css
+++ b/list-manager/list-manager.css
@@ -137,40 +137,86 @@ body {
.list-hint {
font-size: 0.8rem;
opacity: 0.7;
+ margin-top: -4px;
+}
+
+.selection-hint {
+ font-size: 0.75rem;
+ opacity: 0.6;
+ margin-top: 4px;
+ font-style: italic;
}
.lists {
display: flex;
flex-direction: column;
- gap: 8px;
+ gap: 10px;
overflow-y: auto;
padding-right: 4px;
}
+/* Custom scrollbar styling */
+.lists::-webkit-scrollbar,
+.word-list::-webkit-scrollbar {
+ width: 8px;
+}
+
+.lists::-webkit-scrollbar-track,
+.word-list::-webkit-scrollbar-track {
+ background: #1a1511;
+ border-radius: 10px;
+}
+
+.lists::-webkit-scrollbar-thumb,
+.word-list::-webkit-scrollbar-thumb {
+ background: var(--input-border);
+ border-radius: 10px;
+ transition: background 0.2s ease;
+}
+
+.lists::-webkit-scrollbar-thumb:hover,
+.word-list::-webkit-scrollbar-thumb:hover {
+ background: #4a3e36;
+}
+
.list-item {
background: #1f1813;
- border: 1px solid transparent;
+ border: 2px solid transparent;
border-radius: 12px;
padding: 10px 12px;
display: grid;
- grid-template-columns: auto 1fr auto;
+ grid-template-columns: 1fr auto;
gap: 10px;
align-items: center;
cursor: pointer;
+ transition: all 0.2s ease;
+ position: relative;
+}
+
+.list-item:hover {
+ background: #251f19;
+ border-color: rgba(242, 168, 101, 0.3);
}
.list-item.active {
border-color: var(--accent);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
+ background: #2a2218;
+}
+
+.list-item.selected {
+ background: rgba(242, 168, 101, 0.15);
+ border-color: rgba(242, 168, 101, 0.6);
+}
+
+.list-item.selected.active {
+ border-color: var(--accent);
+ background: rgba(242, 168, 101, 0.2);
}
.list-item.drag-over {
border-color: var(--accent-hover);
-}
-
-.list-item input[type="checkbox"] {
- width: 16px;
- height: 16px;
+ transform: scale(1.02);
}
.list-meta {
@@ -279,7 +325,7 @@ body {
background: #1a1511;
display: flex;
flex-direction: column;
- gap: 6px;
+ gap: 8px;
}
.empty {
@@ -291,20 +337,129 @@ body {
.word-item {
display: grid;
- grid-template-columns: auto 1fr auto auto auto;
+ grid-template-columns: 1fr auto auto auto auto;
gap: 8px;
align-items: center;
- padding: 6px 8px;
+ padding: 8px 10px;
border-radius: 10px;
background: #201915;
+ border: 2px solid transparent;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ position: relative;
+}
+
+.word-item:hover {
+ background: #2a2218;
+ border-color: rgba(242, 168, 101, 0.2);
+}
+
+.word-item.selected {
+ background: rgba(242, 168, 101, 0.15);
+ border-color: rgba(242, 168, 101, 0.6);
}
.word-item.disabled {
opacity: 0.5;
}
-.word-item input[type="text"] {
+.word-text {
+ font-size: 0.9rem;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ user-select: none;
+}
+
+.word-text.editing {
+ display: none;
+}
+
+.word-edit-input {
+ display: none;
width: 100%;
+ background: var(--input-bg);
+ color: var(--text-color);
+ border: 1px solid var(--accent);
+ border-radius: 8px;
+ padding: 4px 8px;
+ font-size: 0.9rem;
+}
+
+.word-edit-input.active {
+ display: block;
+}
+
+.word-actions {
+ display: flex;
+ gap: 4px;
+ align-items: center;
+ pointer-events: auto;
+}
+
+.word-actions > * {
+ pointer-events: auto;
+}
+
+.icon-btn {
+ background: transparent;
+ border: none;
+ color: var(--text-color);
+ opacity: 0.6;
+ cursor: pointer;
+ padding: 4px 6px;
+ border-radius: 6px;
+ transition: all 0.2s ease;
+ font-size: 0.85rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 28px;
+ min-height: 28px;
+}
+
+.icon-btn:hover {
+ opacity: 1;
+ background: rgba(242, 168, 101, 0.15);
+ color: var(--accent);
+}
+
+.icon-btn i {
+ pointer-events: none;
+}
+
+.toggle-btn {
+ width: 40px;
+ height: 22px;
+ background: rgba(255, 255, 255, 0.1);
+ border: 1px solid var(--input-border);
+ border-radius: 11px;
+ position: relative;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ padding: 0;
+}
+
+.toggle-btn::after {
+ content: '';
+ position: absolute;
+ width: 16px;
+ height: 16px;
+ background: var(--text-color);
+ border-radius: 50%;
+ top: 2px;
+ left: 2px;
+ transition: all 0.2s ease;
+}
+
+.toggle-btn.active {
+ background: var(--accent);
+ border-color: var(--accent);
+}
+
+.toggle-btn.active::after {
+ left: 20px;
+ background: var(--accent-text);
}
button {
@@ -379,6 +534,7 @@ input[type="color"]::-webkit-color-swatch {
width: 38px;
height: 28px;
border-radius: 8px;
+ cursor: pointer;
}
.word-item input[type="color"]::-webkit-color-swatch-wrapper {
@@ -389,6 +545,11 @@ input[type="color"]::-webkit-color-swatch {
border-radius: 6px;
}
+.word-item input[type="color"]:hover {
+ transform: scale(1.05);
+ transition: transform 0.2s ease;
+}
+
.stats {
font-size: 0.85rem;
opacity: 0.7;
diff --git a/list-manager/list-manager.html b/list-manager/list-manager.html
index 99ef70a..e96a2f0 100644
--- a/list-manager/list-manager.html
+++ b/list-manager/list-manager.html
@@ -85,6 +85,7 @@
+
Click to select • Ctrl/Cmd+Click for multi-select • Click edit icon to rename
diff --git a/popup/popup.css b/popup/popup.css
index 0e7cb7c..4cd8176 100644
--- a/popup/popup.css
+++ b/popup/popup.css
@@ -272,10 +272,18 @@ body.light {
overflow: hidden;
min-height: 0;
display: grid;
- grid-template-rows: auto auto auto 1fr;
+ grid-template-rows: auto auto auto 1fr auto;
row-gap: 6px;
}
+.selection-hint {
+ font-size: 0.7em;
+ opacity: 0.6;
+ text-align: center;
+ font-style: italic;
+ padding: 4px 0 0 0;
+}
+
.section[data-section="addwords"] textarea {
height: 44px;
}
@@ -589,23 +597,29 @@ input[type="file"] {
left: 4px;
height: 34px;
display: grid;
- grid-template-columns: 18px 1fr 26px 26px;
+ grid-template-columns: 1fr auto auto auto auto;
align-items: center;
gap: 6px;
padding: 6px 8px;
box-sizing: border-box;
border-radius: 8px;
background: var(--input-bg);
- border: 1px solid var(--input-border);
+ border: 2px solid transparent;
transition: all 0.2s;
+ cursor: pointer;
}
#wordList .word-item:hover {
background: var(--highlight-tag);
- border-color: var(--accent);
+ border-color: rgba(242, 168, 101, 0.3);
box-shadow: var(--shadow-sm);
}
+#wordList .word-item.selected {
+ background: rgba(242, 168, 101, 0.15);
+ border-color: rgba(242, 168, 101, 0.6);
+}
+
#wordList .word-item.disabled {
opacity: 0.5;
background: var(--section-bg);
@@ -615,18 +629,30 @@ input[type="file"] {
opacity: 0.65;
}
-#wordList .word-item.disabled input[type="text"] {
- color: var(--text-color) !important;
- opacity: 0.6;
+#wordList .word-item.disabled .word-text {
text-decoration: line-through;
}
-#wordList input[type="text"] {
+#wordList .word-text {
+ font-size: 0.8em;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ user-select: none;
+ min-width: 0;
+}
+
+#wordList .word-text.editing {
+ display: none;
+}
+
+#wordList .word-edit-input {
+ display: none;
min-width: 0;
width: 100%;
background-color: var(--section-bg) !important;
color: var(--text-color) !important;
- border: 1px solid var(--input-border) !important;
+ border: 1px solid var(--accent) !important;
padding: 4px 6px;
border-radius: 6px;
font-size: 0.8em;
@@ -634,11 +660,88 @@ input[type="file"] {
margin: 0;
}
-#wordList input[type="text"]:focus {
+#wordList .word-edit-input.active {
+ display: block;
+}
+
+#wordList .word-edit-input:focus {
border-color: var(--accent) !important;
outline: none;
}
+#wordList .word-actions {
+ display: flex;
+ gap: 4px;
+ align-items: center;
+ pointer-events: auto;
+}
+
+#wordList .word-actions > * {
+ pointer-events: auto;
+}
+
+#wordList .icon-btn {
+ background: transparent;
+ border: none;
+ color: var(--text-color);
+ opacity: 0.6;
+ cursor: pointer;
+ padding: 3px 5px;
+ border-radius: 4px;
+ transition: all 0.2s ease;
+ font-size: 0.75em;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 22px;
+ min-height: 22px;
+}
+
+#wordList .icon-btn:hover {
+ opacity: 1;
+ background: rgba(242, 168, 101, 0.15);
+ color: var(--accent);
+}
+
+#wordList .icon-btn i {
+ pointer-events: none;
+}
+
+#wordList .toggle-btn {
+ width: 32px;
+ height: 18px;
+ background: rgba(255, 255, 255, 0.1);
+ border: 1px solid var(--input-border);
+ border-radius: 9px;
+ position: relative;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ padding: 0;
+ flex-shrink: 0;
+}
+
+#wordList .toggle-btn::after {
+ content: '';
+ position: absolute;
+ width: 12px;
+ height: 12px;
+ background: var(--text-color);
+ border-radius: 50%;
+ top: 2px;
+ left: 2px;
+ transition: all 0.2s ease;
+}
+
+#wordList .toggle-btn.active {
+ background: var(--accent);
+ border-color: var(--accent);
+}
+
+#wordList .toggle-btn.active::after {
+ left: 16px;
+ background: var(--accent-text);
+}
+
#wordList input[type="color"] {
width: 22px;
height: 22px;
@@ -646,18 +749,14 @@ input[type="file"] {
border-radius: 3px;
border: 1px solid var(--input-border);
cursor: pointer;
- transition: border-color 0.2s;
+ transition: all 0.2s;
align-self: center;
+ flex-shrink: 0;
}
#wordList input[type="color"]:hover {
border-color: var(--accent);
-}
-
-#wordList input[type="checkbox"] {
- margin: 0;
- width: 16px;
- height: 16px;
+ transform: scale(1.05);
}
#wordCount {
diff --git a/popup/popup.html b/popup/popup.html
index cccacf1..9d24836 100644
--- a/popup/popup.html
+++ b/popup/popup.html
@@ -101,6 +101,7 @@
+ Click to select • Ctrl/Cmd+Click for multi-select
diff --git a/src/list-manager/ListManagerController.ts b/src/list-manager/ListManagerController.ts
index 41510a3..939ea70 100644
--- a/src/list-manager/ListManagerController.ts
+++ b/src/list-manager/ListManagerController.ts
@@ -64,15 +64,16 @@ export class ListManagerController {
const listsContainer = document.getElementById('listsContainer');
listsContainer?.addEventListener('click', (e) => this.handleListClick(e));
- listsContainer?.addEventListener('change', (e) => this.handleListCheckboxChange(e));
listsContainer?.addEventListener('dragstart', (e) => this.handleDragStart(e));
listsContainer?.addEventListener('dragover', (e) => this.handleDragOver(e));
listsContainer?.addEventListener('drop', (e) => this.handleDrop(e));
listsContainer?.addEventListener('dragend', () => this.clearDragState());
const wordList = document.getElementById('wordList');
+ wordList?.addEventListener('click', (e) => this.handleWordListClick(e));
wordList?.addEventListener('change', (e) => this.handleWordListChange(e));
wordList?.addEventListener('keydown', (e) => this.handleWordListKeydown(e));
+ wordList?.addEventListener('blur', (e) => this.handleWordListBlur(e), true);
}
private setupStorageSync(): void {
@@ -313,29 +314,28 @@ export class ListManagerController {
const listItem = target.closest('.list-item') as HTMLElement | null;
if (!listItem) return;
- if (target.tagName === 'INPUT' || target.tagName === 'BUTTON') return;
-
const index = Number(listItem.dataset.index);
if (Number.isNaN(index)) return;
+ const mouseEvent = event as MouseEvent;
+ // Ctrl/Cmd + click for multi-select
+ if (mouseEvent.ctrlKey || mouseEvent.metaKey) {
+ if (this.selectedLists.has(index)) {
+ this.selectedLists.delete(index);
+ } else {
+ this.selectedLists.add(index);
+ }
+ this.renderLists();
+ return;
+ }
+
+ // Regular click - set as current and clear multi-selection
this.currentListIndex = index;
+ this.selectedLists.clear();
this.selectedWords.clear();
this.render();
}
- private handleListCheckboxChange(event: Event): void {
- const target = event.target as HTMLInputElement;
- if (!target.classList.contains('list-checkbox')) return;
- const index = Number(target.dataset.index);
- if (Number.isNaN(index)) return;
-
- if (target.checked) {
- this.selectedLists.add(index);
- } else {
- this.selectedLists.delete(index);
- }
- }
-
private handleDragStart(event: DragEvent): void {
const target = (event.target as HTMLElement).closest('.list-item') as HTMLElement | null;
if (!target) return;
@@ -384,23 +384,84 @@ export class ListManagerController {
document.querySelectorAll('.list-item.drag-over').forEach(item => item.classList.remove('drag-over'));
}
- private handleWordListChange(event: Event): void {
- const target = event.target as HTMLInputElement;
+ private handleWordListClick(event: Event): void {
+ const target = event.target as HTMLElement;
const list = this.lists[this.currentListIndex];
if (!list) return;
- if (target.classList.contains('word-checkbox') && target.dataset.index != null) {
+ const editBtn = target.closest('.edit-word-btn') as HTMLElement | null;
+ if (editBtn) {
+ event.stopPropagation();
+ const index = Number(editBtn.dataset.index);
+ if (Number.isNaN(index)) return;
+ this.startEditingWord(index);
+ return;
+ }
+
+ // Handle toggle button click
+ if (target.classList.contains('toggle-btn')) {
+ event.stopPropagation();
const index = Number(target.dataset.index);
- if (target.checked) {
- this.selectedWords.add(index);
- } else {
+ if (Number.isNaN(index)) return;
+ const word = list.words[index];
+ if (word) {
+ word.active = !word.active;
+ this.save();
+ }
+ return;
+ }
+
+ // Don't select if clicking on color inputs or edit input
+ if (target.tagName === 'INPUT') {
+ if ((target as HTMLInputElement).type === 'color') {
+ event.stopPropagation();
+ return;
+ }
+ if (target.classList.contains('word-edit-input')) {
+ event.stopPropagation();
+ return;
+ }
+ }
+
+ // Don't select if clicking inside word-actions area (except on the word item itself)
+ if (target.closest('.word-actions') && !target.classList.contains('word-item')) {
+ return;
+ }
+
+ // Handle word item selection
+ const wordItem = target.closest('.word-item') as HTMLElement | null;
+ if (!wordItem) return;
+
+ const index = Number(wordItem.dataset.index);
+ if (Number.isNaN(index)) return;
+
+ const mouseEvent = event as MouseEvent;
+ // Ctrl/Cmd + click for multi-select
+ if (mouseEvent.ctrlKey || mouseEvent.metaKey) {
+ if (this.selectedWords.has(index)) {
this.selectedWords.delete(index);
+ } else {
+ this.selectedWords.add(index);
}
this.renderWords();
return;
}
- const editIndex = Number(target.dataset.bgEdit ?? target.dataset.fgEdit ?? target.dataset.activeEdit ?? -1);
+ // Regular click - toggle selection
+ if (this.selectedWords.has(index)) {
+ this.selectedWords.delete(index);
+ } else {
+ this.selectedWords.add(index);
+ }
+ this.renderWords();
+ }
+
+ private handleWordListChange(event: Event): void {
+ const target = event.target as HTMLInputElement;
+ const list = this.lists[this.currentListIndex];
+ if (!list) return;
+
+ const editIndex = Number(target.dataset.bgEdit ?? target.dataset.fgEdit ?? -1);
if (Number.isNaN(editIndex) || editIndex < 0) return;
const word = list.words[editIndex];
@@ -408,14 +469,28 @@ export class ListManagerController {
if (target.dataset.bgEdit != null) word.background = target.value;
if (target.dataset.fgEdit != null) word.foreground = target.value;
- if (target.dataset.activeEdit != null) word.active = target.checked;
this.save();
}
- private handleWordListKeydown(event: KeyboardEvent): void {
- if (event.key !== 'Enter') return;
+ private startEditingWord(index: number): void {
+ const wordItem = document.querySelector(`.word-item[data-index="${index}"]`);
+ if (!wordItem) return;
+
+ const textSpan = wordItem.querySelector('.word-text') as HTMLElement;
+ const input = wordItem.querySelector('.word-edit-input') as HTMLInputElement;
+ if (!textSpan || !input) return;
+
+ textSpan.classList.add('editing');
+ input.classList.add('active');
+ input.focus();
+ input.select();
+ }
+
+ private handleWordListBlur(event: Event): void {
const target = event.target as HTMLInputElement;
+ if (!target.classList.contains('word-edit-input')) return;
+
const list = this.lists[this.currentListIndex];
if (!list) return;
@@ -425,8 +500,26 @@ export class ListManagerController {
const word = list.words[index];
if (!word) return;
- word.wordStr = target.value;
- this.save();
+ const newValue = target.value.trim();
+ if (newValue && newValue !== word.wordStr) {
+ word.wordStr = newValue;
+ this.save();
+ } else {
+ this.renderWords();
+ }
+ }
+
+ private handleWordListKeydown(event: KeyboardEvent): void {
+ const target = event.target as HTMLInputElement;
+ if (!target.classList.contains('word-edit-input')) return;
+
+ if (event.key === 'Enter') {
+ event.preventDefault();
+ target.blur();
+ } else if (event.key === 'Escape') {
+ event.preventDefault();
+ this.renderWords();
+ }
}
private getSelectedListIndices(): number[] {
@@ -459,10 +552,10 @@ export class ListManagerController {
const item = document.createElement('div');
item.className = 'list-item';
if (index === this.currentListIndex) item.classList.add('active');
+ if (this.selectedLists.has(index)) item.classList.add('selected');
item.draggable = true;
item.dataset.index = index.toString();
item.innerHTML = `
-