better formatting

This commit is contained in:
Hellings 2026-10-23 09:12:49 -04:00
parent ebc85b2938
commit a25da3fc7b
74 changed files with 6910 additions and 4861 deletions

209
index.ts
View file

@ -6,38 +6,109 @@
*/ */
import { fileURLToPath } from "node:url"; import { fileURLToPath } from "node:url";
import { readFile } from "node:fs/promises"; import { readFile } from "node:fs/promises";
import type { import type { Integration, Mounts } from "muddle";
Integration,
Mounts,
} from "muddle";
import type { Views } from "muddle/views"; import type { Views } from "muddle/views";
export interface AmezingAccentPreset {
export interface AmezingAccentPreset { name: string; light: string; dark: string } name: string;
light: string;
dark: string;
}
/** Accent presets from ametrine/data/accent_presets.toml. */ /** Accent presets from ametrine/data/accent_presets.toml. */
export const ACCENT_PRESETS: Record<string, AmezingAccentPreset> = { export const ACCENT_PRESETS: Record<string, AmezingAccentPreset> = {
red: { name: "red", light: "hsl(342.0779, 72%, 58%)", dark: "hsl(345.18988, 100%, 69%)" }, red: {
orange: { name: "orange", light: "hsl(15.771428, 74%, 54%)", dark: "hsl(19.731544, 96%, 70%)" }, name: "red",
yellow: { name: "yellow", light: "hsl(34.639175, 91%, 42%)", dark: "hsl(44.70588, 100%, 70%)" }, light: "hsl(342.0779, 72%, 58%)",
green: { name: "green", light: "hsl(153.7815, 61%, 38%)", dark: "hsl(90, 59%, 66%)" }, dark: "hsl(345.18988, 100%, 69%)",
blue: { name: "blue", light: "hsl(192, 71%, 38%)", dark: "hsl(186.42857, 71%, 69%)" }, },
purple: { name: "purple", light: "hsl(254.11766, 44%, 55%)", dark: "hsl(249.88234, 77%, 78%)" }, orange: {
teal: { name: "teal", light: "hsl(180, 65%, 35%)", dark: "hsl(183, 85%, 65%)" }, name: "orange",
pink: { name: "pink", light: "hsl(333.88236, 69%, 58%)", dark: "hsl(336.78634, 100%, 70%)" }, light: "hsl(15.771428, 74%, 54%)",
cyan: { name: "cyan", light: "hsl(195, 71%, 35%)", dark: "hsl(193.41046, 72%, 70%)" }, dark: "hsl(19.731544, 96%, 70%)",
indigo: { name: "indigo", light: "hsl(232.05884, 61%, 42%)", dark: "hsl(234.61538, 73%, 71%)" }, },
amber: { name: "amber", light: "hsl(38.57695, 94%, 44%)", dark: "hsl(40.35484, 100%, 72%)" }, yellow: {
ochrea: { name: "ochrea", light: "hsl(45.75298, 95%, 45%)", dark: "hsl(46.09091, 100%, 78%)" }, name: "yellow",
lime: { name: "lime", light: "hsl(86.25406, 60%, 42%)", dark: "hsl(86.84211, 93%, 71%)" }, light: "hsl(34.639175, 91%, 42%)",
maroon: { name: "maroon", light: "hsl(321.81819, 26%, 41%)", dark: "hsl(322.10526, 66%, 66%)" }, dark: "hsl(44.70588, 100%, 70%)",
navy: { name: "navy", light: "hsl(216, 44%, 38%)", dark: "hsl(218, 69%, 69%)" }, },
olive: { name: "olive", light: "hsl(81, 36%, 41%)", dark: "hsl(81, 64%, 65%)" }, green: {
slate: { name: "slate", light: "hsl(212.53197, 15%, 44%)", dark: "hsl(212.90323, 61%, 72%)" }, name: "green",
light: "hsl(153.7815, 61%, 38%)",
dark: "hsl(90, 59%, 66%)",
},
blue: {
name: "blue",
light: "hsl(192, 71%, 38%)",
dark: "hsl(186.42857, 71%, 69%)",
},
purple: {
name: "purple",
light: "hsl(254.11766, 44%, 55%)",
dark: "hsl(249.88234, 77%, 78%)",
},
teal: {
name: "teal",
light: "hsl(180, 65%, 35%)",
dark: "hsl(183, 85%, 65%)",
},
pink: {
name: "pink",
light: "hsl(333.88236, 69%, 58%)",
dark: "hsl(336.78634, 100%, 70%)",
},
cyan: {
name: "cyan",
light: "hsl(195, 71%, 35%)",
dark: "hsl(193.41046, 72%, 70%)",
},
indigo: {
name: "indigo",
light: "hsl(232.05884, 61%, 42%)",
dark: "hsl(234.61538, 73%, 71%)",
},
amber: {
name: "amber",
light: "hsl(38.57695, 94%, 44%)",
dark: "hsl(40.35484, 100%, 72%)",
},
ochrea: {
name: "ochrea",
light: "hsl(45.75298, 95%, 45%)",
dark: "hsl(46.09091, 100%, 78%)",
},
lime: {
name: "lime",
light: "hsl(86.25406, 60%, 42%)",
dark: "hsl(86.84211, 93%, 71%)",
},
maroon: {
name: "maroon",
light: "hsl(321.81819, 26%, 41%)",
dark: "hsl(322.10526, 66%, 66%)",
},
navy: {
name: "navy",
light: "hsl(216, 44%, 38%)",
dark: "hsl(218, 69%, 69%)",
},
olive: {
name: "olive",
light: "hsl(81, 36%, 41%)",
dark: "hsl(81, 64%, 65%)",
},
slate: {
name: "slate",
light: "hsl(212.53197, 15%, 44%)",
dark: "hsl(212.90323, 61%, 72%)",
},
}; };
function parseHsl(value: string): [string, string, string] | undefined { function parseHsl(value: string): [string, string, string] | undefined {
const match = /hsl\(\s*([\d.]+%?)\s*[, ]\s*([\d.]+%?)\s*[, ]\s*([\d.]+%?)\s*\)/.exec(value); const match =
/hsl\(\s*([\d.]+%?)\s*[, ]\s*([\d.]+%?)\s*[, ]\s*([\d.]+%?)\s*\)/.exec(
value,
);
return match ? [match[1]!, match[2]!, match[3]!] : undefined; return match ? [match[1]!, match[2]!, match[3]!] : undefined;
} }
@ -45,7 +116,11 @@ function parseHsl(value: string): [string, string, string] | undefined {
export function accentStyle(accent: string | [string, string?]): string { export function accentStyle(accent: string | [string, string?]): string {
const inputs = Array.isArray(accent) ? accent : [accent]; const inputs = Array.isArray(accent) ? accent : [accent];
const light = ACCENT_PRESETS[inputs[0] ?? ""]?.light ?? inputs[0]; const light = ACCENT_PRESETS[inputs[0] ?? ""]?.light ?? inputs[0];
const dark = ACCENT_PRESETS[inputs[1] ?? inputs[0] ?? ""]?.dark ?? inputs[1] ?? ACCENT_PRESETS[inputs[0] ?? ""]?.dark ?? inputs[0]; const dark =
ACCENT_PRESETS[inputs[1] ?? inputs[0] ?? ""]?.dark ??
inputs[1] ??
ACCENT_PRESETS[inputs[0] ?? ""]?.dark ??
inputs[0];
const lightHsl = parseHsl(light ?? ""); const lightHsl = parseHsl(light ?? "");
const darkHsl = parseHsl(dark ?? ""); const darkHsl = parseHsl(dark ?? "");
if (!lightHsl || !darkHsl) throw new Error(`Unknown accent color: ${accent}`); if (!lightHsl || !darkHsl) throw new Error(`Unknown accent color: ${accent}`);
@ -86,27 +161,55 @@ const COMPONENTS = [
] as const; ] as const;
function componentTemplates(): [string, string][] { function componentTemplates(): [string, string][] {
return COMPONENTS.map((name) => [`amezing-${name}`, fileURLToPath(new URL(`./components/${name}.spug`, import.meta.url))]); return COMPONENTS.map((name) => [
`amezing-${name}`,
fileURLToPath(new URL(`./components/${name}.spug`, import.meta.url)),
]);
} }
interface TemplateViews { interface TemplateViews {
component(name: string, component: unknown): unknown; component(name: string, component: unknown): unknown;
engine?: { renderComponent(path: string, props: Record<string, unknown>, context: { locals: Record<string, unknown>; params: Record<string, string> }): Promise<string> }; engine?: {
renderComponent(
path: string,
props: Record<string, unknown>,
context: {
locals: Record<string, unknown>;
params: Record<string, string>;
},
): Promise<string>;
};
} }
function registerAll(views: TemplateViews, accent: string | undefined): void { function registerAll(views: TemplateViews, accent: string | undefined): void {
for (const [name, template] of componentTemplates()) { for (const [name, template] of componentTemplates()) {
views.component(name, { views.component(name, {
async render(props: Record<string, unknown>, context: { locals: Record<string, unknown>; params: Record<string, string> }) { async render(
return views.engine!.renderComponent(template, { accentStyle: accent, ...props }, context); props: Record<string, unknown>,
context: {
locals: Record<string, unknown>;
params: Record<string, string>;
},
) {
return views.engine!.renderComponent(
template,
{ accentStyle: accent, ...props },
context,
);
}, },
}); });
} }
} }
/** Registers the Ametrine components on the views registry. */ /** Registers the Ametrine components on the views registry. */
export function registerAmezing(views: Views, options: { accentColor?: string | [string, string?] } = {}): void { export function registerAmezing(
registerAll(views as unknown as Parameters<typeof registerAll>[0], options.accentColor ? accentStyle(options.accentColor) : undefined); views: Views,
options: { accentColor?: string | [string, string?] } = {},
): void {
registerAll(
views as unknown as Parameters<typeof registerAll>[0],
options.accentColor ? accentStyle(options.accentColor) : undefined,
);
} }
/** Compiled theme stylesheet (Citrine base + Ametrine layout). */ /** Compiled theme stylesheet (Citrine base + Ametrine layout). */
@ -133,22 +236,44 @@ export const amezingFonts: Record<string, string> = {
"/fonts/commit-mono.woff2": "fonts/commit-mono.woff2", "/fonts/commit-mono.woff2": "fonts/commit-mono.woff2",
}; };
export function amezingMount(options: { accentColor?: string | [string, string?] } = {}): Mounts { export function amezingMount(
const accent = options.accentColor ? accentStyle(options.accentColor) : undefined; options: { accentColor?: string | [string, string?] } = {},
): Mounts {
const accent = options.accentColor
? accentStyle(options.accentColor)
: undefined;
return { return {
views: (views) => registerAll(views as unknown as Parameters<typeof registerAll>[0], accent), views: (views) =>
registerAll(
views as unknown as Parameters<typeof registerAll>[0],
accent,
),
routes: (route) => { routes: (route) => {
for (const [routePath, file] of Object.entries(amezingScripts)) { for (const [routePath, file] of Object.entries(amezingScripts)) {
route("GET", `/_muddle/amezing/${routePath}`, async () => route(
new Response(await readFile(new URL(`./${file}`, import.meta.url), "utf8"), { "GET",
`/_muddle/amezing/${routePath}`,
async () =>
new Response(
await readFile(new URL(`./${file}`, import.meta.url), "utf8"),
{
headers: { "content-type": "text/javascript; charset=utf-8" }, headers: { "content-type": "text/javascript; charset=utf-8" },
})); },
),
);
} }
for (const [routePath, file] of Object.entries(amezingFonts)) { for (const [routePath, file] of Object.entries(amezingFonts)) {
route("GET", routePath, async () => route(
new Response(await readFile(new URL(`./${file}`, import.meta.url)), { "GET",
routePath,
async () =>
new Response(
await readFile(new URL(`./${file}`, import.meta.url)),
{
headers: { "content-type": "font/woff2" }, headers: { "content-type": "font/woff2" },
})); },
),
);
} }
}, },
styles: { "/_muddle/amezing.css": () => amezingStyles() }, styles: { "/_muddle/amezing.css": () => amezingStyles() },
@ -156,6 +281,8 @@ export function amezingMount(options: { accentColor?: string | [string, string?]
} }
/** Convenience integration. */ /** Convenience integration. */
export function amezingIntegration(options: { accentColor?: string | [string, string?] } = {}): Integration { export function amezingIntegration(
options: { accentColor?: string | [string, string?] } = {},
): Integration {
return { name: "amezing", mounts: [amezingMount(options)] }; return { name: "amezing", mounts: [amezingMount(options)] };
} }

View file

@ -2,6 +2,11 @@
"name": "@muddle/amezing", "name": "@muddle/amezing",
"version": "0.1.0", "version": "0.1.0",
"type": "module", "type": "module",
"exports": { ".": "./index.ts", "./styles": "./styles/ametrine.css" }, "exports": {
"peerDependencies": { "muddle": "*" } ".": "./index.ts",
"./styles": "./styles/ametrine.css"
},
"peerDependencies": {
"muddle": "*"
}
} }

View file

@ -47,9 +47,7 @@
} }
@mixin chip { @mixin chip {
transition: transition: all var(--transition), transform var(--transition-bezier);
all var(--transition),
transform var(--transition-bezier);
box-shadow: var(--edge-highlight); box-shadow: var(--edge-highlight);
border-radius: var(--rounded-corner-small); border-radius: var(--rounded-corner-small);
background-color: var(--bg-muted-1); background-color: var(--bg-muted-1);

View file

@ -344,8 +344,7 @@
// FONTS // FONTS
--font-system-ui: system-ui, sans-serif; --font-system-ui: system-ui, sans-serif;
--font-ui-monospace: ui-monospace, monospace; --font-ui-monospace: ui-monospace, monospace;
--font-emoji: --font-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji"; "Noto Color Emoji";
// FONT SIZES // FONT SIZES
@ -376,16 +375,13 @@
--disabled-opacity: 0.4; --disabled-opacity: 0.4;
// SHADOWS // SHADOWS
--shadow: --shadow: 0 0 0 #{rpx(1)} rgba(0, 0, 0, 0.03),
0 0 0 #{rpx(1)} rgba(0, 0, 0, 0.03),
0 #{rpx(1)} #{rpx(3)} #{rpx(1)} rgba(0, 0, 0, 0.07), 0 #{rpx(1)} #{rpx(3)} #{rpx(1)} rgba(0, 0, 0, 0.07),
0 #{rpx(2)} #{rpx(6)} #{rpx(2)} rgba(0, 0, 0, 0.03); 0 #{rpx(2)} #{rpx(6)} #{rpx(2)} rgba(0, 0, 0, 0.03);
--shadow-inset: --shadow-inset: inset 0 0 0 #{rpx(1)} rgba(0, 0, 0, 0.03),
inset 0 0 0 #{rpx(1)} rgba(0, 0, 0, 0.03),
inset 0 #{rpx(1)} #{rpx(3)} #{rpx(1)} rgba(0, 0, 0, 0.07), inset 0 #{rpx(1)} #{rpx(3)} #{rpx(1)} rgba(0, 0, 0, 0.07),
inset 0 #{rpx(2)} #{rpx(6)} #{rpx(2)} rgba(0, 0, 0, 0.03); inset 0 #{rpx(2)} #{rpx(6)} #{rpx(2)} rgba(0, 0, 0, 0.03);
--shadow-raised: --shadow-raised: 0 0 0 #{rpx(1)} rgba(0, 0, 0, 0.06),
0 0 0 #{rpx(1)} rgba(0, 0, 0, 0.06),
0 #{rpx(2)} #{rpx(6)} #{rpx(2)} rgba(0, 0, 0, 0.14), 0 #{rpx(2)} #{rpx(6)} #{rpx(2)} rgba(0, 0, 0, 0.14),
0 #{rpx(4)} #{rpx(12)} #{rpx(4)} rgba(0, 0, 0, 0.06); 0 #{rpx(4)} #{rpx(12)} #{rpx(4)} rgba(0, 0, 0, 0.06);
--shadow-glass: 0 #{rpx(6)} #{rpx(12)} #{rpx(-6)} rgba(0, 0, 0, 0.1); --shadow-glass: 0 #{rpx(6)} #{rpx(12)} #{rpx(-6)} rgba(0, 0, 0, 0.1);
@ -555,16 +551,15 @@
--contrast-color: oklch(from var(--accent-color) var(--l) 0 h / var(--a)); --contrast-color: oklch(from var(--accent-color) var(--l) 0 h / var(--a));
// SHADOWS // SHADOWS
--shadow-glow: --shadow-glow: 0 0 0 #{rpx(1)} var(--bg-muted-2),
0 0 0 #{rpx(1)} var(--bg-muted-2),
0 #{rpx(2)} #{rpx(6)} #{rpx(2)} var(--bg-muted-1), 0 #{rpx(2)} #{rpx(6)} #{rpx(2)} var(--bg-muted-1),
0 #{rpx(4)} #{rpx(24)} #{rpx(4)} var(--bg-muted-2); 0 #{rpx(4)} #{rpx(24)} #{rpx(4)} var(--bg-muted-2);
--shadow-glow-inset: --shadow-glow-inset: inset 0 0 0 #{rpx(1)} var(--bg-muted-2),
inset 0 0 0 #{rpx(1)} var(--bg-muted-2),
inset 0 #{rpx(2)} #{rpx(6)} #{rpx(2)} var(--bg-muted-1), inset 0 #{rpx(2)} #{rpx(6)} #{rpx(2)} var(--bg-muted-1),
inset 0 #{rpx(4)} #{rpx(24)} #{rpx(4)} var(--bg-muted-2); inset 0 #{rpx(4)} #{rpx(24)} #{rpx(4)} var(--bg-muted-2);
--text-shadow-glow: --text-shadow-glow: var(--bg-muted-2) 0 0 #{rpx(4)}, var(
var(--bg-muted-2) 0 0 #{rpx(4)}, var(--accent-color) 0 0 #{rpx(12)}; --accent-color
) 0 0 #{rpx(12)};
} }
} }
} }

View file

@ -237,9 +237,7 @@ kbd {
transition-duration: var(--transition); transition-duration: var(--transition);
transition-property: transform, box-shadow, background-color; transition-property: transform, box-shadow, background-color;
cursor: pointer; cursor: pointer;
box-shadow: box-shadow: var(--edge-highlight), inset 0 -0.125rem 0 var(--bg-muted-2);
var(--edge-highlight),
inset 0 -0.125rem 0 var(--bg-muted-2);
border-radius: var(--rounded-corner-small); border-radius: var(--rounded-corner-small);
background-color: var(--bg-muted-1); background-color: var(--bg-muted-1);
padding: 0 0.375rem; padding: 0 0.375rem;
@ -362,9 +360,7 @@ details {
--icon: var(--icon-caret-down); --icon: var(--icon-caret-down);
display: inline-block; display: inline-block;
vertical-align: rpx(-2); vertical-align: rpx(-2);
transition: transition: all var(--transition), transform var(--transition-bezier);
all var(--transition),
transform var(--transition-bezier);
margin-inline-end: 0.25rem; margin-inline-end: 0.25rem;
} }
} }

View file

@ -76,9 +76,7 @@ input[type="checkbox"] {
position: absolute; position: absolute;
transform: scale(0.5); transform: scale(0.5);
opacity: 0; opacity: 0;
transition: transition: opacity var(--transition), transform var(--transition-bezier);
opacity var(--transition),
transform var(--transition-bezier);
content: ""; content: "";
} }

View file

@ -9,9 +9,7 @@ span.spoiler {
&.solid { &.solid {
filter: none; filter: none;
transition: transition: background-color var(--transition), color var(--transition);
background-color var(--transition),
color var(--transition);
border-radius: var(--rounded-corner-small); border-radius: var(--rounded-corner-small);
background-color: var(--fg-muted-1); background-color: var(--fg-muted-1);
color: transparent; color: transparent;

View file

@ -243,8 +243,10 @@
display: inline-block; display: inline-block;
transition: var(--transition-bezier); transition: var(--transition-bezier);
transition-property: transition-property:
border-start-start-radius, border-end-start-radius, border-start-start-radius,
border-start-end-radius, border-end-end-radius; border-end-start-radius,
border-start-end-radius,
border-end-end-radius;
border-radius: var(--rounded-corner-small); border-radius: var(--rounded-corner-small);
background-color: var(--bg-muted-1); background-color: var(--bg-muted-1);
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;

View file

@ -9,9 +9,7 @@
background-color: var(--bg-muted-1); background-color: var(--bg-muted-1);
padding: 0.125rem 0.375rem; padding: 0.125rem 0.375rem;
border-radius: 0.25rem; border-radius: 0.25rem;
transition: transition: background-color var(--transition), color var(--transition);
background-color var(--transition),
color var(--transition);
&:hover { &:hover {
background-color: var(--bg-muted-2); background-color: var(--bg-muted-2);

View file

@ -15,9 +15,7 @@
background-color: var(--bg-muted-1); background-color: var(--bg-muted-1);
color: var(--fg-color); color: var(--fg-color);
font-size: var(--font-size-medium); font-size: var(--font-size-medium);
transition: transition: border-color var(--transition), box-shadow var(--transition);
border-color var(--transition),
box-shadow var(--transition);
&:focus { &:focus {
outline: none; outline: none;

View file

@ -19,9 +19,7 @@
left: 0.75rem; left: 0.75rem;
color: var(--fg-muted-2); color: var(--fg-muted-2);
pointer-events: none; pointer-events: none;
transition: transition: color var(--transition), opacity var(--transition-bezier);
color var(--transition),
opacity var(--transition-bezier);
opacity: 0.7; opacity: 0.7;
} }

View file

@ -6,9 +6,7 @@
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
z-index: 9999; z-index: 9999;
transition: transition: visibility var(--transition), opacity var(--transition);
visibility var(--transition),
opacity var(--transition);
inset: 0; inset: 0;
background-color: var(--shade-color); background-color: var(--shade-color);
padding-block-start: 15vh; padding-block-start: 15vh;
@ -74,9 +72,7 @@
position: absolute; position: absolute;
transform: translateX(0.5rem); transform: translateX(0.5rem);
opacity: 0; opacity: 0;
transition: transition: opacity var(--transition), transform var(--transition-bezier);
opacity var(--transition),
transform var(--transition-bezier);
cursor: help; cursor: help;
inset-block-start: 0.625rem; inset-block-start: 0.625rem;
inset-inline-end: 1rem; inset-inline-end: 1rem;

View file

@ -116,9 +116,7 @@
a { a {
display: flex; display: flex;
transition: transition: color var(--transition), transform var(--transition-bezier);
color var(--transition),
transform var(--transition-bezier);
height: fit-content; height: fit-content;
color: var(--fg-muted-1); color: var(--fg-muted-1);

View file

@ -203,9 +203,7 @@
display: flex; display: flex;
flex-shrink: 0; flex-shrink: 0;
gap: 0.25rem; gap: 0.25rem;
transition: transition: width var(--transition), visibility var(--transition);
width var(--transition),
visibility var(--transition);
margin-block: 0; margin-block: 0;
box-shadow: var(--edge-highlight), var(--shadow-glass); box-shadow: var(--edge-highlight), var(--shadow-glass);
border-radius: 1.125rem; border-radius: 1.125rem;

View file

@ -9,8 +9,14 @@
z-index: 3; z-index: 3;
transition-duration: var(--transition); transition-duration: var(--transition);
transition-property: transition-property:
visibility, transform, inset-block-start, box-shadow, border-inline-end, visibility,
border-start-end-radius, border-end-end-radius, height; transform,
inset-block-start,
box-shadow,
border-inline-end,
border-start-end-radius,
border-end-end-radius,
height;
inset-block-start: 0; inset-block-start: 0;
inset-inline-start: 0; inset-inline-start: 0;
border-inline-end: rpx(1) solid var(--bg-muted-2); border-inline-end: rpx(1) solid var(--bg-muted-2);

File diff suppressed because one or more lines are too long

View file

@ -146,22 +146,34 @@ function initSearch() {
for (const match of result.matches) { for (const match of result.matches) {
if (match.key === "title") continue; if (match.key === "title") continue;
const indices = match.indices.sort((a, b) => Math.abs(a[1] - a[0] - searchVal.length) - Math.abs(b[1] - b[0] - searchVal.length)).slice(0, MAX_RESULTS); const indices = match.indices
.sort(
(a, b) =>
Math.abs(a[1] - a[0] - searchVal.length) -
Math.abs(b[1] - b[0] - searchVal.length),
)
.slice(0, MAX_RESULTS);
const value = match.value; const value = match.value;
for (const ind of indices) { for (const ind of indices) {
const start = Math.max(0, ind[0] - TEASER_SIZE); const start = Math.max(0, ind[0] - TEASER_SIZE);
const end = Math.min(value.length - 1, ind[1] + TEASER_SIZE); const end = Math.min(value.length - 1, ind[1] + TEASER_SIZE);
output += "<span>" output +=
+ value.substring(start, ind[0]) "<span>" +
+ `<strong>${value.substring(ind[0], ind[1] + 1)}</strong>` value.substring(start, ind[0]) +
+ value.substring(ind[1] + 1, end) `<strong>${value.substring(ind[0], ind[1] + 1)}</strong>` +
+ "</span>"; value.substring(ind[1] + 1, end) +
"</span>";
} }
if (match.indices.length > MAX_RESULTS) { if (match.indices.length > MAX_RESULTS) {
const moreMatchesText = document.getElementById("more-matches-text").textContent; const moreMatchesText =
output += `<span class="more-matches">${moreMatchesText}</span>`.replace("$MATCHES", `+${match.indices.length - MAX_RESULTS}`); document.getElementById("more-matches-text").textContent;
output +=
`<span class="more-matches">${moreMatchesText}</span>`.replace(
"$MATCHES",
`+${match.indices.length - MAX_RESULTS}`,
);
} }
} }
return output + "</div>"; return output + "</div>";