commit 8cc347fa00d1521e1edafb5379663d4ea48635c3
parent a1fc6caeebb144e572b786c73c4f2b0bbc42e3aa
Author: Hunter
Date:   Mon, 17 Nov 2025 11:00:12 -0500

support arbitrary grid sizes; add banana theme

Diffstat:
Mreadme.md | 13++++++++-----
Mscript.js | 108++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mstyle.css | 74+++++++++++++++++++++++++++++++++++++++++++++-----------------------------
3 files changed, 157 insertions(+), 38 deletions(-)

diff --git a/readme.md b/readme.md @@ -22,16 +22,19 @@ So here's a web app that does the same thing (and then some) for free. ## usage <img src="readme_images/usage.gif"> -Different Techo types use differently-spaced grid paper. Use the links below to select the appropriate spacing for your Techo. +Different Techo types use differently-sized grid paper. Use the links below to select the appropriate grid size for your Techo. | <b>Techo</b> | <b>Link</b> | |-------------------|-------------| -| Planner A6 | [Use 4mm grid ↗](link)<br>(default) | -| Original<br>Cousin<br>HON A6<br>HON A5<br>Original Avec<br>Cousin Avec<br>5-Year Techo A6<br>5-Year Techo A5<br>Day-Free A6<br>Day-Free A5 | [Use 3.7mm grid ↗](link) | -| Weeks<br>Weeks Mega | [Use 3.55mm grid ↗](link) | +| Planner A6 | [Use 4mm grid ↗](https://hunterirving.github.io/memori?grid-size=4mm)<br>(default) | +| Original<br>Cousin<br>HON A6<br>HON A5<br>Original Avec<br>Cousin Avec<br>5-Year Techo A6<br>5-Year Techo A5<br>Day-Free A6<br>Day-Free A5 | [Use 3.7mm grid ↗](https://hunterirving.github.io/memori?grid-size=3.7mm) | +| Weeks<br>Weeks Mega | [Use 3.55mm grid ↗](https://hunterirving.github.io/memori?grid-size=3.55mm) | -After opening memori in your web browser, drag one or more images from your desktop onto the grid. + +### controls + +- After opening memori in your web browser, drag one or more images from your desktop onto the grid.<br> <img src="readme_images/drag_n_drop.gif"> - click and drag images to move them<br> diff --git a/script.js b/script.js @@ -1,6 +1,40 @@ -const GRID_COLS = 49; -const GRID_ROWS = 66; -const CELL_SIZE_MM = 4; // Physical size of each cell when printed +// Paper dimensions in mm +const LETTER_WIDTH_MM = 215.9; // 8.5 inches +const LETTER_HEIGHT_MM = 279.4; // 11 inches +const A4_WIDTH_MM = 210; +const A4_HEIGHT_MM = 297; +const MARGIN_MM = 6.35; // 0.25 inches + +// Calculate maximum grid dimensions that fit both Letter and A4 with margins +function calculateGridDimensions(cellSize) { + // Available printable area (limiting factor is the smaller of Letter/A4 for each dimension) + const availableWidth = Math.min(LETTER_WIDTH_MM, A4_WIDTH_MM) - (2 * MARGIN_MM); + const availableHeight = Math.min(LETTER_HEIGHT_MM, A4_HEIGHT_MM) - (2 * MARGIN_MM); + + // Calculate how many cells fit + const cols = Math.floor(availableWidth / cellSize); + const rows = Math.floor(availableHeight / cellSize); + + return { cols, rows }; +} + +// Calculate grid dimensions as percentage of Letter paper (used for screen layout) +function calculateGridPercentages(cellSize, cols, rows) { + const gridWidthMM = cols * cellSize; + const gridHeightMM = rows * cellSize; + return { + widthPercent: (gridWidthMM / LETTER_WIDTH_MM) * 100, + heightPercent: (gridHeightMM / LETTER_HEIGHT_MM) * 100 + }; +} + +// Cell size bounds (in mm) +const MIN_CELL_SIZE_MM = 2; +const MAX_CELL_SIZE_MM = 10; + +let GRID_COLS = 49; +let GRID_ROWS = 66; +let CELL_SIZE_MM = 4; // Physical size of each cell when printed (can be overridden by URL parameter) const grid = document.getElementById('grid'); const page = document.querySelector('.page'); @@ -8,6 +42,54 @@ const page = document.querySelector('.page'); let popupElement = null; let popupTimeout = null; +// Parse URL parameters for custom cell size +function parseCellSizeFromURL() { + const urlParams = new URLSearchParams(window.location.search); + const gridSizeParam = urlParams.get('grid-size'); + + if (gridSizeParam) { + // Remove 'mm' suffix if present + const sizeStr = gridSizeParam.toLowerCase().replace('mm', '').trim(); + const size = parseFloat(sizeStr); + + // Check if size is valid + if (isNaN(size)) { + showPopup('Invalid grid size. Using default 4mm.', 3000); + return 4; + } + + // Check if size is within reasonable bounds + if (size < MIN_CELL_SIZE_MM || size > MAX_CELL_SIZE_MM) { + showPopup(`Grid size must be between ${MIN_CELL_SIZE_MM}mm and ${MAX_CELL_SIZE_MM}mm. Using default 4mm.`, 3500); + return 4; + } + + // Valid size + showPopup(`Grid set to ${size}mm`); + return size; + } + + return 4; // Default +} + +// Initialize cell size from URL +CELL_SIZE_MM = parseCellSizeFromURL(); + +// Calculate grid dimensions based on cell size +const gridDimensions = calculateGridDimensions(CELL_SIZE_MM); +GRID_COLS = gridDimensions.cols; +GRID_ROWS = gridDimensions.rows; + +// Calculate grid percentages for screen layout +const gridPercentages = calculateGridPercentages(CELL_SIZE_MM, GRID_COLS, GRID_ROWS); + +// Update CSS variables for both screen and print +document.documentElement.style.setProperty('--cell-size-mm', `${CELL_SIZE_MM}mm`); +document.documentElement.style.setProperty('--grid-cols', GRID_COLS); +document.documentElement.style.setProperty('--grid-rows', GRID_ROWS); +document.documentElement.style.setProperty('--grid-width-percent', `${gridPercentages.widthPercent}%`); +document.documentElement.style.setProperty('--grid-height-percent', `${gridPercentages.heightPercent}%`); + // Calculate cell size dynamically based on actual grid dimensions function getCellSize() { const gridRect = grid.getBoundingClientRect(); @@ -78,9 +160,27 @@ function getPixelPerfectBounds(cellX, cellY, cellWidth, cellHeight) { for (let i = 0; i < GRID_COLS * GRID_ROWS; i++) { const cell = document.createElement('div'); cell.className = 'grid-cell'; + + // Add right border to rightmost column + const col = i % GRID_COLS; + if (col === GRID_COLS - 1) { + cell.classList.add('right-edge'); + } + + // Add bottom border to bottom row + const row = Math.floor(i / GRID_COLS); + if (row === GRID_ROWS - 1) { + cell.classList.add('bottom-edge'); + } + grid.appendChild(cell); } +// Apply solid border style for grids 3.56mm or smaller +if (CELL_SIZE_MM <= 3.56) { + document.documentElement.classList.add('solid-grid'); +} + let images = []; let dragState = null; let resizeState = null; @@ -997,7 +1097,7 @@ window.addEventListener('afterprint', () => { // Theme system let currentThemeIndex = 0; let isF2Pressed = false; -const themes = ['sea-breeze', 'grape-soda', 'grapefruit', 'guac', 'mojito', 'toast']; +const themes = ['sea-breeze', 'grape-soda', 'grapefruit', 'guac', 'mojito', 'banana']; function setTheme(theme) { document.documentElement.setAttribute('data-theme', theme); diff --git a/style.css b/style.css @@ -12,11 +12,11 @@ --lime: #a9cf51; --avocado: #7a8520; - /* toast theme colors */ - --butter: #ffe598; - --white-wheat: #fffef9; - --crumb: #decca3; - --peanut-butter: #be852a; + /* banana theme colors */ + --peel: #ffcc12; + --flesh: #f8f5e3; + --unripe: #a5d269; + --bruise: #4d4235; /* mojito theme colors */ --mint: #9febaa; @@ -56,6 +56,7 @@ --desk: var(--cerulean); --page: var(--mist); --grid-line: var(--horizon); + --grid-line-light: color-mix(in srgb, var(--grid-line) 65%, transparent); --accent: var(--lagoon); /* Set text color for all themes */ @@ -73,11 +74,11 @@ --accent: var(--onion); } -:root[data-theme="toast"] { - --desk: var(--butter); - --page: var(--white-wheat); - --grid-line: var(--crumb); - --accent: var(--peanut-butter); +:root[data-theme="banana"] { + --desk: var(--peel); + --page: var(--flesh); + --grid-line: var(--unripe); + --accent: var(--bruise); } :root[data-theme="mojito"] { @@ -165,18 +166,36 @@ body { display: block; } -/* Add right border to rightmost column (every 49th cell starting from cell 49) */ -.grid-cell:nth-child(49n) { +/* Add right border to rightmost column */ +.grid-cell.right-edge { border-right: 1px dashed var(--grid-line); width: calc(100% + 1px); } -/* Add bottom border to bottom row (last 49 cells: 3185-3234) */ -.grid-cell:nth-child(n + 3185) { +/* Add bottom border to bottom row */ +.grid-cell.bottom-edge { border-bottom: 1px dashed var(--grid-line); height: calc(100% + 1px); } +/* Solid grid lines for cell sizes <= 3.56mm (screen preview only) */ +.solid-grid .grid-cell { + border-top-style: solid; + border-left-style: solid; + border-top-color: var(--grid-line-light); + border-left-color: var(--grid-line-light); +} + +.solid-grid .grid-cell.right-edge { + border-right-style: solid; + border-right-color: var(--grid-line-light); +} + +.solid-grid .grid-cell.bottom-edge { + border-bottom-style: solid; + border-bottom-color: var(--grid-line-light); +} + @media (max-width: 680px) { body { padding: 0; @@ -190,19 +209,19 @@ body { .grid-cell { border-top-style: solid; border-left-style: solid; - border-top-color: color-mix(in srgb, var(--grid-line) 65%, transparent); - border-left-color: color-mix(in srgb, var(--grid-line) 65%, transparent); + border-top-color: var(--grid-line-light); + border-left-color: var(--grid-line-light); } - .grid-cell:nth-child(49n) { + .grid-cell.right-edge { border-right-style: solid; - border-right-color: color-mix(in srgb, var(--grid-line) 65%, transparent); + border-right-color: var(--grid-line-light); width: calc(100% + 1px); } - .grid-cell:nth-child(n + 3185) { + .grid-cell.bottom-edge { border-bottom-style: solid; - border-bottom-color: color-mix(in srgb, var(--grid-line) 65%, transparent); + border-bottom-color: var(--grid-line-light); height: calc(100% + 1px); } } @@ -483,22 +502,16 @@ body.dragging * { padding: 0 !important; } - .grid-cell:nth-child(49n) { + .grid-cell.right-edge { border-right: 1px dashed var(--default-grid) !important; width: calc(100% + 1px) !important; } - .grid-cell:nth-child(n + 3185) { + .grid-cell.bottom-edge { border-bottom: 1px dashed var(--default-grid) !important; height: calc(100% + 1px) !important; } - /* Remove bottom border from cell above bottom-right corner to prevent artifact */ - .grid-cell:nth-child(3185) { - border-bottom: none !important; - height: 100% !important; - } - .image-container { outline: none !important; position: absolute !important; @@ -543,6 +556,10 @@ body.dragging * { .add-images-btn { display: none !important; } + + .popup-notification { + display: none !important; + } } @page { @@ -596,7 +613,6 @@ body.dragging * { transform: translateX(-50%); background-color: var(--accent); color: var(--page); - border: 2px solid var(--page); padding: 0.7rem 0.9rem; border-radius: 50rem; font-size: 1.2rem;