feat: split logo scale by viewport
This commit is contained in:
@@ -178,10 +178,8 @@
|
||||
return `#${hex}`;
|
||||
}
|
||||
|
||||
function homeLogoScale(theme) {
|
||||
const scale = Number(theme.tokens?.home_logo_scale || 100);
|
||||
if (!Number.isFinite(scale)) return 100;
|
||||
return Math.min(300, Math.max(50, Math.round(scale)));
|
||||
function homeLogoScale(theme, mode) {
|
||||
return themesStore.resolveThemeHomeLogoScale(theme, mode);
|
||||
}
|
||||
|
||||
function openThemeAccentPicker(theme) {
|
||||
@@ -296,8 +294,8 @@
|
||||
themesStore.setThemeAccent(theme.key, value);
|
||||
}
|
||||
|
||||
function setThemeHomeLogoScale(theme, value) {
|
||||
themesStore.setThemeHomeLogoScale(theme.key, value);
|
||||
function setThemeHomeLogoScale(theme, mode, value) {
|
||||
themesStore.setThemeHomeLogoScale(theme.key, mode, value);
|
||||
}
|
||||
|
||||
function isThemeControlTarget(target) {
|
||||
@@ -586,11 +584,11 @@
|
||||
<span>{at("themes_use_in_admin", {}, "Использовать в админке")}</span>
|
||||
</label>
|
||||
<div class="admin-theme-card-option appearance-logo-scale-row">
|
||||
<span
|
||||
<span class="appearance-logo-scale-label"
|
||||
>{at(
|
||||
"appearance_theme_home_logo_scale",
|
||||
"appearance_theme_home_logo_scale_desktop",
|
||||
{},
|
||||
"Логотип на главной и входе"
|
||||
"Логотип на десктопе"
|
||||
)}</span
|
||||
>
|
||||
<RangeInput
|
||||
@@ -598,9 +596,13 @@
|
||||
min="50"
|
||||
max="300"
|
||||
step="5"
|
||||
ariaLabel={at("appearance_theme_home_logo_scale", {}, "Home logo scale")}
|
||||
value={homeLogoScale(theme)}
|
||||
onValueChange={(value) => setThemeHomeLogoScale(theme, value)}
|
||||
ariaLabel={at(
|
||||
"appearance_theme_home_logo_scale_desktop",
|
||||
{},
|
||||
"Desktop logo scale"
|
||||
)}
|
||||
value={homeLogoScale(theme, "desktop")}
|
||||
onValueChange={(value) => setThemeHomeLogoScale(theme, "desktop", value)}
|
||||
/>
|
||||
<span class="appearance-logo-scale-value">
|
||||
<Input
|
||||
@@ -609,8 +611,44 @@
|
||||
min="50"
|
||||
max="300"
|
||||
step="5"
|
||||
value={homeLogoScale(theme)}
|
||||
oninput={(event) => setThemeHomeLogoScale(theme, event.currentTarget.value)}
|
||||
value={homeLogoScale(theme, "desktop")}
|
||||
oninput={(event) =>
|
||||
setThemeHomeLogoScale(theme, "desktop", event.currentTarget.value)}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
<div class="admin-theme-card-option appearance-logo-scale-row">
|
||||
<span class="appearance-logo-scale-label"
|
||||
>{at(
|
||||
"appearance_theme_home_logo_scale_mobile",
|
||||
{},
|
||||
"Логотип на мобильных"
|
||||
)}</span
|
||||
>
|
||||
<RangeInput
|
||||
class="appearance-logo-scale-range"
|
||||
min="50"
|
||||
max="300"
|
||||
step="5"
|
||||
ariaLabel={at(
|
||||
"appearance_theme_home_logo_scale_mobile",
|
||||
{},
|
||||
"Mobile logo scale"
|
||||
)}
|
||||
value={homeLogoScale(theme, "mobile")}
|
||||
onValueChange={(value) => setThemeHomeLogoScale(theme, "mobile", value)}
|
||||
/>
|
||||
<span class="appearance-logo-scale-value">
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="50"
|
||||
max="300"
|
||||
step="5"
|
||||
value={homeLogoScale(theme, "mobile")}
|
||||
oninput={(event) =>
|
||||
setThemeHomeLogoScale(theme, "mobile", event.currentTarget.value)}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
@@ -847,10 +885,15 @@
|
||||
|
||||
.appearance-logo-scale-row {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(96px, 1fr) auto;
|
||||
grid-template-columns: minmax(112px, 0.8fr) minmax(96px, 1fr) auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.appearance-logo-scale-label {
|
||||
min-width: 0;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
:global(.appearance-logo-scale-range) {
|
||||
width: 100%;
|
||||
accent-color: var(--accent);
|
||||
@@ -910,5 +953,13 @@
|
||||
.appearance-url-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.appearance-logo-scale-row {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
}
|
||||
|
||||
:global(.appearance-logo-scale-range) {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -29,9 +29,13 @@ function applyDemoThemeTokens(catalog) {
|
||||
const themes = catalog?.themes || [];
|
||||
for (const theme of themes) {
|
||||
theme.tokens = theme.tokens || {};
|
||||
const currentScale = Number(theme.tokens.home_logo_scale);
|
||||
if (!Number.isFinite(currentScale) || currentScale > DEMO_HOME_LOGO_SCALE) {
|
||||
theme.tokens.home_logo_scale = DEMO_HOME_LOGO_SCALE;
|
||||
const logoScaleKeys = ["home_logo_scale_desktop", "home_logo_scale_mobile"];
|
||||
for (const key of ["home_logo_scale", ...logoScaleKeys]) {
|
||||
if (key !== "home_logo_scale" && !(key in theme.tokens)) continue;
|
||||
const currentScale = Number(theme.tokens[key]);
|
||||
if (!Number.isFinite(currentScale) || currentScale > DEMO_HOME_LOGO_SCALE) {
|
||||
theme.tokens[key] = DEMO_HOME_LOGO_SCALE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,23 @@ function cloneCatalog(catalog) {
|
||||
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
const HOME_LOGO_SCALE_TOKEN = {
|
||||
desktop: "home_logo_scale_desktop",
|
||||
mobile: "home_logo_scale_mobile",
|
||||
};
|
||||
|
||||
function normalizeHomeLogoScale(scale) {
|
||||
if (String(scale ?? "").trim() === "") scale = 100;
|
||||
const numeric = Number(scale);
|
||||
return Number.isFinite(numeric) ? Math.min(300, Math.max(50, Math.round(numeric))) : 100;
|
||||
}
|
||||
|
||||
function resolveThemeHomeLogoScale(theme, mode = "desktop") {
|
||||
const tokens = theme?.tokens || {};
|
||||
const modeKey = HOME_LOGO_SCALE_TOKEN[mode] || HOME_LOGO_SCALE_TOKEN.desktop;
|
||||
return normalizeHomeLogoScale(tokens[modeKey] ?? tokens.home_logo_scale ?? 100);
|
||||
}
|
||||
|
||||
export function createThemesStore({ api, onThemesSaved, flash, at }) {
|
||||
const state = writable({
|
||||
themesCatalog: { default_theme: "dark", themes: [] },
|
||||
@@ -214,27 +231,29 @@ export function createThemesStore({ api, onThemesSaved, flash, at }) {
|
||||
}));
|
||||
}
|
||||
|
||||
function setThemeHomeLogoScale(key, scale) {
|
||||
if (String(scale ?? "").trim() === "") scale = 100;
|
||||
const numeric = Number(scale);
|
||||
const nextScale = Number.isFinite(numeric)
|
||||
? Math.min(300, Math.max(50, Math.round(numeric)))
|
||||
: 100;
|
||||
function setThemeHomeLogoScale(key, mode, scale) {
|
||||
const normalizedMode = mode === "mobile" ? "mobile" : "desktop";
|
||||
const nextScale = normalizeHomeLogoScale(scale);
|
||||
state.update((s) => ({
|
||||
...s,
|
||||
themesCatalog: {
|
||||
...s.themesCatalog,
|
||||
themes: (s.themesCatalog.themes || []).map((theme) =>
|
||||
theme.key === key
|
||||
? {
|
||||
...theme,
|
||||
tokens: {
|
||||
...(theme.tokens || {}),
|
||||
home_logo_scale: nextScale === 100 ? null : nextScale,
|
||||
},
|
||||
}
|
||||
: theme
|
||||
),
|
||||
themes: (s.themesCatalog.themes || []).map((theme) => {
|
||||
if (theme.key !== key) return theme;
|
||||
const desktopScale =
|
||||
normalizedMode === "desktop" ? nextScale : resolveThemeHomeLogoScale(theme, "desktop");
|
||||
const mobileScale =
|
||||
normalizedMode === "mobile" ? nextScale : resolveThemeHomeLogoScale(theme, "mobile");
|
||||
return {
|
||||
...theme,
|
||||
tokens: {
|
||||
...(theme.tokens || {}),
|
||||
home_logo_scale: null,
|
||||
home_logo_scale_desktop: desktopScale === 100 ? null : desktopScale,
|
||||
home_logo_scale_mobile: mobileScale === 100 ? null : mobileScale,
|
||||
},
|
||||
};
|
||||
}),
|
||||
},
|
||||
}));
|
||||
}
|
||||
@@ -246,6 +265,7 @@ export function createThemesStore({ api, onThemesSaved, flash, at }) {
|
||||
setCurrentTheme,
|
||||
setThemeAccent,
|
||||
setThemeHomeLogoScale,
|
||||
resolveThemeHomeLogoScale,
|
||||
togglePrimaryAccent,
|
||||
toggleAdminUse,
|
||||
uploadLogoFile,
|
||||
|
||||
@@ -113529,6 +113529,54 @@ export const DEMO_DATASET = {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "admin_appearance_theme_home_logo_scale_desktop",
|
||||
audience: "internal",
|
||||
values: {
|
||||
ru: {
|
||||
base: "Логотип на десктопе",
|
||||
fallback: "Логотип на десктопе",
|
||||
effective: "Логотип на десктопе",
|
||||
override: "",
|
||||
overridden: false,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
},
|
||||
en: {
|
||||
base: "Desktop logo scale",
|
||||
fallback: "Логотип на десктопе",
|
||||
effective: "Desktop logo scale",
|
||||
override: "",
|
||||
overridden: false,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "admin_appearance_theme_home_logo_scale_mobile",
|
||||
audience: "internal",
|
||||
values: {
|
||||
ru: {
|
||||
base: "Логотип на мобильных",
|
||||
fallback: "Логотип на мобильных",
|
||||
effective: "Логотип на мобильных",
|
||||
override: "",
|
||||
overridden: false,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
},
|
||||
en: {
|
||||
base: "Mobile logo scale",
|
||||
fallback: "Логотип на мобильных",
|
||||
effective: "Mobile logo scale",
|
||||
override: "",
|
||||
overridden: false,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "admin_appearance_themes_sub",
|
||||
audience: "internal",
|
||||
|
||||
@@ -33,6 +33,8 @@ const TOKEN_TO_CSS_VAR = {
|
||||
font_logo: "--font-logo",
|
||||
font_mono: "--font-mono",
|
||||
home_logo_scale: "--home-logo-scale",
|
||||
home_logo_scale_desktop: "--home-logo-scale-desktop",
|
||||
home_logo_scale_mobile: "--home-logo-scale-mobile",
|
||||
admin_bg: "--admin-bg",
|
||||
admin_surface: "--admin-surface",
|
||||
admin_surface_2: "--admin-surface-2",
|
||||
@@ -44,6 +46,12 @@ const TOKEN_TO_CSS_VAR = {
|
||||
admin_dim: "--admin-dim",
|
||||
};
|
||||
|
||||
const LOGO_SCALE_TOKEN_KEYS = new Set([
|
||||
"home_logo_scale",
|
||||
"home_logo_scale_desktop",
|
||||
"home_logo_scale_mobile",
|
||||
]);
|
||||
|
||||
export function themeTokensToInlineStyle(tokens, primaryFallback = "#00fe7a", options = {}) {
|
||||
const t = tokens && typeof tokens === "object" ? tokens : {};
|
||||
const parts = [];
|
||||
@@ -54,7 +62,7 @@ export function themeTokensToInlineStyle(tokens, primaryFallback = "#00fe7a", op
|
||||
if (key === "accent") continue;
|
||||
const value = t[key];
|
||||
if (value === undefined || value === null || value === "") continue;
|
||||
if (key === "home_logo_scale") {
|
||||
if (LOGO_SCALE_TOKEN_KEYS.has(key)) {
|
||||
const scale = Number(value);
|
||||
if (!Number.isFinite(scale) || scale <= 0) continue;
|
||||
parts.push(`${cssVar}:${scale / 100}`);
|
||||
|
||||
@@ -111,6 +111,7 @@ input {
|
||||
}
|
||||
|
||||
.app-shell {
|
||||
--home-logo-scale-effective: var(--home-logo-scale-mobile, var(--home-logo-scale, 1));
|
||||
min-height: 100dvh;
|
||||
background: var(--bg, #02070b) !important;
|
||||
}
|
||||
@@ -119,3 +120,9 @@ input {
|
||||
--desktop-rail-width: 252px;
|
||||
--desktop-page-gutter: clamp(28px, 4vw, 72px);
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.app-shell {
|
||||
--home-logo-scale-effective: var(--home-logo-scale-desktop, var(--home-logo-scale, 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,9 +64,9 @@ a {
|
||||
}
|
||||
|
||||
.app-shell .loader .brand-mark.brand-mark-lg {
|
||||
width: calc(4.125rem * var(--home-logo-scale, 1));
|
||||
height: calc(4.125rem * var(--home-logo-scale, 1));
|
||||
font-size: calc(2.875rem * var(--home-logo-scale, 1));
|
||||
width: calc(4.125rem * var(--home-logo-scale-effective, 1));
|
||||
height: calc(4.125rem * var(--home-logo-scale-effective, 1));
|
||||
font-size: calc(2.875rem * var(--home-logo-scale-effective, 1));
|
||||
}
|
||||
|
||||
.app-header,
|
||||
@@ -2207,15 +2207,15 @@ a {
|
||||
}
|
||||
|
||||
.app-shell .home-brand .brand-mark.brand-mark-xl {
|
||||
width: calc(6rem * var(--home-logo-scale, 1));
|
||||
height: calc(6rem * var(--home-logo-scale, 1));
|
||||
font-size: calc(4.375rem * var(--home-logo-scale, 1));
|
||||
width: calc(6rem * var(--home-logo-scale-effective, 1));
|
||||
height: calc(6rem * var(--home-logo-scale-effective, 1));
|
||||
font-size: calc(4.375rem * var(--home-logo-scale-effective, 1));
|
||||
}
|
||||
|
||||
.app-shell .login-brand-auth .brand-mark.brand-mark-xl {
|
||||
width: calc(116px * var(--home-logo-scale, 1));
|
||||
height: calc(116px * var(--home-logo-scale, 1));
|
||||
font-size: calc(84px * var(--home-logo-scale, 1));
|
||||
width: calc(116px * var(--home-logo-scale-effective, 1));
|
||||
height: calc(116px * var(--home-logo-scale-effective, 1));
|
||||
font-size: calc(84px * var(--home-logo-scale-effective, 1));
|
||||
}
|
||||
|
||||
.home-bottom {
|
||||
@@ -3027,9 +3027,9 @@ a {
|
||||
.app-shell .home-brand .brand-mark,
|
||||
.app-shell .home-brand .brand-mark.brand-mark-lg,
|
||||
.app-shell .home-brand .brand-mark.brand-mark-xl {
|
||||
width: calc(clamp(180px, 18vw, 260px) * var(--home-logo-scale, 1));
|
||||
height: calc(clamp(180px, 18vw, 260px) * var(--home-logo-scale, 1));
|
||||
font-size: calc(clamp(124px, 13vw, 184px) * var(--home-logo-scale, 1));
|
||||
width: calc(clamp(180px, 18vw, 260px) * var(--home-logo-scale-effective, 1));
|
||||
height: calc(clamp(180px, 18vw, 260px) * var(--home-logo-scale-effective, 1));
|
||||
font-size: calc(clamp(124px, 13vw, 184px) * var(--home-logo-scale-effective, 1));
|
||||
}
|
||||
|
||||
.home-bottom {
|
||||
|
||||
Reference in New Issue
Block a user