Fix translations, center logo/footer, add tile zoom control
Build and Deploy Verso / deploy (push) Successful in 14m8s
Build and Deploy Verso / deploy (push) Successful in 14m8s
- 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>
This commit is contained in:
@@ -9,7 +9,7 @@ block content
|
||||
.container
|
||||
.row
|
||||
.col-12
|
||||
.text-center.mb-4
|
||||
.lumiere-logo-center.mb-4
|
||||
img.verso-login-logo(
|
||||
src=buildImgPath('ol-brand/verso-logo.svg')
|
||||
alt='Verso'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { memo, useCallback, useEffect, useRef } from 'react'
|
||||
import React, { memo, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useProjectListContext } from '../context/project-list-context'
|
||||
import { Project } from '../../../../../types/project/dashboard/api'
|
||||
@@ -28,6 +28,46 @@ import { CompileAndDownloadProjectPDFButtonTooltip } from './table/cells/action-
|
||||
import { ArchiveProjectButtonTooltip } from './table/cells/action-buttons/archive-project-button'
|
||||
import { TrashProjectButtonTooltip } from './table/cells/action-buttons/trash-project-button'
|
||||
|
||||
// ── Tile zoom ─────────────────────────────────────────────────────────────────
|
||||
|
||||
type ZoomLevel = 0.75 | 1 | 1.35
|
||||
const ZOOM_OPTIONS: { value: ZoomLevel; label: string }[] = [
|
||||
{ value: 0.75, label: 'S' },
|
||||
{ value: 1, label: 'M' },
|
||||
{ value: 1.35, label: 'L' },
|
||||
]
|
||||
const ZOOM_STORAGE_KEY = 'lumiere-card-scale'
|
||||
|
||||
function useLumiereCardScale(): [ZoomLevel, (z: ZoomLevel) => void] {
|
||||
const [scale, setScale] = useState<ZoomLevel>(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem(ZOOM_STORAGE_KEY)
|
||||
if (stored) {
|
||||
const val = parseFloat(stored)
|
||||
if ((ZOOM_OPTIONS.map(o => o.value) as number[]).includes(val)) {
|
||||
return val as ZoomLevel
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// storage unavailable
|
||||
}
|
||||
return 1
|
||||
})
|
||||
|
||||
const updateScale = useCallback((z: ZoomLevel) => {
|
||||
setScale(z)
|
||||
try {
|
||||
localStorage.setItem(ZOOM_STORAGE_KEY, String(z))
|
||||
} catch (_) {
|
||||
// ignore
|
||||
}
|
||||
}, [])
|
||||
|
||||
return [scale, updateScale]
|
||||
}
|
||||
|
||||
// ── Format helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
type FormatVariant = 'latex' | 'typst' | 'quarto' | 'quarto-slides'
|
||||
|
||||
function getFormatVariant(
|
||||
@@ -137,6 +177,7 @@ export function ProjectListLumiere() {
|
||||
const navbarProps = getMeta('ol-navbar')
|
||||
const footerProps = getMeta('ol-footer')
|
||||
const { t } = useTranslation()
|
||||
const [cardScale, setCardScale] = useLumiereCardScale()
|
||||
const {
|
||||
error,
|
||||
visibleProjects,
|
||||
@@ -206,6 +247,23 @@ export function ProjectListLumiere() {
|
||||
filter={filter}
|
||||
selectedTag={selectedTag}
|
||||
/>
|
||||
<div
|
||||
className="lumiere-zoom-control"
|
||||
role="group"
|
||||
aria-label="Taille des cartes"
|
||||
>
|
||||
{ZOOM_OPTIONS.map(({ value, label }) => (
|
||||
<button
|
||||
key={value}
|
||||
type="button"
|
||||
className={`lumiere-zoom-btn${cardScale === value ? ' active' : ''}`}
|
||||
onClick={() => setCardScale(value)}
|
||||
aria-pressed={cardScale === value}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<NewProjectButton
|
||||
id="lumiere-new-project-button"
|
||||
showAddAffiliationWidget
|
||||
@@ -241,7 +299,11 @@ export function ProjectListLumiere() {
|
||||
{visibleProjects.length === 0 ? (
|
||||
<p className="lumiere-empty">{t('no_projects')}</p>
|
||||
) : (
|
||||
<div className="lumiere-card-grid">
|
||||
<div
|
||||
className="lumiere-card-grid"
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
style={{ '--lum-card-scale': cardScale } as React.CSSProperties}
|
||||
>
|
||||
{visibleProjects.map(project => (
|
||||
<ProjectCard key={project.id} project={project} />
|
||||
))}
|
||||
|
||||
@@ -57,7 +57,10 @@ i18n.use(initReactI18next).init({
|
||||
const localesPromise = import(
|
||||
/* webpackChunkName: "[request]" */ `../../locales/${LANG}.json`
|
||||
).then(lang => {
|
||||
i18n.addResourceBundle(LANG, 'translation', lang)
|
||||
// webpack dynamic JSON imports return a module object { default: JSON },
|
||||
// not the raw JSON — unwrap if needed.
|
||||
const data = lang.default ?? lang
|
||||
i18n.addResourceBundle(LANG, 'translation', data)
|
||||
i18n.addResourceBundle(
|
||||
LANG,
|
||||
'writefull',
|
||||
|
||||
@@ -44,10 +44,17 @@
|
||||
background-color: #f0faf8;
|
||||
min-height: 100vh;
|
||||
|
||||
// Flex wrapper replaces .text-center so the block image centers reliably.
|
||||
.lumiere-logo-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.verso-login-logo {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 520px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +62,10 @@
|
||||
// Same light-teal treatment as the project page footer.
|
||||
body:has(.login-page) footer.site-footer {
|
||||
position: relative;
|
||||
|
||||
.site-footer-content > .row {
|
||||
align-items: center;
|
||||
}
|
||||
background-color: #edf7f4 !important;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.28'/%3E%3C/svg%3E") !important;
|
||||
background-size: 200px 200px !important;
|
||||
|
||||
@@ -398,12 +398,51 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi
|
||||
// ── Card grid ─────────────────────────────────────────────────────────────
|
||||
|
||||
.lumiere-card-grid {
|
||||
--lum-card-scale: 1;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||
grid-template-columns: repeat(auto-fill, minmax(calc(180px * var(--lum-card-scale)), 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
// ── Zoom control (S / M / L card-size picker) ─────────────────────────────
|
||||
|
||||
.lumiere-zoom-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border: 1px solid $lum-border;
|
||||
border-radius: 7px;
|
||||
padding: 2px;
|
||||
gap: 1px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.lumiere-zoom-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
padding: 3px 9px;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
color: $lum-text-sub;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
transition: background-color 0.12s ease, color 0.12s ease;
|
||||
letter-spacing: 0.05em;
|
||||
|
||||
&:hover {
|
||||
background: rgba($lum-teal, 0.1);
|
||||
color: $lum-teal;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #fff;
|
||||
color: $lum-teal;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Card wrapper (checkbox + link) ────────────────────────────────────────
|
||||
|
||||
.lumiere-card-wrapper {
|
||||
@@ -518,7 +557,7 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi
|
||||
|
||||
.lumiere-card-thumb {
|
||||
position: relative;
|
||||
height: 130px;
|
||||
height: calc(130px * var(--lum-card-scale, 1));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -728,6 +767,10 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi
|
||||
|
||||
.project-list-lumiere footer.site-footer {
|
||||
position: relative;
|
||||
|
||||
.site-footer-content > .row {
|
||||
align-items: center;
|
||||
}
|
||||
background-color: #edf7f4 !important;
|
||||
background-image: #{$lum-noise} !important;
|
||||
background-size: 200px 200px !important;
|
||||
|
||||
Reference in New Issue
Block a user