Editor:
- Auto-collapse the file-tree rail on mobile so the editor+PDF panels
occupy the full screen width instead of sharing it with a 15% sidebar.
The user can still open the rail from the toolbar; the collapse only
fires on first load or when switching to a mobile viewport.
Project page (Lumiere):
- Move the XS/M/L zoom buttons from the mobile filter-pill toolbar into
a row with the New Project button, so neither is stranded alone.
- The search bar gets its own full-width row above the actions row.
- Desktop layout is unchanged (search + new-project stay side-by-side;
zoom stays in the title row). `display:contents` makes the wrapper
div transparent to the desktop flex container.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tor Browser and Firefox with privacy.resistFingerprinting report a
desktop-sized viewport (~980px) even on a real Android phone. This made
window.matchMedia('(max-width: 767px)') return false, so isMobile was
always false on Tor, leaving the editor in side-by-side (horizontal)
layout instead of the expected vertical stack.
Fix: add a secondary check using `(pointer: coarse) and (max-width:
1024px)`. Touch hardware is not spoofed by fingerprinting resistance,
so this reliably catches phones and tablets regardless of the reported
viewport width. Applied to both getInitialLayout() and the live
isMobile state in main-layout.tsx.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Email:
- Replace Overleaf green palette with Verso teal (#2a9d8f) for CTA
buttons, links, and logo text
- Rename force-overleaf-style CSS class to force-verso-style in all
email body templates and layout
- Replace all user-visible "Overleaf" strings with settings.appName
across email subjects, bodies, and sign-offs (EmailBuilder.mjs)
- Remove Overleaf CEO signature from onboarding email; substitute
"The Verso Team"
- Fix utm_source=overleaf → utm_source=verso in onboarding links
- Point git token docs URL to local siteUrl instead of docs.overleaf.com
- Fix hard-coded Overleaf green (#0F7A06) in SSO disabled email link
Mobile filter chips:
- Switch from overflow-x:auto (still leaks through ancestor flex chain)
to flex-wrap:wrap with flex:1 1 auto on each chip so all chips in a
row grow to equal width — no overflow, clean alignment
- Toolbar becomes flex-column: chips on top, zoom below-right
Misc:
- Remove import_typst_file option from new-project menu
- Add interface_language to extracted-translations.json whitelist
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CLSI thumbnails: bump to 794px/q90 (matches preview quality) for
crisp display on 2x/3x phone screens
- Lumière filter chips → underline tab bar: single scrollable row with
teal active indicator, no more wrapping alignment issues; zoom buttons
separated by a vertical divider on the right
- Fix editor vertical split default on mobile: disable react-resizable-panels
autoSaveId on mobile to prevent a stale collapsed PDF pane from firing
onCollapse → changeLayout('flat') and overriding the verticalSplit
default set by getInitialLayout()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Overflow fix: ActionsCell (up to 9 icon buttons) was assigned to the
`auto` column in the compact row, blowing out the row to ~300px.
Replace with ActionsDropdown (single ⋮ button) on mobile via
d-md-none / d-none d-md-flex, same pattern as the classic table.
Tile view: remove the isMobile force to compact (effectiveScale=0).
Add a mobile-only toolbar row (d-flex d-md-none) combining the filter
pills and a new XS/M/L zoom control:
- XS (scale=0) → compact rows
- M (scale=1) → 2 tiles per row (CSS: repeat(2, 1fr))
- L (scale≥1.35) → 1 tile per row (CSS: 1fr, class --mobile-1col)
The --lum-card-scale inline var is suppressed on mobile so CSS media
query controls thumbnail height (0.85 for 2-col, 1.3 for 1-col).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Compact row (xs): wrap format/owner/date in a lumiere-compact-meta div
that uses display:contents on desktop (preserving the 6-column grid) and
switches to a 2-row grid layout on mobile — row 1: checkbox/name/actions,
row 2: format·owner·date. Actions are always visible on touch devices.
Filter access: add a horizontal scrollable filter-pill bar (d-md-none)
to the Lumière header so users can switch between All/Yours/Shared/Archived/
Trashed on phone without needing the desktop sidebar.
Also: hide zoom control on mobile (d-md-none), auto-force compact view on
mobile via useIsMobile hook, fix search form min-width overflow on xs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Convert: backend now returns parentFolderId+isNew; frontend calls
dispatchCreateDoc directly so the new file appears without a page refresh
- Set as main: infer compiler from file extension and POST both rootDocId
and compiler together; updateProject propagates the change to the
editor settings dropdown and project list immediately
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Set as main document (context menu):
- canSetRootDocId used selectedEntityIds so .typ/.qmd files couldn't be
set as main via right-click on an unselected file.
Now computed locally from contextMenuEntityId (same pattern as convert)
using isValidTeXFile which already covers .typ, .qmd, .tex etc.
Compiler filter (editor settings):
- docs?.find(id) could return undefined due to ID format mismatch,
causing all engines to show as available for non-LaTeX projects.
Added findInTree fallback so the root doc name is always resolved.
ZIP import compiler:
- Projects created from ZIP always got defaultLatexCompiler ('quarto')
regardless of content.
- findRootDocFileFromDirectory now also searches for .typ and .qmd root
files after finding no .tex file.
- ProjectUploadManager now infers the compiler from the root doc
extension and sets it on the project after import.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
canRename required selectedEntityIds.size === 1, so right-clicking an
unselected file hid the convert items even though contextMenuEntityId
was correctly set. Replace canRename with !fileTreeReadOnly for the
convert-specific gate, which is the actual write-access check needed.
Also add showExportDocumentSuccess so the user sees the warning toast
on successful conversion instead of silent nothing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs:
1. Converting when output already exists threw DuplicateNameError (400).
Now overwrites existing doc via setDocument instead of failing.
2. Right-clicking an unselected file left contextMenuEntityId null,
so the first click on Convert silently did nothing. Added
contextMenuEntityId to FileTreeMainContext, set it on right-click
and on the … button click; FileTreeItemMenuItems now uses it for
the convert hooks rather than relying on selectedEntityIds.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
postJSON without options sends Content-Type: application/json with no
body; body-parser's BodyParserWrapper intercepts the resulting
SyntaxError and returns 400 before the route handler runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add "Convert to Typst (.typ)" in the file tree context menu for .tex
docs, and "Convert to LaTeX (.tex)" for .typ docs. Clicking runs pandoc
on the file content and creates the converted file in the same folder.
- New backend endpoint POST /project/:id/doc/:id/convert/:type that reads
the doc from document-updater, runs pandoc directly, and creates the
result via ProjectEntityUpdateHandler (file tree updates via socket).
- Rewrite the export success toast for typst and latex conversions: no
more link to /contact, replaced with a plain warning that errors are
expected (pandoc does not support all constructs).
- Add i18n keys: convert_to_typst, convert_to_latex,
typst_export_feedback_message, latex_export_feedback_message (EN + FR)
and all four to extracted-translations.json.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- clsi-nginx: allow hyphens in project-id regex — conversion IDs are UUIDs
which nginx was rejecting, causing 500 on file download after conversion
- CLSI ConversionController/Manager: add 'latex' export type (typst→latex via pandoc)
- Web: add 'latex' to SUPPORTED_CONVERSION_TYPES
- Frontend: add Export as LaTeX button (visible only for typst projects)
- Fix visibility logic: export-as-latex shows for typst, export-as-typst shows for latex
- Add export_as_latex translation key (en + fr)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ConversionController.js: add typst to CONVERSION_CONFIGS (missing entry caused 400→500 chain)
- export-project-with-conversion-button: hide button for non-LaTeX projects (typst/quarto) via compiler check
- project-list-lumiere.tsx + scss: revert lumiere-card-actions back inside .lumiere-card (put them back like they were)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Typst → LaTeX import:
- CLSI ConversionManager: add 'typst' to CONVERSION_CONFIGS
(pandoc input.typ --from typst --to latex --standalone → zip archive)
- Web controller: allow 'typst' as a valid importDocument conversion type
- Frontend modal: add .typ file config to ImportDocumentModal
- New project button modal: add 'import_typst' variant + switch case
- New project button: show "Import Typst file" when enablePandocConversions
is true (no split test gate — Verso has no SaaS split test infra)
- Locales: add choose_typst_file and import_typst_file keys (18 locales)
Export button fix:
- Remove featureFlag="export-typst" from ExportProjectWithConversionButton
so the button shows whenever enablePandocConversions is true, without
needing an unconfigured split test to return 'enabled'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a new "Export as Typst" option in the project title dropdown and
File menu, mirroring the existing docx/markdown/html export pipeline.
Changes:
- CLSI ConversionManager: add 'typst' to LATEX_EXPORT_CONFIGS
(compressOutput: false, pandoc --from latex --to typst)
- Web controller: register 'typst' → 'typ' in SUPPORTED_CONVERSION_TYPES
- Frontend: extend conversionType union and add ExportProjectWithConversionButton
- File menu: add 'export-as-typst' to the download group command structure
- Locales: add export_as_typst key to all 18 locale files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The DropdownHeader in the View > Layout menu was using a raw English
string instead of t('editor_settings'). Added the key to all 18 locale
files with appropriate translations.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Popper lazy-initializes on first open, causing it to place the menu at
[0,0] before it has computed the toggle's position. renderOnMount forces
Popper to initialize while the component is first mounted, so the
position is ready before the user's first click.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
.lumiere-card has both backdrop-filter and a hover transform, both of
which create a new containing block for position:fixed descendants,
trapping Popper dropdowns inside the card's overflow:hidden bounds.
Fix: move .lumiere-card-actions outside .lumiere-card (sibling inside
.lumiere-card-wrapper, which has position:relative but no filter or
transform). The actions strip is now absolutely positioned at the card
bottom with its own solid background and bottom border-radius.
No backdrop-filter on the strip to avoid re-introducing the same trap.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ProjectCard in the Lumiere tile view always showed CompileAndDownloadProjectPDFButtonTooltip,
ignoring the project compiler. Quarto presentation projects need the
DownloadPresentationButtonTooltip (HTML/PDF dropdown) instead, matching
the logic already in actions-cell.tsx and actions-dropdown.tsx.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
layout-context: getInitialLayout() was returning verticalSplit for
any stored 'vertical' preference, including on desktop. Now checks
isMobile first so stored mobile preference doesn't bleed into PC.
compile-and-download-pdf: when compile succeeds but output.pdf is
absent from outputFiles, the code crashed silently at outputFile.build
leaving the user with no feedback. Now shows the error modal instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Footer: use translate('built_on') key instead of hardcoded 'Built on';
update fr.json 'built_on' → 'Basé sur Overleaf'
- Mobile project list: move search bar + button outside the bordered
TableContainer so its width is viewport-constrained, not affected by
the table's fixed layout
- Mobile table rows: use width:100% (not auto) on cells so they fill the
full tr width regardless of the higher-specificity column percentage
rules; add explicit width:100% on tr to anchor flex-column sizing;
keep width:auto on absolutely-positioned actions cell
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
quartoFlavor is set only after a project is compiled with the current
build. Existing Quarto projects that haven't been recompiled have
quartoFlavor=undefined, so the old check (quartoFlavor === 'revealjs')
fell through to the regular PDF compile button with no dropdown.
Drop the quartoFlavor guard — compiler === 'quarto' is sufficient since
all Quarto projects in Verso are RevealJS presentations. Changes applied
to ActionsCell (desktop icon), DownloadPresentationButtonTooltip guard,
and ActionsDropdown (mobile three-dot menu).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Search bar overflow: min-width:0 on form prevents input min-content
from overflowing flex container on narrow screens
- Remove duplicate New Project button from header row (tableTopArea
already provides it for mobile)
- Simplify tableTopArea: single button+search layout regardless of
isLibraryEnabled flag
- 2-line project rows on mobile: merge dash-cell-date-owner +
dash-cell-tag into a single dash-cell-meta so date/owner/tags flow
inline on line 2 below the project name
- Footer mobile: hide language-picker-text on mobile (icon only) to
prevent 3rd line in 2-row footer
- Language picker: use mousedown instead of click for outside-close
handler — click bubbling is unreliable on iOS for non-interactive
elements; mousedown fires for all taps
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Mobile vertical layout: add key= based on direction so react-resizable-panels
remounts cleanly when switching between horizontal and vertical; also use
isVertical (not just pdfLayout) for the autoSaveId to avoid restoring a
mismatched layout from localStorage
- Language picker: replace stopPropagation pattern with a containment check on
the document click handler — more robust on React pages where Bootstrap JS or
React's event delegation can interfere with stopPropagation
- Presentation download dropdown: use popperConfig strategy:'fixed' so the menu
escapes overflow:hidden table cells; remove forced drop='up' and let Popper
choose; defer URL.revokeObjectURL by 10 s to give the browser time to start
the download before the blob URL is released
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On mobile (< 768 px) the existing side-by-side layout automatically switches
to a vertical stack (editor on top, PDF/presentation on bottom) without
changing the stored layout preference.
A new "Top / bottom split" option is added to the layout menu so desktop
users can choose the same vertical split explicitly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Using the generic 'download' icon duplicated the ZIP button icon,
giving two identical icons side by side. Switch to picture_as_pdf to
match the previous compile-and-download button's appearance.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Quarto Slides (RevealJS) projects compile to output.html, not output.pdf,
so the existing "Download PDF" button was meaningless for them. Replace it
with a two-option dropdown matching the editor's PdfHybridDownloadButton:
- Desktop (ActionsCell): icon button opens a dropup with
"Download standalone HTML" and "Download PDF slides"
- Mobile (ActionsDropdown): two separate dropdown items with the same
choices and per-format spinner while the export is in progress
Both use the same /project/:id/presentation-export/:format endpoint and
show a loading modal (with error reporting) during the server-side render,
exactly as the editor toolbar does.
Non-RevealJS projects continue to show the compile-and-download-PDF button
unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Footer (both React and Pug):
- Below md: switch to flex-wrap so items wrap naturally instead of
overflowing; reset line-height from the fixed 49px to normal; add
row-gap so wrapped rows aren't crammed together
- Add footer-sep class to pipe separator <li>s so they can be hidden
on small screens (wrapping mid-separator looks wrong)
- Change col-lg-3 text-end → text-lg-end so the right column (licence,
source code) aligns left when it stacks full-width below lg
Project list:
- Show NewProjectButton on mobile in the header row (the sidebar that
holds the button is already hidden below md via d-none d-md-flex,
leaving users with no way to create projects on their phone)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rewrites LanguagePicker to use availableLanguages from ol-footer meta
instead of subdomainLang (which is always empty in single-domain setup)
- Passes availableLanguages through layout-react.pug → ol-footer meta so
React footer picks it up
- Adds InterfaceLanguageSetting component to the editor settings modal
("Spelling and language" tab) for use when no footer is present
- Adds interface_language key to all five locale files (en/fr/de/es/it)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Uploads from slow connections consistently fail with 502 after ~60-120s
because an upstream proxy (Traefik or cloud load-balancer) has a
"first response byte" deadline that fires before the request body arrives.
Fix: add startStreamingResponse middleware (after auth, before multer)
that immediately writes HTTP 200 + Transfer-Encoding: chunked + '\n'.
With proxy_request_buffering off in Nginx, this reaches the proxy at T≈0,
so no timeout triggers. The upload body continues streaming; multer writes
to disk; the actual JSON result arrives as the final chunk. Periodic
heartbeat '\n' writes every 30s keep response-idle timeouts at bay too.
Client-side: override Uppy's getResponseData/validateStatus to trim
leading whitespace before JSON.parse so the extra '\n' bytes are ignored.
Server-side: sendUploadResponse() helper handles both streaming mode
(res.headersSent → res.end(json)) and normal mode (res.status(N).json()).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- XS compact row: format column 70px→96px so "QUARTO SLIDES" stays on one line;
trim owner/date cols slightly to compensate
- Welcome page (0 projects): Lumière branch now renders before the 0-projects
check; ProjectListLumiere renders WelcomePageContent when totalProjectsCount=0
so new users get the full onboarding experience in the Lumière shell
- 404 page: notFound() now detects the user's overallTheme and passes isLumiere
to the template; layout-base.pug sets data-lumiere on the body; error-pages.scss
and project-list-lumiere.scss add [data-lumiere='true'] rules for the body
background gradient, navbar white+stripe, and styled error box
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
JSDoc blocks in typst-decorations.ts and quarto-decorations.ts contained
*/ sequences inside them, which Babel's parser treats as terminating the
block comment prematurely.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add typst-decorations.ts ViewPlugin that runs alongside the existing
LaTeX visual decorations. For Typst files in visual mode it:
- Hides *…* markers and applies font-weight:700 to the StrongBody
- Hides _…_ markers and applies font-style:italic to the EmphBody
- Hides = prefix marks and applies heading CSS (h1–h6 font sizes)
- Hides backtick delimiters and applies monospace to RawInlineContent
Markers reappear when the cursor enters the node (selectionSet trigger).
Register CSS rules for .ol-cm-typst-{strong,emph,heading,h1-h6,raw-inline}
in visual-theme.ts. Wire the plugin into visual.ts after markDecorations.
The visual editor toggle was already available for .typ files since 'typ'
is in validRootDocExtensions — no gating change needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the CSS-only compact card hack with a dedicated
ProjectCardCompact component that reuses FormatCell, OwnerCell,
LastUpdatedCell (with tooltip + updated-by), ActionsCell (full set),
and InlineTags — identical data to the classic table view. CSS Grid
aligns columns across rows: checkbox | name+tags | format | owner |
date | actions. Actions fade in on row hover.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Search bar: set min-width: 300px so the placeholder text is fully
visible. XS zoom level (value 0): adds lumiere-card-grid--compact class
which switches cards to horizontal rows, hides the thumbnail, and shows
only name / badge / owner / date / actions in a compact strip. Stored
0.75 from old S already fell back to 1 (S); new 0 is cleanly additive.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Old S (0.75×) removed — too small. Old M→S (1×), old L→M (1.35×),
new L added at 1.75×. Stored 0.75 in localStorage falls back to 1×.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace Overleaf icons with Verso branding on setPassword.pug
(square icon) and primaryEmailCheck.pug (wordmark). Replace hardcoded
French aria-label "Taille des cartes" on zoom control with t('card_size')
and add card_size key to all 5 locale files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Card owner: "You" now goes through t('you') so it renders as
"Vous"/"Tu"/"Du" etc. instead of always "You"
- Relative dates (fromNow): moment.locale() is now set from the app
language so "2 days ago" becomes "il y a 2 jours" etc.
- Footer: "Built on", "Source code", "AGPL licence" are now translated
via t() with keys added to all locale files and extracted-translations
- New keys: built_on, source_code, agpl_licence (FR/DE/IT/ES translations
added manually)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
S/M/L buttons now appear inline with the page title rather than in the
action bar. Bootstrap tooltips get pointer-events:none so they can no
longer steal :hover from the card beneath them, preventing the lift
animation from flickering when hovering over tag dots.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- i18n: unwrap webpack module object on dynamic JSON import (lang.default ?? lang)
so French bundle keys are correctly registered in the i18next store
- Login logo: use flex centering on wrapper instead of display:block + margin:auto
- Footer (project list + login): align-items:center on .row for vertical centering
- Tile zoom: S/M/L control in header with CSS custom property (--lum-card-scale)
that scales grid column width and card thumbnail height; persisted in localStorage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Footer: remove font-size/letter-spacing overrides so the browser
default applies; monospace right col keeps its uppercase + tracking
but no longer shrinks the font
- Card tags: move coloured dots into the .lumiere-card-meta flex row
instead of a separate div — zero added height, all cards uniform
- Card tags tooltip: replace native title attr with OLTooltip (React
Bootstrap tooltip) for a consistent Verso look on hover
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Footer: pale teal (#edf7f4) with noise grain instead of dark navy;
serif author credit darker (#1a2e3b), right col monospace muted;
teal→blue 2px stripe preserved; same treatment on login page
- Card tags: render as 8px coloured dots only (title attr for tooltip)
— no text means no wrapping, consistent card heights across the grid
- i18n fr.json: add deselect_all → "Tout désélectionner"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Footer: dark navy (#0d1b24) with noise texture, teal→blue gradient
top stripe; serif author credit on the left, monospace/uppercase
meta links on the right; same design on login page
- Thumbnail: larger inset (14px top, 12px sides) so more background
gradient shows around the preview; subtle drop shadow added
- Card tags: projects now show their label chips on the card (colored
dot + name, read-only, max 3, no close button inside the link)
- Selection bar: btn-secondary recoloured to Lumière palette; dropdown
menus rounded with teal accent on hover
- i18n fr.json: add n_projects_selected, n_projects_selected_plural,
toolbar_selected_projects (×4 variants)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After a successful compile, web service calls a new CLSI endpoint
(GET /project/:id/user/:uid/build/:bid/thumbnail) which runs pdftocairo
page-1 to a 190px-wide JPEG using the existing thumbnail preset. The
JPEG is stored in Redis (90-day TTL, overwritten on next compile) by
the new ThumbnailManager.
GET /project/:Project_id/thumbnail serves the cached JPEG to authenticated
users, returning 404 when no thumbnail exists. Project cards in the
Lumière grid show the image overlaying the coloured gradient tile; if
the image 404s (project never compiled or cache expired) the onerror
handler hides it and the gradient + initial letter shows through.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restructures ProjectCard so the card is a <div> container instead of <a>
(buttons cannot be nested inside anchor elements). A .lumiere-card-link
anchor wraps the thumb+body area; a .lumiere-card-actions strip sits below
it and fades in on hover.
Buttons added (reusing the same tooltip components as the classic table):
- Copy project (opens CloneProjectModal)
- Download project zip
- Compile & download PDF
- Archive project (skipped when already archived)
- Trash project (skipped when already trashed)
Action icons are coloured $lum-text-muted at rest and shift to $lum-teal
on hover, matching the Lumière palette.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each project card now has a checkbox (top-left corner, semi-transparent by
default, fully opaque on hover). When any card is selected a selection bar
slides in above the grid showing: select-all checkbox, count, the existing
bulk-action toolbar (archive, trash, tags, delete), and a deselect-all button.
:has(input:checked) keeps all checkboxes visible once a selection is active.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- en.json: replace 'Overleaf' with 'Verso' in 6 user-visible strings
(email_already_registered, add_manager_user_not_found, compile_timeout,
download_metadata, to_confirm_email address, welcome_opening_workspace)
- groups-and-enterprise-banner: use dynamic appName instead of hard-coded
'Overleaf'
- SidebarLowerSection: add showAccountIcons prop (default true); set false
in project dashboard sidebar — account menu is already in the top-right
navbar, so the bottom-left duplicate is removed for all themes
- ds-nav-verso-logo: replace opacity-fade hover with scale+brightness
transform so logo is fully visible at rest
- Lumière: scope new-project-dropdown sidebar padding to avoid misaligning
the button when it appears next to the search bar in the header
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>