Compare commits

...

2 commits

Author SHA1 Message Date
e5b08e772a Bugfix: loading theme options 2023-06-30 13:14:26 +04:00
8d372d30fb Bugfix: pre width; other menu for articles 2023-06-30 13:13:59 +04:00
5 changed files with 61 additions and 23 deletions

View file

@ -64,15 +64,16 @@ import TextBox from "./TextBox.astro";
<script> <script>
var lessLoaded = false var lessLoaded = false
class ThemingOption { class ThemingOption<T> {
input: HTMLInputElement | undefined input: HTMLInputElement | undefined
value: T;
onchange: onchange:
(opt: ThemingOption, upd: boolean) => any = (opt: ThemingOption<T>, upd: boolean) => any =
(_opt, _upd) => {} (_opt, _upd) => {}
constructor ( constructor (
inputId: string, inputId: string,
onchange: (opt: ThemingOption, upd: boolean) => any onchange: (opt: ThemingOption<T>, upd: boolean) => any
) { ) {
this.input = document.getElementById(inputId) as HTMLInputElement this.input = document.getElementById(inputId) as HTMLInputElement
this.onchange = onchange this.onchange = onchange
@ -103,6 +104,15 @@ import TextBox from "./TextBox.astro";
} }
} }
/** Converts any object to number.
* Returns the default value passed to `def` parameter
* if `Number(val)` returns `NaN`.
*/
const toNum = (val: any, def: number) => {
const res = Number(val)
return isNaN(res) ? def : res
}
const colorRegex = /#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/ const colorRegex = /#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/
/** Parses color-like string and /** Parses color-like string and
* returns the color in the general format. * returns the color in the general format.
@ -114,11 +124,12 @@ import TextBox from "./TextBox.astro";
return (val.match(colorRegex) || [])[1] return (val.match(colorRegex) || [])[1]
} }
new ThemingOption( new ThemingOption<boolean>(
'dark', 'dark',
(opt, upd) => { (opt, upd) => {
if (upd) { if (upd) {
const state = opt.input.checked const state = opt.input.checked
opt.value = state
localStorage.setItem('dc09_dark', state ? '1' : '0') localStorage.setItem('dc09_dark', state ? '1' : '0')
return opt.onchange(opt, false) return opt.onchange(opt, false)
} }
@ -132,70 +143,81 @@ import TextBox from "./TextBox.astro";
media.matches media.matches
) )
) )
opt.value = state
opt.input.checked = state opt.input.checked = state
document.body.dataset.dark = state ? '1' : '0' document.body.dataset.dark = state ? '1' : '0'
} }
) )
const purebgOpt = new ThemingOption( const purebgOpt = new ThemingOption<boolean>(
'purebg', // pure background 'purebg', // pure background
(opt, upd) => { (opt, upd) => {
if (upd) { if (upd) {
const state = opt.input.checked const state = opt.input.checked
opt.value = state
localStorage.setItem('dc09_purebg', state ? '1' : '0') localStorage.setItem('dc09_purebg', state ? '1' : '0')
reloadTheme() reloadTheme()
return opt.onchange(opt, false) return opt.onchange(opt, false)
} }
opt.input.checked = toBool(localStorage.getItem('dc09_purebg')) const value = toBool(localStorage.getItem('dc09_purebg'))
opt.value = value
opt.input.checked = value
} }
) )
const accentOpt = new ThemingOption( const accentOpt = new ThemingOption<string>(
'accent', 'accent',
(opt, upd) => { (opt, upd) => {
if (upd) { if (upd) {
if (!opt.input.validity.valid) return if (!opt.input.validity.valid) return
const color = toColor(opt.input.value) const color = toColor(opt.input.value)
if (!color) return if (!color) return
opt.value = color
localStorage.setItem('dc09_accent', color) localStorage.setItem('dc09_accent', color)
reloadTheme() reloadTheme()
return return
} }
const color = localStorage.getItem('dc09_accent') || '6570d6' const color = toColor(localStorage.getItem('dc09_accent')) || '6570d6'
opt.value = color
opt.input.value = color opt.input.value = color
} }
) )
const bdrsOpt = new ThemingOption( const bdrsOpt = new ThemingOption<number>(
'bdrs', // border-radius, as in Emmet 'bdrs', // border-radius, as in Emmet
(opt, upd) => { (opt, upd) => {
if (upd) { if (upd) {
const value = opt.input.value const valueStr = opt.input.value
localStorage.setItem('dc09_bdrs', value) const value = Number(opt.input.value)
if (isNaN(value)) return;
opt.value = value
localStorage.setItem('dc09_bdrs', valueStr)
reloadTheme() reloadTheme()
return return
} }
let value = Number(localStorage.getItem('dc09_bdrs')) const value = toNum(localStorage.getItem('dc09_bdrs'), 2)
value = isNaN(value) ? 2 : value opt.value = value
opt.input.value = String(value) opt.input.value = String(value)
opt.input.dispatchEvent(new Event('updatedByJavascript')) opt.input.dispatchEvent(new Event('updatedByJavascript'))
} }
) )
const colorsSection = document.getElementById('custom-colors') const colorsSection = document.getElementById('custom-colors')
new ThemingOption( new ThemingOption<boolean>(
'custom-theme', 'custom-theme',
(opt, upd) => { (opt, upd) => {
if (upd) { if (upd) {
const state = opt.input.checked const state = opt.input.checked
opt.value = state
localStorage.setItem('dc09_custom', state ? '1' : '0') localStorage.setItem('dc09_custom', state ? '1' : '0')
return opt.onchange(opt, false) return opt.onchange(opt, false)
} }
const state = toBool(localStorage.getItem('dc09_custom')) const state = toBool(localStorage.getItem('dc09_custom'))
opt.value = state
opt.input.checked = state opt.input.checked = state
colorsSection.dataset.show = state ? '1' : '0' colorsSection.dataset.show = state ? '1' : '0'
@ -225,9 +247,9 @@ import TextBox from "./TextBox.astro";
} }
function reloadTheme() { function reloadTheme() {
const accent = '#' + toColor(accentOpt.input.value) const accent = '#' + accentOpt.value
const bdrs = Number(bdrsOpt.input.value) const bdrs = bdrsOpt.value
const purebg = purebgOpt.input.checked const purebg = purebgOpt.value
eval('less').modifyVars({ eval('less').modifyVars({
accent: accent, accent: accent,
bdrs: `${bdrs}rem`, bdrs: `${bdrs}rem`,

View file

@ -6,16 +6,21 @@ import MenuItem from "../components/MenuItem.astro";
export interface Props { export interface Props {
title: string; title: string;
description: string; description: string;
article?: boolean;
} }
const { title, description } = Astro.props; const { title, description, article = false } = Astro.props;
--- ---
<Layout title={"Blog | " + title} description={description}> <Layout title={"Blog | " + title} description={description}>
<slot name="metadata" slot="metadata" /> <slot name="metadata" slot="metadata" />
<Menu> <Menu>
{
!article ?
<MenuItem name="Home" icon="&#xf104;" link="/" /> <MenuItem name="Home" icon="&#xf104;" link="/" />
<MenuItem name="Articles" icon="&#xf015;" link="/blog" /> <MenuItem name="Articles" icon="&#xf1ea;" link="/blog" /> :
<MenuItem name="Articles" icon="&#xf104;" link="/blog" />
}
<MenuItem name="Shorts" icon="&#xf0e7;" link="/blog/shorts" /> <MenuItem name="Shorts" icon="&#xf0e7;" link="/blog/shorts" />
<MenuItem name="Random" icon="&#xf522;" link="/blog/random" /> <MenuItem name="Random" icon="&#xf522;" link="/blog/random" />
<MenuItem name="Search" icon="&#xf002;" link="/blog/search" /> <MenuItem name="Search" icon="&#xf002;" link="/blog/search" />

View file

@ -34,7 +34,7 @@ const { title, description } = Astro.props;
padding: 0; padding: 0;
box-sizing: border-box; box-sizing: border-box;
padding: 0 0.5rem; padding: 0 @body-padding;
background: var(--bg); background: var(--bg);
color: var(--fg); color: var(--fg);
@ -46,8 +46,12 @@ const { title, description } = Astro.props;
main { main {
margin: auto; margin: auto;
padding: 0.25rem; padding: @main-padding;
max-width: @max-width; max-width: @max-width;
/*
width: 100%;
overflow-x: hidden;
*/
} }
article { article {

View file

@ -26,7 +26,7 @@ const {
const locale = 'ru-RU'; const locale = 'ru-RU';
--- ---
<BlogLayout title={title} description={description}> <BlogLayout title={title} description={description} article={true}>
<Fragment slot="metadata"> <Fragment slot="metadata">
<meta property="og:type" content="article" /> <meta property="og:type" content="article" />
<meta property="og:title" content={title} /> <meta property="og:title" content={title} />
@ -50,6 +50,8 @@ const locale = 'ru-RU';
</BlogLayout> </BlogLayout>
<style lang="less" is:global> <style lang="less" is:global>
@import "/src/styles/max_width.less";
article { article {
& > h1:first-of-type { & > h1:first-of-type {
display: none; display: none;
@ -83,6 +85,9 @@ const locale = 'ru-RU';
} }
pre { pre {
max-width: calc(100vw - @body-padding * 2 - @main-padding * 2) !important;
box-sizing: border-box;
padding: 1rem; padding: 1rem;
border-radius: var(--bdrs); border-radius: var(--bdrs);

View file

@ -1 +1,3 @@
@max-width: 800px; @max-width: 800px;
@body-padding: 0.5rem;
@main-padding: 0.25rem;