Compare commits
2 commits
994a41f9e3
...
e5b08e772a
Author | SHA1 | Date | |
---|---|---|---|
e5b08e772a | |||
8d372d30fb |
5 changed files with 61 additions and 23 deletions
|
@ -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`,
|
||||||
|
|
|
@ -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>
|
||||||
<MenuItem name="Home" icon="" link="/" />
|
{
|
||||||
<MenuItem name="Articles" icon="" link="/blog" />
|
!article ?
|
||||||
|
<MenuItem name="Home" icon="" link="/" />
|
||||||
|
<MenuItem name="Articles" icon="" link="/blog" /> :
|
||||||
|
<MenuItem name="Articles" icon="" link="/blog" />
|
||||||
|
}
|
||||||
<MenuItem name="Shorts" icon="" link="/blog/shorts" />
|
<MenuItem name="Shorts" icon="" link="/blog/shorts" />
|
||||||
<MenuItem name="Random" icon="" link="/blog/random" />
|
<MenuItem name="Random" icon="" link="/blog/random" />
|
||||||
<MenuItem name="Search" icon="" link="/blog/search" />
|
<MenuItem name="Search" icon="" link="/blog/search" />
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
@max-width: 800px;
|
@max-width: 800px;
|
||||||
|
@body-padding: 0.5rem;
|
||||||
|
@main-padding: 0.25rem;
|
||||||
|
|
Loading…
Add table
Reference in a new issue