feat: consolidate to single Architectural Grid view and remove all notesViewMode logic
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m6s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m6s
This commit is contained in:
@@ -8,19 +8,11 @@ export default async function HomePage() {
|
|||||||
getAISettings(),
|
getAISettings(),
|
||||||
])
|
])
|
||||||
|
|
||||||
const notesViewMode =
|
|
||||||
settings?.notesViewMode === 'masonry'
|
|
||||||
? ('masonry' as const)
|
|
||||||
: settings?.notesViewMode === 'tabs'
|
|
||||||
? ('tabs' as const)
|
|
||||||
: ('masonry' as const)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HomeClient
|
<HomeClient
|
||||||
initialNotes={allNotes}
|
initialNotes={allNotes}
|
||||||
initialSettings={{
|
initialSettings={{
|
||||||
showRecentNotes: settings?.showRecentNotes !== false,
|
showRecentNotes: settings?.showRecentNotes !== false,
|
||||||
notesViewMode,
|
|
||||||
noteHistory: settings?.noteHistory === true,
|
noteHistory: settings?.noteHistory === true,
|
||||||
noteHistoryMode: (settings?.noteHistoryMode ?? 'manual') as 'manual' | 'auto',
|
noteHistoryMode: (settings?.noteHistoryMode ?? 'manual') as 'manual' | 'auto',
|
||||||
aiAssistantEnabled: settings?.paragraphRefactor !== false,
|
aiAssistantEnabled: settings?.paragraphRefactor !== false,
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ export type UserAISettingsData = {
|
|||||||
preferredLanguage?: 'auto' | 'en' | 'fr' | 'es' | 'de' | 'fa' | 'it' | 'pt' | 'ru' | 'zh' | 'ja' | 'ko' | 'ar' | 'hi' | 'nl' | 'pl'
|
preferredLanguage?: 'auto' | 'en' | 'fr' | 'es' | 'de' | 'fa' | 'it' | 'pt' | 'ru' | 'zh' | 'ja' | 'ko' | 'ar' | 'hi' | 'nl' | 'pl'
|
||||||
demoMode?: boolean
|
demoMode?: boolean
|
||||||
showRecentNotes?: boolean
|
showRecentNotes?: boolean
|
||||||
notesViewMode?: 'masonry' | 'tabs'
|
|
||||||
emailNotifications?: boolean
|
emailNotifications?: boolean
|
||||||
desktopNotifications?: boolean
|
desktopNotifications?: boolean
|
||||||
anonymousAnalytics?: boolean
|
anonymousAnalytics?: boolean
|
||||||
@@ -39,7 +38,6 @@ const USER_AI_SETTINGS_PRISMA_KEYS = [
|
|||||||
'fontSize',
|
'fontSize',
|
||||||
'demoMode',
|
'demoMode',
|
||||||
'showRecentNotes',
|
'showRecentNotes',
|
||||||
'notesViewMode',
|
|
||||||
'emailNotifications',
|
'emailNotifications',
|
||||||
'desktopNotifications',
|
'desktopNotifications',
|
||||||
'anonymousAnalytics',
|
'anonymousAnalytics',
|
||||||
@@ -61,13 +59,6 @@ function pickUserAISettingsForDb(input: UserAISettingsData): Partial<Record<User
|
|||||||
out[key] = v
|
out[key] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
out.notesViewMode != null &&
|
|
||||||
out.notesViewMode !== 'masonry' &&
|
|
||||||
out.notesViewMode !== 'tabs'
|
|
||||||
) {
|
|
||||||
delete out.notesViewMode
|
|
||||||
}
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +139,6 @@ const getCachedAISettings = unstable_cache(
|
|||||||
preferredLanguage: 'auto' as const,
|
preferredLanguage: 'auto' as const,
|
||||||
demoMode: false,
|
demoMode: false,
|
||||||
showRecentNotes: false,
|
showRecentNotes: false,
|
||||||
notesViewMode: 'masonry' as const,
|
|
||||||
emailNotifications: false,
|
emailNotifications: false,
|
||||||
desktopNotifications: false,
|
desktopNotifications: false,
|
||||||
anonymousAnalytics: false,
|
anonymousAnalytics: false,
|
||||||
@@ -163,13 +153,6 @@ const getCachedAISettings = unstable_cache(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const raw = settings.notesViewMode
|
|
||||||
const viewMode =
|
|
||||||
raw === 'masonry'
|
|
||||||
? ('masonry' as const)
|
|
||||||
: raw === 'tabs'
|
|
||||||
? ('tabs' as const)
|
|
||||||
: ('masonry' as const)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
titleSuggestions: settings.titleSuggestions,
|
titleSuggestions: settings.titleSuggestions,
|
||||||
@@ -181,7 +164,6 @@ const getCachedAISettings = unstable_cache(
|
|||||||
preferredLanguage: (settings.preferredLanguage || 'auto') as 'auto' | 'en' | 'fr' | 'es' | 'de' | 'fa' | 'it' | 'pt' | 'ru' | 'zh' | 'ja' | 'ko' | 'ar' | 'hi' | 'nl' | 'pl',
|
preferredLanguage: (settings.preferredLanguage || 'auto') as 'auto' | 'en' | 'fr' | 'es' | 'de' | 'fa' | 'it' | 'pt' | 'ru' | 'zh' | 'ja' | 'ko' | 'ar' | 'hi' | 'nl' | 'pl',
|
||||||
demoMode: settings.demoMode,
|
demoMode: settings.demoMode,
|
||||||
showRecentNotes: settings.showRecentNotes,
|
showRecentNotes: settings.showRecentNotes,
|
||||||
notesViewMode: viewMode,
|
|
||||||
emailNotifications: settings.emailNotifications,
|
emailNotifications: settings.emailNotifications,
|
||||||
desktopNotifications: settings.desktopNotifications,
|
desktopNotifications: settings.desktopNotifications,
|
||||||
anonymousAnalytics: settings.anonymousAnalytics,
|
anonymousAnalytics: settings.anonymousAnalytics,
|
||||||
@@ -207,7 +189,6 @@ const getCachedAISettings = unstable_cache(
|
|||||||
preferredLanguage: 'auto' as const,
|
preferredLanguage: 'auto' as const,
|
||||||
demoMode: false,
|
demoMode: false,
|
||||||
showRecentNotes: false,
|
showRecentNotes: false,
|
||||||
notesViewMode: 'masonry' as const,
|
|
||||||
emailNotifications: false,
|
emailNotifications: false,
|
||||||
desktopNotifications: false,
|
desktopNotifications: false,
|
||||||
anonymousAnalytics: false,
|
anonymousAnalytics: false,
|
||||||
@@ -246,7 +227,6 @@ export async function getAISettings(userId?: string) {
|
|||||||
preferredLanguage: 'auto' as const,
|
preferredLanguage: 'auto' as const,
|
||||||
demoMode: false,
|
demoMode: false,
|
||||||
showRecentNotes: false,
|
showRecentNotes: false,
|
||||||
notesViewMode: 'masonry' as const,
|
|
||||||
emailNotifications: false,
|
emailNotifications: false,
|
||||||
desktopNotifications: false,
|
desktopNotifications: false,
|
||||||
anonymousAnalytics: false,
|
anonymousAnalytics: false,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { useSearchParams, useRouter } from 'next/navigation'
|
|||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
import { Note } from '@/lib/types'
|
import { Note } from '@/lib/types'
|
||||||
import { getAllNotes, searchNotes, enableNoteHistory, getNoteById, createNote } from '@/app/actions/notes'
|
import { getAllNotes, searchNotes, enableNoteHistory, getNoteById, createNote } from '@/app/actions/notes'
|
||||||
import { NotesMainSection, type NotesViewMode } from '@/components/notes-main-section'
|
|
||||||
import { NotesEditorialView } from '@/components/notes-editorial-view'
|
import { NotesEditorialView } from '@/components/notes-editorial-view'
|
||||||
|
|
||||||
import { MemoryEchoNotification } from '@/components/memory-echo-notification'
|
import { MemoryEchoNotification } from '@/components/memory-echo-notification'
|
||||||
@@ -46,7 +45,6 @@ const NotebookSummaryDialog = dynamic(
|
|||||||
|
|
||||||
type InitialSettings = {
|
type InitialSettings = {
|
||||||
showRecentNotes: boolean
|
showRecentNotes: boolean
|
||||||
notesViewMode: 'masonry' | 'tabs'
|
|
||||||
noteHistory: boolean
|
noteHistory: boolean
|
||||||
noteHistoryMode: 'manual' | 'auto'
|
noteHistoryMode: 'manual' | 'auto'
|
||||||
aiAssistantEnabled: boolean
|
aiAssistantEnabled: boolean
|
||||||
@@ -66,7 +64,6 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
|||||||
const [pinnedNotes, setPinnedNotes] = useState<Note[]>(
|
const [pinnedNotes, setPinnedNotes] = useState<Note[]>(
|
||||||
initialNotes.filter(n => n.isPinned)
|
initialNotes.filter(n => n.isPinned)
|
||||||
)
|
)
|
||||||
const [notesViewMode, setNotesViewMode] = useState<NotesViewMode>(initialSettings.notesViewMode)
|
|
||||||
const [noteHistoryMode] = useState<'manual' | 'auto'>(initialSettings.noteHistoryMode)
|
const [noteHistoryMode] = useState<'manual' | 'auto'>(initialSettings.noteHistoryMode)
|
||||||
const [editingNote, setEditingNote] = useState<{ note: Note; readOnly?: boolean } | null>(null)
|
const [editingNote, setEditingNote] = useState<{ note: Note; readOnly?: boolean } | null>(null)
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
@@ -98,16 +95,15 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
|||||||
}
|
}
|
||||||
}, [shouldSuggestLabels, suggestNotebookId])
|
}, [shouldSuggestLabels, suggestNotebookId])
|
||||||
|
|
||||||
// Sidebar carnet / inbox: forceList → liste éditoriale + fermer l'éditeur plein écran (comme la ref. architectural-grid)
|
// Sidebar carnet / inbox: fermer l'éditeur plein écran (comme la ref. architectural-grid)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const forceList = searchParams.get('forceList')
|
if (searchParams.get('forceList') === '1') {
|
||||||
if (forceList !== '1') return
|
setEditingNote(null)
|
||||||
setNotesViewMode(prev => (prev === 'tabs' ? 'masonry' : prev))
|
const params = new URLSearchParams(searchParams.toString())
|
||||||
setEditingNote(null)
|
params.delete('forceList')
|
||||||
const params = new URLSearchParams(searchParams.toString())
|
const newUrl = params.toString() ? `/?${params.toString()}` : '/'
|
||||||
params.delete('forceList')
|
router.replace(newUrl, { scroll: false })
|
||||||
const newUrl = params.toString() ? `/?${params.toString()}` : '/'
|
}
|
||||||
router.replace(newUrl, { scroll: false })
|
|
||||||
}, [searchParams, router])
|
}, [searchParams, router])
|
||||||
|
|
||||||
const notebookFilter = searchParams.get('notebook')
|
const notebookFilter = searchParams.get('notebook')
|
||||||
@@ -234,7 +230,6 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = (e: Event) => {
|
const handler = (e: Event) => {
|
||||||
const { name } = (e as CustomEvent).detail
|
const { name } = (e as CustomEvent).detail
|
||||||
if (!name) return
|
|
||||||
const removeLabel = (note: Note) => {
|
const removeLabel = (note: Note) => {
|
||||||
const currentLabels = note.labels || []
|
const currentLabels = note.labels || []
|
||||||
const updated = currentLabels.filter((l) => l.toLowerCase() !== name.toLowerCase())
|
const updated = currentLabels.filter((l) => l.toLowerCase() !== name.toLowerCase())
|
||||||
@@ -346,13 +341,13 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
|||||||
return trail
|
return trail
|
||||||
}, [currentNotebook, notebooks])
|
}, [currentNotebook, notebooks])
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setControls({
|
setControls({
|
||||||
isTabsMode: notesViewMode === 'tabs',
|
|
||||||
openNoteComposer: () => handleAddNote(),
|
openNoteComposer: () => handleAddNote(),
|
||||||
})
|
})
|
||||||
return () => setControls(null)
|
return () => setControls(null)
|
||||||
}, [notesViewMode, setControls])
|
}, [setControls])
|
||||||
|
|
||||||
// Apply sort order to notes
|
// Apply sort order to notes
|
||||||
const sortedNotes = useMemo(() => {
|
const sortedNotes = useMemo(() => {
|
||||||
@@ -373,8 +368,6 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
|||||||
alpha: t('sidebar.sortAlpha') || 'A → Z',
|
alpha: t('sidebar.sortAlpha') || 'A → Z',
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTabs = notesViewMode === 'tabs'
|
|
||||||
const isEditorialMode = !isTabs
|
|
||||||
|
|
||||||
const handleEditorClose = useCallback(() => {
|
const handleEditorClose = useCallback(() => {
|
||||||
setEditingNote(null)
|
setEditingNote(null)
|
||||||
@@ -399,8 +392,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex w-full min-h-0 flex-1 flex-col',
|
'flex w-full min-h-0 flex-1 flex-col gap-3 py-1'
|
||||||
isTabs ? 'gap-3 py-1' : 'h-full'
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{editingNote ? (
|
{editingNote ? (
|
||||||
@@ -413,10 +405,9 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex-1 overflow-y-auto min-h-0 bg-memento-paper flex flex-col">
|
<div className="flex-1 overflow-y-auto min-h-0 bg-memento-paper flex flex-col">
|
||||||
<div className={cn(
|
<div
|
||||||
'px-12 pt-12 pb-8 flex flex-col gap-6',
|
className="px-12 pt-12 pb-8 flex flex-col gap-6 sticky top-0 bg-memento-paper/90 backdrop-blur-md z-30"
|
||||||
isEditorialMode ? 'sticky top-0 bg-memento-paper/90 backdrop-blur-md z-30' : ''
|
>
|
||||||
)}>
|
|
||||||
<div className="flex justify-between items-start">
|
<div className="flex justify-between items-start">
|
||||||
<div>
|
<div>
|
||||||
{currentNotebook && notebookPath.length > 0 && (
|
{currentNotebook && notebookPath.length > 0 && (
|
||||||
@@ -571,18 +562,6 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
|||||||
<div className="px-12 flex-1 pb-20">
|
<div className="px-12 flex-1 pb-20">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="text-center py-8 text-muted-foreground">{t('general.loading')}</div>
|
<div className="text-center py-8 text-muted-foreground">{t('general.loading')}</div>
|
||||||
) : isTabs ? (
|
|
||||||
<NotesMainSection
|
|
||||||
viewMode={notesViewMode}
|
|
||||||
notes={sortedNotes}
|
|
||||||
onEdit={(note, readOnly) => setEditingNote({ note, readOnly })}
|
|
||||||
onSizeChange={handleSizeChange}
|
|
||||||
currentNotebookId={searchParams.get('notebook')}
|
|
||||||
noteHistoryMode={noteHistoryMode}
|
|
||||||
onOpenHistory={handleOpenHistory}
|
|
||||||
onEnableHistory={handleEnableHistory}
|
|
||||||
onNoteCreated={handleNoteCreated}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<div className="max-w-3xl space-y-16">
|
<div className="max-w-3xl space-y-16">
|
||||||
{sortedPinnedNotes.length > 0 && (
|
{sortedPinnedNotes.length > 0 && (
|
||||||
|
|||||||
@@ -1,161 +0,0 @@
|
|||||||
/**
|
|
||||||
* Masonry Grid — Deux modes d'affichage :
|
|
||||||
* 1. Variable : CSS Grid avec tailles small/medium/large
|
|
||||||
* 2. Uniform : CSS Columns masonry (comme Google Keep)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ─── Container ──────────────────────────────────── */
|
|
||||||
.masonry-container {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0 8px 40px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ═══════════════════════════════════════════════════
|
|
||||||
MODE 1 : VARIABLE (CSS Grid avec tailles différentes)
|
|
||||||
═══════════════════════════════════════════════════ */
|
|
||||||
|
|
||||||
.masonry-css-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
||||||
grid-auto-rows: auto;
|
|
||||||
gap: 12px;
|
|
||||||
align-items: start;
|
|
||||||
grid-auto-flow: dense;
|
|
||||||
}
|
|
||||||
|
|
||||||
.masonry-sortable-item[data-size="medium"] {
|
|
||||||
grid-column: span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.masonry-sortable-item[data-size="large"] {
|
|
||||||
grid-column: span 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ═══════════════════════════════════════════════════
|
|
||||||
MODE 2 : UNIFORM — CSS Columns masonry (Google Keep)
|
|
||||||
═══════════════════════════════════════════════════ */
|
|
||||||
|
|
||||||
.masonry-container[data-card-size-mode="uniform"] .masonry-css-grid {
|
|
||||||
display: block;
|
|
||||||
column-width: 240px;
|
|
||||||
column-gap: 12px;
|
|
||||||
orphans: 1;
|
|
||||||
widows: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.masonry-container[data-card-size-mode="uniform"] .masonry-sortable-item,
|
|
||||||
.masonry-container[data-card-size-mode="uniform"] .masonry-sortable-item[data-size="medium"],
|
|
||||||
.masonry-container[data-card-size-mode="uniform"] .masonry-sortable-item[data-size="large"] {
|
|
||||||
break-inside: avoid;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
display: inline-block;
|
|
||||||
width: 100%;
|
|
||||||
grid-column: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Sortable items ─────────────────────────────── */
|
|
||||||
.masonry-sortable-item {
|
|
||||||
break-inside: avoid;
|
|
||||||
box-sizing: border-box;
|
|
||||||
will-change: transform;
|
|
||||||
transition: opacity 0.15s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Note card base ─────────────────────────────── */
|
|
||||||
.note-card {
|
|
||||||
width: 100% !important;
|
|
||||||
min-width: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Drag overlay ───────────────────────────────── */
|
|
||||||
.masonry-drag-overlay {
|
|
||||||
cursor: grabbing;
|
|
||||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.25), 0 8px 16px rgba(0, 0, 0, 0.15);
|
|
||||||
border-radius: 12px;
|
|
||||||
opacity: 0.95;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Mobile (< 480px) ───────────────────────────── */
|
|
||||||
@media (max-width: 479px) {
|
|
||||||
.masonry-css-grid {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.masonry-sortable-item[data-size="medium"],
|
|
||||||
.masonry-sortable-item[data-size="large"] {
|
|
||||||
grid-column: span 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.masonry-container[data-card-size-mode="uniform"] .masonry-css-grid {
|
|
||||||
column-width: 100%;
|
|
||||||
column-gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.masonry-container {
|
|
||||||
padding: 0 4px 16px 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Small tablet (480–767px) ───────────────────── */
|
|
||||||
@media (min-width: 480px) and (max-width: 767px) {
|
|
||||||
.masonry-css-grid {
|
|
||||||
grid-template-columns: repeat(2, 1fr);
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.masonry-sortable-item[data-size="large"] {
|
|
||||||
grid-column: span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.masonry-container {
|
|
||||||
padding: 0 8px 20px 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Tablet (768–1023px) ────────────────────────── */
|
|
||||||
@media (min-width: 768px) and (max-width: 1023px) {
|
|
||||||
.masonry-css-grid {
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Desktop (1024–1279px) ─────────────────────── */
|
|
||||||
@media (min-width: 1024px) and (max-width: 1279px) {
|
|
||||||
.masonry-css-grid {
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Large Desktop (1280px+) ───────────────────── */
|
|
||||||
@media (min-width: 1280px) {
|
|
||||||
.masonry-css-grid {
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
||||||
gap: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.masonry-container {
|
|
||||||
max-width: 1600px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0 12px 32px 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Print ──────────────────────────────────────── */
|
|
||||||
@media print {
|
|
||||||
.masonry-sortable-item {
|
|
||||||
break-inside: avoid;
|
|
||||||
page-break-inside: avoid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Reduced motion ─────────────────────────────── */
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.masonry-sortable-item {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,346 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useState, useEffect, useCallback, memo, useMemo, useRef } from 'react';
|
|
||||||
import {
|
|
||||||
DndContext,
|
|
||||||
DragEndEvent,
|
|
||||||
DragOverlay,
|
|
||||||
DragStartEvent,
|
|
||||||
PointerSensor,
|
|
||||||
TouchSensor,
|
|
||||||
closestCenter,
|
|
||||||
useSensor,
|
|
||||||
useSensors,
|
|
||||||
} from '@dnd-kit/core';
|
|
||||||
import {
|
|
||||||
SortableContext,
|
|
||||||
arrayMove,
|
|
||||||
rectSortingStrategy,
|
|
||||||
useSortable,
|
|
||||||
} from '@dnd-kit/sortable';
|
|
||||||
import { CSS } from '@dnd-kit/utilities';
|
|
||||||
import { Note } from '@/lib/types';
|
|
||||||
import { NoteCard } from './note-card';
|
|
||||||
import { updateFullOrderWithoutRevalidation } from '@/app/actions/notes';
|
|
||||||
import { useEditorUI } from '@/context/editor-ui-context';
|
|
||||||
import { useLanguage } from '@/lib/i18n';
|
|
||||||
import { useCardSizeMode } from '@/hooks/use-card-size-mode';
|
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
import './masonry-grid.css';
|
|
||||||
|
|
||||||
// Lazy-load NoteEditor — uniquement chargé au clic
|
|
||||||
const NoteEditor = dynamic(
|
|
||||||
() => import('./note-editor').then(m => ({ default: m.NoteEditor })),
|
|
||||||
{ ssr: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
interface MasonryGridProps {
|
|
||||||
notes: Note[];
|
|
||||||
onEdit?: (note: Note, readOnly?: boolean) => void;
|
|
||||||
onSizeChange?: (noteId: string, size: 'small' | 'medium' | 'large') => void;
|
|
||||||
isTrashView?: boolean;
|
|
||||||
noteHistoryEnabled?: boolean;
|
|
||||||
noteHistoryMode?: 'manual' | 'auto';
|
|
||||||
onOpenHistory?: (note: Note) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─────────────────────────────────────────────
|
|
||||||
// Sortable Note Item
|
|
||||||
// ─────────────────────────────────────────────
|
|
||||||
interface SortableNoteProps {
|
|
||||||
note: Note;
|
|
||||||
onEdit: (note: Note, readOnly?: boolean) => void;
|
|
||||||
onSizeChange: (noteId: string, newSize: 'small' | 'medium' | 'large') => void;
|
|
||||||
onDragStartNote?: (noteId: string) => void;
|
|
||||||
onDragEndNote?: () => void;
|
|
||||||
isDragging?: boolean;
|
|
||||||
isOverlay?: boolean;
|
|
||||||
isTrashView?: boolean;
|
|
||||||
noteHistoryEnabled?: boolean;
|
|
||||||
onOpenHistory?: (note: Note) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SortableNoteItem = memo(function SortableNoteItem({
|
|
||||||
note,
|
|
||||||
onEdit,
|
|
||||||
onSizeChange,
|
|
||||||
onDragStartNote,
|
|
||||||
onDragEndNote,
|
|
||||||
isDragging,
|
|
||||||
isOverlay,
|
|
||||||
isTrashView,
|
|
||||||
noteHistoryEnabled,
|
|
||||||
onOpenHistory,
|
|
||||||
}: SortableNoteProps) {
|
|
||||||
const {
|
|
||||||
attributes,
|
|
||||||
listeners,
|
|
||||||
setNodeRef,
|
|
||||||
transform,
|
|
||||||
transition,
|
|
||||||
isDragging: isSortableDragging,
|
|
||||||
} = useSortable({ id: note.id });
|
|
||||||
|
|
||||||
const style: React.CSSProperties = {
|
|
||||||
transform: CSS.Transform.toString(transform),
|
|
||||||
transition,
|
|
||||||
opacity: isSortableDragging && !isOverlay ? 0.3 : 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={setNodeRef}
|
|
||||||
style={style}
|
|
||||||
{...attributes}
|
|
||||||
{...listeners}
|
|
||||||
className="masonry-sortable-item"
|
|
||||||
data-id={note.id}
|
|
||||||
data-size={note.size}
|
|
||||||
>
|
|
||||||
<NoteCard
|
|
||||||
note={note}
|
|
||||||
onEdit={onEdit}
|
|
||||||
onDragStart={onDragStartNote}
|
|
||||||
onDragEnd={onDragEndNote}
|
|
||||||
isDragging={isDragging}
|
|
||||||
isTrashView={isTrashView}
|
|
||||||
onSizeChange={(newSize) => onSizeChange(note.id, newSize)}
|
|
||||||
noteHistoryEnabled={noteHistoryEnabled}
|
|
||||||
onOpenHistory={onOpenHistory}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
|
|
||||||
// ─────────────────────────────────────────────
|
|
||||||
// Sortable Grid Section (pinned or others)
|
|
||||||
// ─────────────────────────────────────────────
|
|
||||||
interface SortableGridSectionProps {
|
|
||||||
notes: Note[];
|
|
||||||
onEdit: (note: Note, readOnly?: boolean) => void;
|
|
||||||
onSizeChange: (noteId: string, newSize: 'small' | 'medium' | 'large') => void;
|
|
||||||
draggedNoteId: string | null;
|
|
||||||
onDragStartNote: (noteId: string) => void;
|
|
||||||
onDragEndNote: () => void;
|
|
||||||
isTrashView?: boolean;
|
|
||||||
noteHistoryEnabled?: boolean;
|
|
||||||
onOpenHistory?: (note: Note) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SortableGridSection = memo(function SortableGridSection({
|
|
||||||
notes,
|
|
||||||
onEdit,
|
|
||||||
onSizeChange,
|
|
||||||
draggedNoteId,
|
|
||||||
onDragStartNote,
|
|
||||||
onDragEndNote,
|
|
||||||
isTrashView,
|
|
||||||
noteHistoryEnabled,
|
|
||||||
onOpenHistory,
|
|
||||||
}: SortableGridSectionProps) {
|
|
||||||
const ids = useMemo(() => notes.map(n => n.id), [notes]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SortableContext items={ids} strategy={rectSortingStrategy}>
|
|
||||||
<div className="masonry-css-grid">
|
|
||||||
{notes.map(note => (
|
|
||||||
<SortableNoteItem
|
|
||||||
key={note.id}
|
|
||||||
note={note}
|
|
||||||
onEdit={onEdit}
|
|
||||||
onSizeChange={onSizeChange}
|
|
||||||
onDragStartNote={onDragStartNote}
|
|
||||||
onDragEndNote={onDragEndNote}
|
|
||||||
isDragging={draggedNoteId === note.id}
|
|
||||||
isTrashView={isTrashView}
|
|
||||||
noteHistoryEnabled={noteHistoryEnabled}
|
|
||||||
onOpenHistory={onOpenHistory}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</SortableContext>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// ─────────────────────────────────────────────
|
|
||||||
// Main MasonryGrid component
|
|
||||||
// ─────────────────────────────────────────────
|
|
||||||
export function MasonryGrid({
|
|
||||||
notes,
|
|
||||||
onEdit,
|
|
||||||
onSizeChange,
|
|
||||||
isTrashView,
|
|
||||||
noteHistoryEnabled = false,
|
|
||||||
onOpenHistory,
|
|
||||||
}: MasonryGridProps) {
|
|
||||||
const { t } = useLanguage();
|
|
||||||
const [editingNote, setEditingNote] = useState<{ note: Note; readOnly?: boolean } | null>(null);
|
|
||||||
const { startDrag, endDrag, draggedNoteId } = useEditorUI();
|
|
||||||
const cardSizeMode = useCardSizeMode();
|
|
||||||
const isUniformMode = cardSizeMode === 'uniform';
|
|
||||||
|
|
||||||
// Local notes state for optimistic size/order updates
|
|
||||||
const [localNotes, setLocalNotes] = useState<Note[]>(notes);
|
|
||||||
const prevNotesRef = useRef<Note[]>(notes);
|
|
||||||
|
|
||||||
if (notes !== prevNotesRef.current) {
|
|
||||||
const localSizeMap = new Map(localNotes.map(n => [n.id, n.size]));
|
|
||||||
const localOrderMap = new Map(localNotes.map((n, i) => [n.id, i]));
|
|
||||||
const newLocalNotes = notes.map(n => ({ ...n, size: localSizeMap.get(n.id) ?? n.size }));
|
|
||||||
newLocalNotes.sort((a, b) => {
|
|
||||||
const oA = localOrderMap.get(a.id)
|
|
||||||
const oB = localOrderMap.get(b.id)
|
|
||||||
if (oA !== undefined && oB !== undefined) return oA - oB
|
|
||||||
if (oA !== undefined) return -1
|
|
||||||
if (oB !== undefined) return 1
|
|
||||||
return 0
|
|
||||||
})
|
|
||||||
setLocalNotes(newLocalNotes);
|
|
||||||
prevNotesRef.current = notes;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pinnedNotes = useMemo(() => localNotes.filter(n => n.isPinned), [localNotes]);
|
|
||||||
const othersNotes = useMemo(() => localNotes.filter(n => !n.isPinned), [localNotes]);
|
|
||||||
|
|
||||||
const [activeId, setActiveId] = useState<string | null>(null);
|
|
||||||
const activeNote = useMemo(
|
|
||||||
() => localNotes.find(n => n.id === activeId) ?? null,
|
|
||||||
[localNotes, activeId]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleEdit = useCallback((note: Note, readOnly?: boolean) => {
|
|
||||||
if (onEdit) {
|
|
||||||
onEdit(note, readOnly);
|
|
||||||
} else {
|
|
||||||
setEditingNote({ note, readOnly });
|
|
||||||
}
|
|
||||||
}, [onEdit]);
|
|
||||||
|
|
||||||
const handleSizeChange = useCallback((noteId: string, newSize: 'small' | 'medium' | 'large') => {
|
|
||||||
setLocalNotes(prev => prev.map(n => n.id === noteId ? { ...n, size: newSize } : n));
|
|
||||||
onSizeChange?.(noteId, newSize);
|
|
||||||
}, [onSizeChange]);
|
|
||||||
|
|
||||||
// @dnd-kit sensors — pointer (desktop) + touch (mobile)
|
|
||||||
const sensors = useSensors(
|
|
||||||
useSensor(PointerSensor, {
|
|
||||||
activationConstraint: { distance: 8 }, // Évite les activations accidentelles
|
|
||||||
}),
|
|
||||||
useSensor(TouchSensor, {
|
|
||||||
activationConstraint: { delay: 200, tolerance: 8 }, // Long-press sur mobile
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const localNotesRef = useRef<Note[]>(localNotes)
|
|
||||||
useEffect(() => {
|
|
||||||
localNotesRef.current = localNotes
|
|
||||||
}, [localNotes])
|
|
||||||
|
|
||||||
const handleDragStart = useCallback((event: DragStartEvent) => {
|
|
||||||
setActiveId(event.active.id as string);
|
|
||||||
startDrag(event.active.id as string);
|
|
||||||
}, [startDrag]);
|
|
||||||
|
|
||||||
const handleDragEnd = useCallback(async (event: DragEndEvent) => {
|
|
||||||
const { active, over } = event;
|
|
||||||
setActiveId(null);
|
|
||||||
endDrag();
|
|
||||||
|
|
||||||
if (!over || active.id === over.id) return;
|
|
||||||
|
|
||||||
const current = localNotesRef.current
|
|
||||||
const activeIdx = current.findIndex(n => n.id === active.id)
|
|
||||||
const overIdx = current.findIndex(n => n.id === over.id)
|
|
||||||
if (activeIdx === -1 || overIdx === -1) return
|
|
||||||
|
|
||||||
const activeNote = current[activeIdx]
|
|
||||||
const overNote = current[overIdx]
|
|
||||||
|
|
||||||
if (activeNote.isPinned !== overNote.isPinned) return
|
|
||||||
|
|
||||||
const reordered = arrayMove(current, activeIdx, overIdx);
|
|
||||||
if (reordered.length === 0) return;
|
|
||||||
|
|
||||||
setLocalNotes(reordered);
|
|
||||||
const ids = reordered.map(n => n.id);
|
|
||||||
updateFullOrderWithoutRevalidation(ids).catch(err => {
|
|
||||||
console.error('Failed to persist order:', err);
|
|
||||||
});
|
|
||||||
}, [endDrag]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DndContext
|
|
||||||
id="masonry-dnd"
|
|
||||||
sensors={sensors}
|
|
||||||
collisionDetection={closestCenter}
|
|
||||||
onDragStart={handleDragStart}
|
|
||||||
onDragEnd={handleDragEnd}
|
|
||||||
>
|
|
||||||
<div className="masonry-container" data-card-size-mode={cardSizeMode}>
|
|
||||||
{pinnedNotes.length > 0 && (
|
|
||||||
<div className="mb-8">
|
|
||||||
<h2 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3 px-2">
|
|
||||||
{t('notes.pinned')}
|
|
||||||
</h2>
|
|
||||||
<SortableGridSection
|
|
||||||
notes={pinnedNotes}
|
|
||||||
onEdit={handleEdit}
|
|
||||||
onSizeChange={handleSizeChange}
|
|
||||||
draggedNoteId={draggedNoteId}
|
|
||||||
onDragStartNote={startDrag}
|
|
||||||
onDragEndNote={endDrag}
|
|
||||||
isTrashView={isTrashView}
|
|
||||||
noteHistoryEnabled={noteHistoryEnabled}
|
|
||||||
onOpenHistory={onOpenHistory}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{othersNotes.length > 0 && (
|
|
||||||
<div>
|
|
||||||
{pinnedNotes.length > 0 && (
|
|
||||||
<h2 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3 px-2">
|
|
||||||
{t('notes.others')}
|
|
||||||
</h2>
|
|
||||||
)}
|
|
||||||
<SortableGridSection
|
|
||||||
notes={othersNotes}
|
|
||||||
onEdit={handleEdit}
|
|
||||||
onSizeChange={handleSizeChange}
|
|
||||||
draggedNoteId={draggedNoteId}
|
|
||||||
onDragStartNote={startDrag}
|
|
||||||
onDragEndNote={endDrag}
|
|
||||||
isTrashView={isTrashView}
|
|
||||||
noteHistoryEnabled={noteHistoryEnabled}
|
|
||||||
onOpenHistory={onOpenHistory}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* DragOverlay — montre une copie flottante pendant le drag */}
|
|
||||||
<DragOverlay>
|
|
||||||
{activeNote ? (
|
|
||||||
<div className="masonry-sortable-item masonry-drag-overlay" data-size={activeNote.size}>
|
|
||||||
<NoteCard
|
|
||||||
note={activeNote}
|
|
||||||
onEdit={handleEdit}
|
|
||||||
isDragging={true}
|
|
||||||
onSizeChange={(newSize) => handleSizeChange(activeNote.id, newSize)}
|
|
||||||
noteHistoryEnabled={noteHistoryEnabled}
|
|
||||||
onOpenHistory={onOpenHistory}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</DragOverlay>
|
|
||||||
|
|
||||||
{editingNote && (
|
|
||||||
<NoteEditor
|
|
||||||
note={editingNote.note}
|
|
||||||
readOnly={editingNote.readOnly}
|
|
||||||
onClose={() => setEditingNote(null)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</DndContext>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import dynamic from 'next/dynamic'
|
|
||||||
import { Note } from '@/lib/types'
|
|
||||||
import { NotesTabsView } from '@/components/notes-tabs-view'
|
|
||||||
|
|
||||||
const MasonryGridLazy = dynamic(
|
|
||||||
() => import('@/components/masonry-grid').then((m) => m.MasonryGrid),
|
|
||||||
{
|
|
||||||
ssr: false,
|
|
||||||
loading: () => (
|
|
||||||
<div
|
|
||||||
className="min-h-[200px] rounded-xl border border-dashed border-muted-foreground/20 bg-muted/30 animate-pulse"
|
|
||||||
aria-hidden
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
export type NotesViewMode = 'masonry' | 'tabs'
|
|
||||||
|
|
||||||
interface NotesMainSectionProps {
|
|
||||||
notes: Note[]
|
|
||||||
viewMode: NotesViewMode
|
|
||||||
onEdit?: (note: Note, readOnly?: boolean) => void
|
|
||||||
onSizeChange?: (noteId: string, size: 'small' | 'medium' | 'large') => void
|
|
||||||
currentNotebookId?: string | null
|
|
||||||
noteHistoryMode?: 'manual' | 'auto'
|
|
||||||
onOpenHistory?: (note: Note) => void
|
|
||||||
onEnableHistory?: (noteId: string) => Promise<void>
|
|
||||||
onNoteCreated?: (note: Note) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export function NotesMainSection({
|
|
||||||
notes,
|
|
||||||
viewMode,
|
|
||||||
onEdit,
|
|
||||||
onSizeChange,
|
|
||||||
currentNotebookId,
|
|
||||||
noteHistoryMode = 'manual',
|
|
||||||
onOpenHistory,
|
|
||||||
onEnableHistory,
|
|
||||||
onNoteCreated,
|
|
||||||
}: NotesMainSectionProps) {
|
|
||||||
if (viewMode === 'tabs') {
|
|
||||||
return (
|
|
||||||
<div className="flex min-h-0 flex-1 flex-col" data-testid="notes-grid-tabs-wrap">
|
|
||||||
<NotesTabsView
|
|
||||||
notes={notes}
|
|
||||||
onEdit={onEdit}
|
|
||||||
currentNotebookId={currentNotebookId}
|
|
||||||
noteHistoryMode={noteHistoryMode}
|
|
||||||
onOpenHistory={onOpenHistory}
|
|
||||||
onEnableHistory={onEnableHistory}
|
|
||||||
onNoteCreated={onNoteCreated}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div data-testid="notes-grid">
|
|
||||||
<MasonryGridLazy
|
|
||||||
notes={notes}
|
|
||||||
onEdit={onEdit}
|
|
||||||
onSizeChange={onSizeChange}
|
|
||||||
noteHistoryMode={noteHistoryMode}
|
|
||||||
onOpenHistory={onOpenHistory}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,6 @@
|
|||||||
import { createContext, useContext, useState, useCallback, useMemo, type ReactNode } from 'react'
|
import { createContext, useContext, useState, useCallback, useMemo, type ReactNode } from 'react'
|
||||||
|
|
||||||
export type HomeUiControls = {
|
export type HomeUiControls = {
|
||||||
isTabsMode: boolean
|
|
||||||
openNoteComposer: () => void
|
openNoteComposer: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -162,13 +162,6 @@
|
|||||||
"unpinned": "Unpinned",
|
"unpinned": "Unpinned",
|
||||||
"redoShortcut": "Redo (Ctrl+Y)",
|
"redoShortcut": "Redo (Ctrl+Y)",
|
||||||
"undoShortcut": "Undo (Ctrl+Z)",
|
"undoShortcut": "Undo (Ctrl+Z)",
|
||||||
"viewCards": "Cards View",
|
|
||||||
"viewCardsTooltip": "Card grid with drag-and-drop reorder",
|
|
||||||
"viewList": "List",
|
|
||||||
"viewListTooltip": "Scannable list with preview, dates, and labels",
|
|
||||||
"viewTabs": "Tabs",
|
|
||||||
"viewTabsTooltip": "Tabs on top, note below — drag tabs to reorder",
|
|
||||||
"viewModeGroup": "Notes display mode",
|
|
||||||
"reorderTabs": "Reorder tab",
|
"reorderTabs": "Reorder tab",
|
||||||
"modified": "Modified",
|
"modified": "Modified",
|
||||||
"created": "Created",
|
"created": "Created",
|
||||||
|
|||||||
@@ -162,13 +162,6 @@
|
|||||||
"unpinned": "Désépinglées",
|
"unpinned": "Désépinglées",
|
||||||
"redoShortcut": "Rétablir (Ctrl+Y)",
|
"redoShortcut": "Rétablir (Ctrl+Y)",
|
||||||
"undoShortcut": "Annuler (Ctrl+Z)",
|
"undoShortcut": "Annuler (Ctrl+Z)",
|
||||||
"viewCards": "Vue par cartes",
|
|
||||||
"viewCardsTooltip": "Grille de cartes et réorganisation par glisser-déposer",
|
|
||||||
"viewList": "Liste",
|
|
||||||
"viewListTooltip": "Liste avec aperçu, dates et étiquettes (style magazine)",
|
|
||||||
"viewTabs": "Onglets",
|
|
||||||
"viewTabsTooltip": "Onglets en haut, contenu dessous — glisser les onglets pour réordonner",
|
|
||||||
"viewModeGroup": "Mode d'affichage des notes",
|
|
||||||
"reorderTabs": "Réordonner l'onglet",
|
"reorderTabs": "Réordonner l'onglet",
|
||||||
"modified": "Modifiée",
|
"modified": "Modifiée",
|
||||||
"created": "Créée",
|
"created": "Créée",
|
||||||
|
|||||||
@@ -279,8 +279,6 @@ model UserAISettings {
|
|||||||
fontSize String @default("medium")
|
fontSize String @default("medium")
|
||||||
demoMode Boolean @default(false)
|
demoMode Boolean @default(false)
|
||||||
showRecentNotes Boolean @default(true)
|
showRecentNotes Boolean @default(true)
|
||||||
/// "masonry" = grille cartes Muuri ; "tabs" = onglets + panneau (type OneNote). Ancienne valeur "list" migrée vers "tabs" en lecture.
|
|
||||||
notesViewMode String @default("masonry")
|
|
||||||
emailNotifications Boolean @default(false)
|
emailNotifications Boolean @default(false)
|
||||||
desktopNotifications Boolean @default(false)
|
desktopNotifications Boolean @default(false)
|
||||||
anonymousAnalytics Boolean @default(false)
|
anonymousAnalytics Boolean @default(false)
|
||||||
|
|||||||
@@ -312,7 +312,6 @@ async function main() {
|
|||||||
fontSize: s.fontSize || 'medium',
|
fontSize: s.fontSize || 'medium',
|
||||||
demoMode: s.demoMode === 1 || s.demoMode === true,
|
demoMode: s.demoMode === 1 || s.demoMode === true,
|
||||||
showRecentNotes: s.showRecentNotes === 1 || s.showRecentNotes === true,
|
showRecentNotes: s.showRecentNotes === 1 || s.showRecentNotes === true,
|
||||||
notesViewMode: s.notesViewMode || 'masonry',
|
|
||||||
emailNotifications: s.emailNotifications === 1 || s.emailNotifications === true,
|
emailNotifications: s.emailNotifications === 1 || s.emailNotifications === true,
|
||||||
desktopNotifications: s.desktopNotifications === 1 || s.desktopNotifications === true,
|
desktopNotifications: s.desktopNotifications === 1 || s.desktopNotifications === true,
|
||||||
anonymousAnalytics: s.anonymousAnalytics === 1 || s.anonymousAnalytics === true,
|
anonymousAnalytics: s.anonymousAnalytics === 1 || s.anonymousAnalytics === true,
|
||||||
|
|||||||
Reference in New Issue
Block a user