fix: unify theme system - fix theme switching persistence
- Unified localStorage key to 'theme-preference' across all components
- Fixed header.tsx using wrong localStorage key ('theme' instead of 'theme-preference')
- Added localStorage hybrid persistence for instant theme changes
- Removed router.refresh() which was causing stale data revert
- Replaced Blue theme with Sepia
- Consolidated auth() calls to prevent race conditions
- Updated UserSettingsData types to include all themes
This commit is contained in:
147
keep-notes/config/masonry-layout.ts
Normal file
147
keep-notes/config/masonry-layout.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Masonry Layout Configuration
|
||||
*
|
||||
* Configuration for responsive masonry grid layout similar to Google Keep
|
||||
* Defines breakpoints, columns, and note sizes for different screen sizes
|
||||
*/
|
||||
|
||||
export interface MasonryLayoutConfig {
|
||||
breakpoints: {
|
||||
mobile: number; // < 480px
|
||||
smallTablet: number; // 480px - 768px
|
||||
tablet: number; // 768px - 1024px
|
||||
desktop: number; // 1024px - 1280px
|
||||
largeDesktop: number; // 1280px - 1600px
|
||||
extraLarge: number; // > 1600px
|
||||
};
|
||||
columns: {
|
||||
mobile: number;
|
||||
smallTablet: number;
|
||||
tablet: number;
|
||||
desktop: number;
|
||||
largeDesktop: number;
|
||||
extraLarge: number;
|
||||
};
|
||||
noteSizes: {
|
||||
small: { minHeight: number; width: number };
|
||||
medium: { minHeight: number; width: number };
|
||||
large: { minHeight: number; width: number };
|
||||
};
|
||||
gap: number;
|
||||
gutter: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default layout configuration based on Google Keep's behavior
|
||||
*
|
||||
* Responsive breakpoints:
|
||||
* - Mobile (< 480px): 1 column
|
||||
* - Small Tablet (480px - 768px): 2 columns
|
||||
* - Tablet (768px - 1024px): 2 columns
|
||||
* - Desktop (1024px - 1280px): 3 columns
|
||||
* - Large Desktop (1280px - 1600px): 4 columns
|
||||
* - Extra Large Desktop (> 1600px): 5 columns
|
||||
*
|
||||
* Note sizes:
|
||||
* - Small: Compact cards (150px min height)
|
||||
* - Medium: Standard cards (200px min height)
|
||||
* - Large: Expanded cards (300px min height)
|
||||
*/
|
||||
export const DEFAULT_LAYOUT: MasonryLayoutConfig = {
|
||||
breakpoints: {
|
||||
mobile: 480,
|
||||
smallTablet: 768,
|
||||
tablet: 1024,
|
||||
desktop: 1280,
|
||||
largeDesktop: 1600,
|
||||
extraLarge: 1920,
|
||||
},
|
||||
columns: {
|
||||
mobile: 1,
|
||||
smallTablet: 2,
|
||||
tablet: 2,
|
||||
desktop: 3,
|
||||
largeDesktop: 4,
|
||||
extraLarge: 5, // This is just a fallback, calculation is dynamic now
|
||||
},
|
||||
noteSizes: {
|
||||
small: { minHeight: 150, width: 210 }, // Narrower for better density
|
||||
medium: { minHeight: 200, width: 240 },
|
||||
large: { minHeight: 300, width: 240 },
|
||||
},
|
||||
gap: 10, // Tighter gap closer to Google Keep
|
||||
gutter: 10,
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the number of columns based on container width
|
||||
*
|
||||
* @param width - Container width in pixels
|
||||
* @returns Number of columns to use
|
||||
*/
|
||||
export function calculateColumns(width: number): number {
|
||||
const { noteSizes, gap, breakpoints } = DEFAULT_LAYOUT;
|
||||
// Use small note width (240px) as minimum column width basis
|
||||
const minColumnWidth = noteSizes.small.width;
|
||||
|
||||
// For very small screens (mobile), force 1 column
|
||||
if (width < breakpoints.mobile) return 1;
|
||||
|
||||
// For larger screens, calculate max columns that fit
|
||||
// Formula: (Width + Gap) / (ColumnWidth + Gap)
|
||||
const columns = Math.floor((width + gap) / (minColumnWidth + gap));
|
||||
|
||||
// Ensure at least 1 column
|
||||
return Math.max(1, columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate item width based on container width and number of columns
|
||||
*
|
||||
* @param containerWidth - Total container width in pixels
|
||||
* @param columns - Number of columns to use
|
||||
* @returns Item width in pixels
|
||||
*/
|
||||
export function calculateItemWidth(containerWidth: number, columns: number): number {
|
||||
const { gap } = DEFAULT_LAYOUT;
|
||||
return (containerWidth - (columns - 1) * gap) / columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get note size dimensions (height and width) based on size type
|
||||
*
|
||||
* @param size - Note size ('small' | 'medium' | 'large')
|
||||
* @returns Note dimensions in pixels
|
||||
*/
|
||||
export function getNoteSizeDimensions(size: 'small' | 'medium' | 'large') {
|
||||
return DEFAULT_LAYOUT.noteSizes[size];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current viewport is mobile
|
||||
*
|
||||
* @returns true if viewport width is less than mobile breakpoint
|
||||
*/
|
||||
export function isMobileViewport(): boolean {
|
||||
return typeof window !== 'undefined' && window.innerWidth < DEFAULT_LAYOUT.breakpoints.mobile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current viewport is tablet
|
||||
*
|
||||
* @returns true if viewport width is between mobile and desktop breakpoints
|
||||
*/
|
||||
export function isTabletViewport(): boolean {
|
||||
if (typeof window === 'undefined') return false;
|
||||
const width = window.innerWidth;
|
||||
return width >= DEFAULT_LAYOUT.breakpoints.mobile && width < DEFAULT_LAYOUT.breakpoints.tablet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current viewport is desktop
|
||||
*
|
||||
* @returns true if viewport width is greater than or equal to tablet breakpoint
|
||||
*/
|
||||
export function isDesktopViewport(): boolean {
|
||||
return typeof window !== 'undefined' && window.innerWidth >= DEFAULT_LAYOUT.breakpoints.tablet;
|
||||
}
|
||||
Reference in New Issue
Block a user