mirror of
https://github.com/GuySandler/CanvasRefined.git
synced 2026-11-03 22:07:18 +01:00
card grid
This commit is contained in:
parent
39964b9877
commit
87176b1973
@ -2,6 +2,7 @@
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Canvas Refined</title>
|
||||
<link href="../css/popup.css" rel="stylesheet">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
@ -839,6 +840,44 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option-container">
|
||||
<h3 class="header-small">Card Grid</h3>
|
||||
<div class="sub-option">
|
||||
<input type="checkbox" id="card_grid" name="card_grid">
|
||||
<label for="card_grid" class="sub-text">Card Grid</label>
|
||||
</div>
|
||||
<div id="card-grid-options" style="display:none; margin-top:12px;">
|
||||
<div style="display:flex;gap:18px;align-items:flex-start;flex-wrap:wrap;">
|
||||
<div id="card-grid-preview" title="Card grid preview" style="display:grid;gap:4px;padding:10px;background:#00000042;border:1px solid #3c3c3c;border-radius:10px;width:fit-content;"></div>
|
||||
<div style="display:flex;flex-direction:column;gap:8px;">
|
||||
<div style="display:flex;gap:8px;align-items:center;">
|
||||
<span class="sub-text" style="width:90px;">Horizontal</span>
|
||||
<input type="number" id="card_grid_columns" class="card-input" min="1" max="12" value="4" style="width:80px;margin-top:0;">
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;align-items:center;">
|
||||
<span class="sub-text" style="width:90px;">Vertical</span>
|
||||
<input type="number" id="card_grid_rows" class="card-input" min="1" max="12" value="3" style="width:80px;margin-top:0;">
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;align-items:center;">
|
||||
<span class="sub-text" style="width:90px;">Column spacing</span>
|
||||
<input type="number" id="card_grid_column_gap" class="card-input" min="0" max="100" value="12" style="width:80px;margin-top:0;">
|
||||
<span class="sub-text">px</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;align-items:center;">
|
||||
<span class="sub-text" style="width:90px;">Row spacing</span>
|
||||
<input type="number" id="card_grid_row_gap" class="card-input" min="0" max="100" value="12" style="width:80px;margin-top:0;">
|
||||
<span class="sub-text">px</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sub-option" style="margin-top:10px">
|
||||
<input type="checkbox" id="card_grid_center_rows" name="card_grid_center_rows">
|
||||
<label for="card_grid_center_rows" class="sub-text">Center uneven rows</label>
|
||||
</div>
|
||||
<p id="card-grid-warning" style="display:none;margin:10px 0 0;color:#ffd166;font-size:12px;font-weight:600;"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option-container">
|
||||
<h3 class="header-small">Missing cards?</h3>
|
||||
<div style="display: flex; gap: 10px; align-items: center;">
|
||||
|
||||
118
js/content.js
118
js/content.js
@ -993,6 +993,10 @@ function applyOptionsChanges(changes) {
|
||||
case "gpa_calc_cumulative":
|
||||
if (!grades) getGrades();
|
||||
setupGPACalc();
|
||||
// The GPA elements are placed on dedicated grid rows when Card
|
||||
// Grid is on (see applyAestheticChanges), so toggling GPA on/off
|
||||
// has to regenerate the grid CSS too.
|
||||
if (options.card_grid === true) debouncedApplyAestheticChanges();
|
||||
break;
|
||||
case "gpa_calc_bounds":
|
||||
calculateGPA2();
|
||||
@ -1064,6 +1068,12 @@ function applyOptionsChanges(changes) {
|
||||
case "cardWidth":
|
||||
case "cardHeight":
|
||||
case "cardPadding":
|
||||
case "card_grid":
|
||||
case "card_grid_columns":
|
||||
case "card_grid_rows":
|
||||
case "card_grid_column_gap":
|
||||
case "card_grid_row_gap":
|
||||
case "card_grid_center_rows":
|
||||
case "customCardStyles":
|
||||
// Coalesce rapid card-style edits (e.g. holding the arrow keys on a
|
||||
// number input) into a single applyAestheticChanges() call. Each
|
||||
@ -1117,6 +1127,14 @@ function applyOptionsChanges(changes) {
|
||||
break;
|
||||
}
|
||||
case "better_sidebar":
|
||||
// Better Sidebar mounts its whole layout on page load, so either
|
||||
// direction of the toggle reloads the page for a clean mount/
|
||||
// removal. The old-value guard keeps a re-save of the same value
|
||||
// from looping the reload.
|
||||
if (changes["better_sidebar"]?.oldValue !== options.better_sidebar) {
|
||||
window.location.reload();
|
||||
break;
|
||||
}
|
||||
if (options.better_sidebar) {
|
||||
ensureBetterSidebar();
|
||||
} else {
|
||||
@ -5881,6 +5899,10 @@ function customizeCards(c = null) {
|
||||
|
||||
});
|
||||
|
||||
// Hiding/unhiding cards changes how many cards sit in each grid row,
|
||||
// so recompute the uneven-row centering offset after visibility is set.
|
||||
centerUnevenGridRows();
|
||||
|
||||
} catch (e) {
|
||||
logError(e);
|
||||
}
|
||||
@ -6579,6 +6601,49 @@ function applyAestheticChanges() {
|
||||
if (options.disable_color_overlay === true) style.textContent += ".ic-DashboardCard__header_hero{opacity: 0!important} .ic-DashboardCard__header-button-bg{opacity: 1!important}";
|
||||
if (options.full_width === true) style.textContent += "#wrapper,.ic-Layout-wrapper{max-width:100%!important}";
|
||||
if (options.center_cards === true) style.textContent += ".ic-DashboardCard__box__container{display:flex!important;flex-wrap:wrap!important;justify-content:center!important;align-items:flex-start!important}";
|
||||
// Card Grid: lay the dashboard card container out as a strict columns x
|
||||
// rows grid chosen in the popup, with separate column/row spacing.
|
||||
// Added after center_cards so it wins the !important tie-break if both
|
||||
// are on. Hidden cards are display:none, so they don't take up grid
|
||||
// cells. Cards beyond the chosen cells fall into zero-height implicit
|
||||
// rows that overflow-hidden clips away — hence the "cards may be cut
|
||||
// off" warning in the popup. When Center Cards is also on, columns size
|
||||
// to the cards' natural width (they have a fixed width anyway) and the
|
||||
// whole grid is centered horizontally, mirroring what Center Cards does
|
||||
// in flex mode.
|
||||
//
|
||||
// Columns are doubled into "sub-columns" (each card spans 2 of them) so
|
||||
// "Center uneven rows" can shift a partial last row by half a card —
|
||||
// e.g. 3 cards under a 4-card row has exactly one column of leftover
|
||||
// space, which needs a half-column offset to look centered. Empty
|
||||
// sub-columns just make the odd case possible; full rows are unaffected.
|
||||
// Tracks are always max-content (Canvas cards have a fixed width, so the
|
||||
// tracks hug them exactly): spacing stays identical whether Center Cards
|
||||
// is on or off, instead of 1fr stretching cells and widening the visual
|
||||
// gaps. Center Cards then just centers the whole grid with
|
||||
// justify-content:center.
|
||||
//
|
||||
// The GPA calculator elements live in this same container (appended by
|
||||
// setupGPACalc), so when they're visible they get definite full-width
|
||||
// rows past the card rows — otherwise they'd take grid cells, land in
|
||||
// the middle of the card flow (they can be prepended), and throw off the
|
||||
// row math. Two spare auto-height template rows host them; when the GPA
|
||||
// feature is off they're display:none and the spare rows collapse to 0.
|
||||
if (options.card_grid === true) {
|
||||
const gridCols = Math.max(1, parseInt(options.card_grid_columns, 10) || 4);
|
||||
const gridRows = Math.max(1, parseInt(options.card_grid_rows, 10) || 3);
|
||||
const gridColGap = Math.max(0, !isNaN(parseInt(options.card_grid_column_gap, 10)) ? parseInt(options.card_grid_column_gap, 10) : 12);
|
||||
const gridRowGap = Math.max(0, !isNaN(parseInt(options.card_grid_row_gap, 10)) ? parseInt(options.card_grid_row_gap, 10) : 12);
|
||||
const centerGrid = options.center_cards === true;
|
||||
const gpaOn = options.gpa_calc === true;
|
||||
const totalRows = gridRows + (gpaOn ? 2 : 0);
|
||||
style.textContent += `.ic-DashboardCard__box__container{display:grid!important;grid-template-columns:repeat(${gridCols * 2},minmax(0,max-content))!important;grid-template-rows:repeat(${totalRows},minmax(0,auto))!important;grid-auto-rows:0!important;column-gap:${gridColGap}px!important;row-gap:${gridRowGap}px!important;align-items:start!important;overflow:hidden!important${centerGrid ? ";justify-content:center!important" : ""}}`;
|
||||
style.textContent += `.ic-DashboardCard__box__container > .ic-DashboardCard{grid-column:span 2!important}`;
|
||||
if (gpaOn) {
|
||||
style.textContent += `.ic-DashboardCard__box__container > .canvasrefined-gpa-card{grid-row:${gridRows + 1}!important;grid-column:span 2!important}`;
|
||||
style.textContent += `.ic-DashboardCard__box__container > .canvasrefined-gpa{grid-row:${gridRows + 2}!important;grid-column:1/-1!important}`;
|
||||
}
|
||||
}
|
||||
if (options.customCardStyles === true) {
|
||||
if (options.imageSize !== undefined && options.imageSize !== 100) style.textContent += `.ic-DashboardCard__header_image {transform: scale(${options.imageSize / 100})!important; }`;
|
||||
if (options.cardRoundness !== undefined && options.cardRoundness !== 5) style.textContent += `.ic-DashboardCard {border-radius: ${options.cardRoundness}px!important;}`;
|
||||
@ -6624,6 +6689,59 @@ function applyAestheticChanges() {
|
||||
if (options.hide_navbar === true) style.textContent += ".ic-app-nav-toggle-and-crumbs{display:none!important}";
|
||||
if (options.custom_styles !== "") style.textContent += options.custom_styles;
|
||||
document.documentElement.appendChild(style);
|
||||
// Uneven-row centering needs the real cards (it offsets the first card of
|
||||
// the last partial row), so schedule it just after the style lands. Run
|
||||
// unconditionally while any grid setting changes: the function clears
|
||||
// stale offsets first, which is what makes turning the option (or the
|
||||
// whole grid) OFF take effect without a page refresh.
|
||||
requestAnimationFrame(centerUnevenGridRows);
|
||||
}
|
||||
|
||||
/*
|
||||
Center uneven grid rows.
|
||||
|
||||
CSS grid always packs rows from the left, so a last row with fewer cards
|
||||
than the chosen column count sits flush-left while the rows above are full.
|
||||
Pure CSS can't center a partial row, so we offset the first card of the last
|
||||
partial row with grid-column-start.
|
||||
|
||||
The grid runs on double sub-columns (each card spans 2 — see
|
||||
applyAestheticChanges), which is what makes this possible at all: with 3
|
||||
cards under a 4-card row the leftover space is one column, and centering
|
||||
needs a HALF-column shift — impossible on plain column lines. On sub-columns
|
||||
the shift is a whole sub-column (half a card + half a gap), so every
|
||||
remainder can be centered exactly.
|
||||
|
||||
Only runs while Card Grid is on. Skips when the cards overflow the explicit
|
||||
template (those extra rows are clipped anyway, and the last visible row is
|
||||
full). Any previously applied offset is cleared first so re-runs (card
|
||||
hidden/unhidden, dashboard re-render, setting changes) start clean.
|
||||
*/
|
||||
function centerUnevenGridRows() {
|
||||
const container = document.querySelector(".ic-DashboardCard__box__container");
|
||||
if (!container) return;
|
||||
const cards = Array.from(container.children).filter(el => el.classList && el.classList.contains("ic-DashboardCard"));
|
||||
cards.forEach(card => card.style.removeProperty("grid-column"));
|
||||
if (options.card_grid !== true || options.card_grid_center_rows !== true) return;
|
||||
const cols = Math.max(1, parseInt(options.card_grid_columns, 10) || 4);
|
||||
const rows = Math.max(1, parseInt(options.card_grid_rows, 10) || 3);
|
||||
const visible = cards.filter(card => getComputedStyle(card).display !== "none");
|
||||
const count = visible.length;
|
||||
// Overflowing the template: extra cards land in clipped implicit rows and
|
||||
// the last explicit row is full, so there's nothing to center.
|
||||
if (count === 0 || count >= cols * rows) return;
|
||||
const lastRowStart = Math.floor((count - 1) / cols) * cols;
|
||||
const inLastRow = count - lastRowStart;
|
||||
if (inLastRow >= cols) return;
|
||||
// Offset in sub-columns: each card spans 2 sub-columns, so the leftover
|
||||
// space is 2 * (cols - inLastRow) sub-columns and centering shifts by
|
||||
// half of it. The explicit start must be paired with an explicit span,
|
||||
// or the card would collapse to a single sub-column. Both are set with
|
||||
// "important" priority because the stylesheet span rule is !important
|
||||
// too — plain inline styles would lose to it and the offset would never
|
||||
// take effect.
|
||||
const offset = cols - inLastRow;
|
||||
if (offset > 0) visible[lastRowStart].style.setProperty("grid-column", `${offset + 1} / span 2`, "important");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
156
js/popup.js
156
js/popup.js
@ -40,6 +40,15 @@ const syncedSubOptions = [
|
||||
"cardWidth",
|
||||
"cardHeight",
|
||||
"cardPadding",
|
||||
// Card Grid settings — included here so theme exports, saved themes and
|
||||
// previous-theme snapshots actually read them from storage (getExport
|
||||
// drops keys it wasn't given).
|
||||
"card_grid",
|
||||
"card_grid_columns",
|
||||
"card_grid_rows",
|
||||
"card_grid_column_gap",
|
||||
"card_grid_row_gap",
|
||||
"card_grid_center_rows",
|
||||
"customBackgroundLink",
|
||||
"customBackgroundScale",
|
||||
"customBackgroundDaily",
|
||||
@ -58,7 +67,7 @@ const localSwitches = [];
|
||||
// Theme export only carries visual settings, never personal productivity data.
|
||||
const exportDarkSchedule = ["auto_dark", "auto_dark_start", "auto_dark_end", "device_dark"];
|
||||
const exportCardColorToggles = ["gradient_cards", "disable_color_overlay"];
|
||||
const exportCardStyles = ["customCardStyles", "imageSize", "cardRoundness", "imageRoundness", "cardSpacing", "cardWidth", "cardHeight", "cardPadding"];
|
||||
const exportCardStyles = ["customCardStyles", "imageSize", "cardRoundness", "imageRoundness", "cardSpacing", "cardWidth", "cardHeight", "cardPadding", "card_grid", "card_grid_columns", "card_grid_rows", "card_grid_column_gap", "card_grid_row_gap", "card_grid_center_rows"];
|
||||
const exportLayout = ["full_width", "center_cards", "condensed_cards", "equal_height_cards", "remlogo", "hide_new_canvas", "hide_navbar", "tab_icons"];
|
||||
const exportSidebar = ["better_sidebar", "sidebar_scale"];
|
||||
const exportTodo = ["better_todo", "todo_hide_feedback", "todo_hide_read", "todo_full_height", "todo_confetti", "todo_progress_rings", "todo_timeframe", "todo_hr24", "todo_separate_scrollbar", "todo_alternate_colors", "todo_ignore_card_colors", "todo_remove_icons", "todo_show_scores", "hover_preview"];
|
||||
@ -186,6 +195,12 @@ const defaultOptions = {
|
||||
"cardWidth": 262,
|
||||
"cardHeight": 146,
|
||||
"cardPadding": 0,
|
||||
"card_grid": false,
|
||||
"card_grid_columns": 4,
|
||||
"card_grid_rows": 3,
|
||||
"card_grid_column_gap": 12,
|
||||
"card_grid_row_gap": 12,
|
||||
"card_grid_center_rows": false,
|
||||
"customCardStyles": false,
|
||||
"customBackgroundLink": "",
|
||||
"customBackgroundScale": 100,
|
||||
@ -201,9 +216,12 @@ sendFromPopup("getCards");
|
||||
// refresh the cards if new ones were just recieved
|
||||
chrome.storage.onChanged.addListener((changes) => {
|
||||
if (changes["custom_cards"]) {
|
||||
if (Object.keys(changes["custom_cards"].oldValue).length !== Object.keys(changes["custom_cards"].newValue).length) {
|
||||
if (Object.keys(changes["custom_cards"].oldValue || {}).length !== Object.keys(changes["custom_cards"].newValue || {}).length) {
|
||||
displayAdvancedCards();
|
||||
}
|
||||
// Hidden-card edits from the card menu change how many cells the
|
||||
// grid preview should mark as filled.
|
||||
updateCardGridPreview();
|
||||
}
|
||||
});
|
||||
|
||||
@ -450,6 +468,109 @@ function setupCardPaddingInput(initial) {
|
||||
});
|
||||
}
|
||||
|
||||
// Card Grid (dashboard card layout). The toggle lives in menu.checkboxes;
|
||||
// this wires the reveal of the options panel plus the squares preview and
|
||||
// the "some cards may be cut off" warning.
|
||||
function setupCardGrid(initial) {
|
||||
const panel = document.getElementById("card-grid-options");
|
||||
if (!panel) return;
|
||||
panel.style.display = initial === true ? "" : "none";
|
||||
// Defer the first render: setupCardGrid runs inside the special-options
|
||||
// loop BEFORE the column/row/gap inputs get their stored values
|
||||
// (setupCardGridCountInput), so an immediate render would use the HTML
|
||||
// defaults and look wrong until a value changes. A 0ms timeout runs once
|
||||
// the whole synchronous setup pass is done.
|
||||
setTimeout(() => updateCardGridPreview(), 0);
|
||||
document.getElementById("card_grid").addEventListener("change", (e) => {
|
||||
panel.style.display = e.target.checked ? "" : "none";
|
||||
if (e.target.checked) updateCardGridPreview();
|
||||
});
|
||||
// Row-centering only affects the preview's last-row offset.
|
||||
document.getElementById("card_grid_center_rows").addEventListener("change", () => {
|
||||
updateCardGridPreview();
|
||||
});
|
||||
}
|
||||
|
||||
// Grid count/spacing inputs for the card grid. Update the preview
|
||||
// immediately on every keystroke, but debounce the storage write like the
|
||||
// other card style number inputs. `fallback` is used when the field is
|
||||
// cleared/invalid — 1 for counts, 0 for spacings.
|
||||
function setupCardGridCountInput(id, initial, fallback = 1) {
|
||||
const el = document.getElementById(id);
|
||||
if (!el) return;
|
||||
el.value = initial;
|
||||
el.addEventListener("input", (e) => {
|
||||
updateCardGridPreview();
|
||||
const num = parseInt(e.target.value, 10);
|
||||
debouncedCardStyleSet(id, isNaN(num) ? fallback : num);
|
||||
});
|
||||
}
|
||||
|
||||
// Number of dashboard cards that will occupy grid cells: every stored card
|
||||
// that isn't hidden via the card menu. Hidden cards get display:none in the
|
||||
// dashboard, so they don't take up a grid slot.
|
||||
function countActiveDashboardCards(cards) {
|
||||
return Object.values(cards || {}).filter(c => c && typeof c === "object" && c.hidden !== true && c.hide !== true).length;
|
||||
}
|
||||
|
||||
// Squares preview: one square per grid cell. Filled squares = cells covered
|
||||
// by an active (non-hidden) card; dim squares = empty cells. Warns when the
|
||||
// grid can't fit every active card.
|
||||
function updateCardGridPreview() {
|
||||
const panel = document.getElementById("card-grid-options");
|
||||
const preview = document.getElementById("card-grid-preview");
|
||||
if (!panel || !preview || panel.style.display === "none") return;
|
||||
const cols = Math.max(1, parseInt(document.getElementById("card_grid_columns").value, 10) || 1);
|
||||
const rows = Math.max(1, parseInt(document.getElementById("card_grid_rows").value, 10) || 1);
|
||||
const colGapRaw = parseInt(document.getElementById("card_grid_column_gap").value, 10);
|
||||
const colGap = Math.max(0, Math.min(10, isNaN(colGapRaw) ? 12 : colGapRaw));
|
||||
const total = cols * rows;
|
||||
preview.style.gridTemplateColumns = `repeat(${cols}, 18px)`;
|
||||
// Echo the chosen column spacing in the preview (clamped so extreme
|
||||
// values don't blow the layout out).
|
||||
preview.style.columnGap = `${colGap}px`;
|
||||
preview.style.rowGap = "4px";
|
||||
preview.innerHTML = "";
|
||||
chrome.storage.sync.get("custom_cards", s => {
|
||||
// Grid may have been toggled off while the storage read was pending.
|
||||
if (document.getElementById("card-grid-options").style.display === "none") return;
|
||||
const active = countActiveDashboardCards(s.custom_cards);
|
||||
// Uneven-row centering: the real grid shifts the last partial row in
|
||||
// half-card steps (double sub-columns — see centerUnevenGridRows).
|
||||
// In the preview that's a margin on every square of that row; since
|
||||
// the squares shift into space where no neighbor sits, nothing
|
||||
// overlaps.
|
||||
let lastRowStart = -1, offset = 0;
|
||||
if (document.getElementById("card_grid_center_rows")?.checked === true && active > 0 && active < total) {
|
||||
lastRowStart = Math.floor((active - 1) / cols) * cols;
|
||||
const inLastRow = active - lastRowStart;
|
||||
if (inLastRow < cols) offset = cols - inLastRow;
|
||||
}
|
||||
for (let i = 0; i < total; i++) {
|
||||
const inShiftedRow = lastRowStart !== -1 && i >= lastRowStart;
|
||||
// The shifted row's empty cells aren't rendered — the row's filled
|
||||
// squares carry the offset, so the empties would misrepresent it.
|
||||
if (inShiftedRow && i >= active) continue;
|
||||
const square = document.createElement("div");
|
||||
square.style.cssText = "width:18px;height:18px;border-radius:4px;box-sizing:border-box;";
|
||||
square.style.background = i < active ? "#56Caf0" : "#3c3c3c";
|
||||
if (inShiftedRow && offset > 0) {
|
||||
square.style.marginLeft = `${offset * (18 + colGap) / 2}px`;
|
||||
}
|
||||
preview.appendChild(square);
|
||||
}
|
||||
const warning = document.getElementById("card-grid-warning");
|
||||
if (warning) {
|
||||
if (active > total) {
|
||||
warning.textContent = `\u26A0 Your grid holds ${total} card${total === 1 ? "" : "s"} but you have ${active} active card${active === 1 ? "" : "s"} - some cards may be cut off.`;
|
||||
warning.style.display = "block";
|
||||
} else {
|
||||
warning.style.display = "none";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setupCustomBackgroundLink(initial) {
|
||||
let el = document.querySelector("#customBackgroundLink");
|
||||
el.value = initial || "";
|
||||
@ -980,6 +1101,8 @@ function setup() {
|
||||
"fitImageToScreen",
|
||||
"card_transparency",
|
||||
"customCardStyles",
|
||||
"card_grid",
|
||||
"card_grid_center_rows",
|
||||
"grade_analytics_zones",
|
||||
],
|
||||
tabs: {
|
||||
@ -1097,6 +1220,26 @@ function setup() {
|
||||
identifier: "cardPadding",
|
||||
setup: (initial) => setupCardPaddingInput(initial),
|
||||
},
|
||||
{
|
||||
identifier: "card_grid",
|
||||
setup: (initial) => setupCardGrid(initial),
|
||||
},
|
||||
{
|
||||
identifier: "card_grid_columns",
|
||||
setup: (initial) => setupCardGridCountInput("card_grid_columns", initial),
|
||||
},
|
||||
{
|
||||
identifier: "card_grid_rows",
|
||||
setup: (initial) => setupCardGridCountInput("card_grid_rows", initial),
|
||||
},
|
||||
{
|
||||
identifier: "card_grid_column_gap",
|
||||
setup: (initial) => setupCardGridCountInput("card_grid_column_gap", initial, 0),
|
||||
},
|
||||
{
|
||||
identifier: "card_grid_row_gap",
|
||||
setup: (initial) => setupCardGridCountInput("card_grid_row_gap", initial, 0),
|
||||
},
|
||||
{
|
||||
identifier: "customBackgroundLink",
|
||||
setup: (initial) => setupCustomBackgroundLink(initial),
|
||||
@ -1906,6 +2049,15 @@ function saveCurrentTheme() {
|
||||
"cardSpacing": current["cardSpacing"],
|
||||
"cardWidth": current["cardWidth"],
|
||||
"cardHeight": current["cardHeight"],
|
||||
"cardPadding": current["cardPadding"],
|
||||
// Card Grid (part of card styles): layout toggle, counts,
|
||||
// spacing and uneven-row centering.
|
||||
"card_grid": current["card_grid"],
|
||||
"card_grid_columns": current["card_grid_columns"],
|
||||
"card_grid_rows": current["card_grid_rows"],
|
||||
"card_grid_column_gap": current["card_grid_column_gap"],
|
||||
"card_grid_row_gap": current["card_grid_row_gap"],
|
||||
"card_grid_center_rows": current["card_grid_center_rows"],
|
||||
"custom_styles": current["custom_styles"],
|
||||
"customCardStyles": current["customCardStyles"],
|
||||
"customBackgroundLink": current["customBackgroundLink"],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user