Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion chrome/src/host/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1151,12 +1151,17 @@ async function getMenuTitle(): Promise<string> {
// Initialize context menu for viewing any file as markdown
async function initializeContextMenu(): Promise<void> {
try {
// Remove old menu item if exists (migration from preview to view)
// Remove old menu items if exist (prevents duplicate ID error on SW restart)
try {
await chrome.contextMenus.remove('preview-as-markdown');
} catch {
// Ignore if old menu doesn't exist
}
try {
await chrome.contextMenus.remove('view-as-markdown');
} catch {
// Ignore if menu doesn't exist yet
}

const title = await getMenuTitle();
chrome.contextMenus.create({
Expand Down
77 changes: 77 additions & 0 deletions chrome/src/webview/ui/toolbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import type {
ToolbarManagerInstance,
GenerateToolbarHTMLOptions
} from '../../../../src/types/index';
import { createRemarkMode } from '../../../../src/ui/remark-mode';
import type { RemarkModeController } from '../../../../src/ui/remark-mode';

// SVG icons for different layouts
export const layoutIcons: Record<string, string> = {
Expand Down Expand Up @@ -57,6 +59,9 @@ export function createToolbarManager(options: ToolbarManagerOptions): ToolbarMan
onToggleSourceMode,
getSourceMode,
isSourceModeActive,
enableRemarkMode,
getRemarkContainer,
getRemarkRawMarkdown,
} = options;

// Layout configurations
Expand All @@ -75,6 +80,33 @@ export function createToolbarManager(options: ToolbarManagerOptions): ToolbarMan
// Global zoom state
let currentZoomLevel = 100;

// Remark Mode controller
let remarkController: RemarkModeController | null = null;
if (enableRemarkMode && getRemarkContainer) {
remarkController = createRemarkMode({
getContainer: getRemarkContainer,
getRawMarkdown: getRemarkRawMarkdown || (() => rawMarkdown),
onModeChange: (isActive: boolean) => {
const btn = document.getElementById('toggle-remark-btn');
if (!btn) return;
btn.classList.toggle('remark-active', isActive);
const title = isActive
? (chrome.i18n?.getMessage('remark_exit_mode') || 'Exit Remark Mode')
: (chrome.i18n?.getMessage('remark_mode') || 'Remark Mode');
btn.title = title;
btn.setAttribute('aria-label', title);
btn.setAttribute('aria-pressed', String(isActive));
},
onAnnotationCountChange: (count: number) => {
const badge = document.getElementById('remark-count-badge');
if (badge) {
badge.textContent = count > 0 ? String(count) : '';
badge.style.display = count > 0 ? 'flex' : 'none';
}
},
});
}

async function exportDocxFromToolbar(): Promise<void> {
const downloadBtn = document.getElementById('download-btn') as HTMLButtonElement | null;
if (!downloadBtn || downloadBtn.disabled) {
Expand Down Expand Up @@ -374,6 +406,40 @@ export function createToolbarManager(options: ToolbarManagerOptions): ToolbarMan
sourceToggleBtn.addEventListener('click', () => {
onToggleSourceMode();
updateSourceToggleUI();
// Exit remark mode when entering source mode
if (getSourceMode() && remarkController?.isActive()) {
remarkController.exit();
updateRemarkToggleUI();
}
});
}

// Remark Mode toggle button
const remarkToggleBtn = document.getElementById('toggle-remark-btn');
function updateRemarkToggleUI(): void {
if (!remarkToggleBtn) return;
const isActive = remarkController?.isActive() ?? false;
remarkToggleBtn.classList.toggle('remark-active', isActive);
remarkToggleBtn.title = isActive
? (chrome.i18n?.getMessage('remark_exit_mode') || 'Exit Remark Mode')
: (chrome.i18n?.getMessage('remark_mode') || 'Remark Mode');
remarkToggleBtn.setAttribute('aria-label', remarkToggleBtn.title);
remarkToggleBtn.setAttribute('aria-pressed', String(isActive));
}

if (remarkToggleBtn && remarkController) {
// Load persisted annotations on init
void remarkController.loadAnnotations();
updateRemarkToggleUI();
remarkToggleBtn.addEventListener('click', () => {
if (remarkController!.isActive()) {
remarkController!.exit();
} else {
// Don't enter remark mode while in source mode
if (getSourceMode?.()) return;
remarkController!.enter();
}
updateRemarkToggleUI();
});
}

Expand Down Expand Up @@ -500,6 +566,7 @@ export function generateToolbarHTML(options: GenerateToolbarHTMLOptions): string
initialMaxWidth,
initialZoom,
enableSourceToggle,
enableRemarkMode,
} = options;

const toolbarLayoutTitleNormal = translate('toolbar_layout_title_normal');
Expand Down Expand Up @@ -564,6 +631,15 @@ export function generateToolbarHTML(options: GenerateToolbarHTMLOptions): string
</button>` : ''}
</div>
<div class="toolbar-right">
${enableRemarkMode ? `
<div style="position:relative;display:inline-flex;">
<button id="toggle-remark-btn" class="toolbar-btn" title="Remark Mode" aria-label="Remark Mode" aria-pressed="false">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor">
<path d="M13.5 3.5l3 3L7 16H4v-3L13.5 3.5Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<span id="remark-count-badge" class="remark-count-badge" style="display:none;position:absolute;top:2px;right:2px;background:#6b7280;color:#fff;font-size:9px;font-weight:700;min-width:14px;height:14px;border-radius:7px;align-items:center;justify-content:center;padding:0 3px;line-height:1;pointer-events:none;"></span>
</div>` : ''}
<button id="download-btn" class="toolbar-btn toolbar-menu-trigger" title="${downloadTitleAttr}" aria-haspopup="menu" aria-expanded="false">
<svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
<path d="M10 3v10m0 0l-3-3m3 3l3-3M3 16h14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
Expand Down Expand Up @@ -594,5 +670,6 @@ export function generateToolbarHTML(options: GenerateToolbarHTMLOptions): string
</div>
<div id="table-of-contents" class="${initialTocClass}"></div>
<div id="toc-overlay" class="hidden"></div>
<div id="remark-sidebar" class="remark-sidebar remark-sidebar-closed"></div>
`;
}
4 changes: 4 additions & 0 deletions chrome/src/webview/viewer-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,9 @@ export async function initializeViewerMain(options: ViewerMainOptions): Promise<
},
getSourceMode: () => sourceModeEnabled,
isSourceModeActive: () => (isMarkdownSourceToggleEnabled() && sourceModeEnabled) || renderState.codeView,
enableRemarkMode: true,
getRemarkContainer: () => document.getElementById('markdown-content'),
getRemarkRawMarkdown: () => liveRawContent,
});

toolbarManager.setInitialZoom(initialZoom);
Expand All @@ -737,6 +740,7 @@ export async function initializeViewerMain(options: ViewerMainOptions): Promise<
initialMaxWidth,
initialZoom,
enableSourceToggle: isMarkdownSourceToggleEnabled(),
enableRemarkMode: true,
});
if (!initialTocVisible) {
document.body.classList.add('toc-hidden');
Expand Down
64 changes: 64 additions & 0 deletions src/_locales/de/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,70 @@
"message": "Zuletzt geöffnet",
"description": "Title for recent files section"
},
"remark_add_note": {
"message": "Notiz hinzufügen…",
"description": "Placeholder for the note input in the annotation popup and sidebar"
},
"remark_cancel": {
"message": "Abbrechen",
"description": "Cancel button in the annotation popup"
},
"remark_color_blue": {
"message": "Frage",
"description": "Label for the blue annotation color"
},
"remark_color_green": {
"message": "Behalten",
"description": "Label for the green annotation color"
},
"remark_color_pink": {
"message": "Bedenken",
"description": "Label for the pink annotation color"
},
"remark_color_yellow": {
"message": "Vorschlag",
"description": "Label for the yellow annotation color"
},
"remark_copied": {
"message": "Kopiert!",
"description": "Feedback shown after remarks are successfully copied"
},
"remark_copy_btn": {
"message": "Anmerkungen kopieren",
"description": "Button label to copy all remarks to clipboard and exit Remark Mode"
},
"remark_copy_failed": {
"message": "Fehler",
"description": "Feedback shown when copying remarks fails"
},
"remark_copy_tooltip": {
"message": "Alle Anmerkungen in die Zwischenablage kopieren und den Anmerkungsmodus beenden",
"description": "Tooltip for the Copy remarks button"
},
"remark_edit_note": {
"message": "Zum Bearbeiten klicken",
"description": "Tooltip on a remark note in the sidebar indicating it is editable"
},
"remark_empty": {
"message": "Text auswählen, um Anmerkungen hinzuzufügen",
"description": "Placeholder shown in sidebar when no remarks exist"
},
"remark_exit_mode": {
"message": "Anmerkungsmodus beenden",
"description": "Toolbar button tooltip to exit Remark Mode"
},
"remark_mode": {
"message": "Anmerkungsmodus",
"description": "Toolbar button tooltip to enter Remark Mode"
},
"remark_save": {
"message": "Speichern",
"description": "Save button in the annotation popup"
},
"remark_sidebar_title": {
"message": "Anmerkungen",
"description": "Title of the Remark Mode sidebar panel"
},
"remove_from_list": {
"message": "Aus Liste entfernen",
"description": "Menu item to remove file from recent list"
Expand Down
64 changes: 64 additions & 0 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,70 @@
"message": "Recent Files",
"description": "Title for recent files section"
},
"remark_add_note": {
"message": "Add a note…",
"description": "Placeholder for the note input in the annotation popup and sidebar"
},
"remark_cancel": {
"message": "Cancel",
"description": "Cancel button in the annotation popup"
},
"remark_color_blue": {
"message": "Question",
"description": "Label for the blue annotation color"
},
"remark_color_green": {
"message": "Keep",
"description": "Label for the green annotation color"
},
"remark_color_pink": {
"message": "Concern",
"description": "Label for the pink annotation color"
},
"remark_color_yellow": {
"message": "Suggestion",
"description": "Label for the yellow annotation color"
},
"remark_copied": {
"message": "Copied!",
"description": "Feedback shown after remarks are successfully copied"
},
"remark_copy_btn": {
"message": "Copy remarks",
"description": "Button label to copy all remarks to clipboard and exit Remark Mode"
},
"remark_copy_failed": {
"message": "Failed",
"description": "Feedback shown when copying remarks fails"
},
"remark_copy_tooltip": {
"message": "Copy all remarks to clipboard, then exit Remark Mode",
"description": "Tooltip for the Copy remarks button"
},
"remark_edit_note": {
"message": "Click to edit",
"description": "Tooltip on a remark note in the sidebar indicating it is editable"
},
"remark_empty": {
"message": "Select text to add remarks",
"description": "Placeholder shown in sidebar when no remarks exist"
},
"remark_exit_mode": {
"message": "Exit Remark Mode",
"description": "Toolbar button tooltip to exit Remark Mode"
},
"remark_mode": {
"message": "Remark Mode",
"description": "Toolbar button tooltip to enter Remark Mode"
},
"remark_save": {
"message": "Save",
"description": "Save button in the annotation popup"
},
"remark_sidebar_title": {
"message": "Remarks",
"description": "Title of the Remark Mode sidebar panel"
},
"remove_from_list": {
"message": "Remove from list",
"description": "Menu item to remove file from recent list"
Expand Down
64 changes: 64 additions & 0 deletions src/_locales/es/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,70 @@
"message": "Archivos recientes",
"description": "Title for recent files section"
},
"remark_add_note": {
"message": "Añadir nota…",
"description": "Placeholder for the note input in the annotation popup and sidebar"
},
"remark_cancel": {
"message": "Cancelar",
"description": "Cancel button in the annotation popup"
},
"remark_color_blue": {
"message": "Pregunta",
"description": "Label for the blue annotation color"
},
"remark_color_green": {
"message": "Mantener",
"description": "Label for the green annotation color"
},
"remark_color_pink": {
"message": "Preocupación",
"description": "Label for the pink annotation color"
},
"remark_color_yellow": {
"message": "Sugerencia",
"description": "Label for the yellow annotation color"
},
"remark_copied": {
"message": "¡Copiado!",
"description": "Feedback shown after remarks are successfully copied"
},
"remark_copy_btn": {
"message": "Copiar anotaciones",
"description": "Button label to copy all remarks to clipboard and exit Remark Mode"
},
"remark_copy_failed": {
"message": "Error",
"description": "Feedback shown when copying remarks fails"
},
"remark_copy_tooltip": {
"message": "Copiar todas las anotaciones al portapapeles y salir del modo anotación",
"description": "Tooltip for the Copy remarks button"
},
"remark_edit_note": {
"message": "Haz clic para editar",
"description": "Tooltip on a remark note in the sidebar indicating it is editable"
},
"remark_empty": {
"message": "Selecciona texto para añadir anotaciones",
"description": "Placeholder shown in sidebar when no remarks exist"
},
"remark_exit_mode": {
"message": "Salir del modo anotación",
"description": "Toolbar button tooltip to exit Remark Mode"
},
"remark_mode": {
"message": "Modo anotación",
"description": "Toolbar button tooltip to enter Remark Mode"
},
"remark_save": {
"message": "Guardar",
"description": "Save button in the annotation popup"
},
"remark_sidebar_title": {
"message": "Anotaciones",
"description": "Title of the Remark Mode sidebar panel"
},
"remove_from_list": {
"message": "Eliminar de la lista",
"description": "Menu item to remove file from recent list"
Expand Down
Loading