feat: custom admonition titles + various fixes

scarlett
NGPixel 1 month ago
parent 7a0e0dcca1
commit 5a3be5c19a
No known key found for this signature in database

@ -100,6 +100,11 @@ async function routes(app: FastifyInstance) {
registration: { registration: {
type: 'boolean' type: 'boolean'
}, },
allowForgotPassword: {
type: 'boolean',
description:
'Whether this strategy offers a password reset from the login screen. False for a strategy whose module has no such setting.'
},
strategy: { strategy: {
type: 'object', type: 'object',
properties: { properties: {
@ -136,7 +141,14 @@ async function routes(app: FastifyInstance) {
if (!site) { if (!site) {
return reply.badRequest('Invalid Site ID') return reply.badRequest('Invalid Site ID')
} }
const activeStrategies = await WIKI.models.authentication.getStrategies({ enabledOnly: true }) /*
`getActiveStrategies` rather than the raw rows: it completes each config from the module's
declared defaults, so a prop added to a module after a strategy was configured reads as its
default here instead of as a missing key.
*/
const activeStrategies = (await WIKI.models.authentication.getActiveStrategies()).filter(
(str: any) => str.isEnabled
)
// -> A site created before it had strategies configured has no list at all // -> A site created before it had strategies configured has no list at all
const configuredStrategies = site.config.authStrategies ?? [] const configuredStrategies = site.config.authStrategies ?? []
const siteStrategies = activeStrategies const siteStrategies = activeStrategies
@ -150,6 +162,14 @@ async function routes(app: FastifyInstance) {
activeStrategy: { activeStrategy: {
displayName: str.displayName, displayName: str.displayName,
registration: str.registration, registration: str.registration,
/*
Named explicitly, like every other field here: this endpoint is public and a strategy's
config is where an OAuth client secret lives, so nothing may reach it by spreading.
A module that declares no such prop reads as false, which is correct rather than a
default -- a strategy with no password of its own has no password to reset.
*/
allowForgotPassword: str.config?.allowForgotPassword === true,
strategy: { strategy: {
key: authModule?.key ?? str.module, key: authModule?.key ?? str.module,
title: authModule?.title ?? str.module, title: authModule?.title ?? str.module,

@ -1737,10 +1737,10 @@
"editor.emoji.smileysEmotion": "Smileys & Emotion", "editor.emoji.smileysEmotion": "Smileys & Emotion",
"editor.emoji.symbols": "Symbols", "editor.emoji.symbols": "Symbols",
"editor.emoji.travelPlaces": "Travel & Places", "editor.emoji.travelPlaces": "Travel & Places",
"editor.markup.admonitionDanger": "Danger / Caution Admonition", "editor.markup.admonitionDanger": "Caution Admonition",
"editor.markup.admonitionImportant": "Important Admonition", "editor.markup.admonitionImportant": "Important Admonition",
"editor.markup.admonitionInfo": "Info / Note Admonition", "editor.markup.admonitionInfo": "Note Admonition",
"editor.markup.admonitionSuccess": "Tip / Success Admonition", "editor.markup.admonitionSuccess": "Tip Admonition",
"editor.markup.admonitionWarning": "Warning Admonition", "editor.markup.admonitionWarning": "Warning Admonition",
"editor.markup.blockquote": "Blockquote", "editor.markup.blockquote": "Blockquote",
"editor.markup.blockquoteAdmonitions": "Blockquote / Admonition", "editor.markup.blockquoteAdmonitions": "Blockquote / Admonition",
@ -1750,6 +1750,7 @@
"editor.markup.blockquoteWarning": "Warning Blockquote", "editor.markup.blockquoteWarning": "Warning Blockquote",
"editor.markup.bold": "Bold", "editor.markup.bold": "Bold",
"editor.markup.distractionFreeMode": "Distraction Free Mode", "editor.markup.distractionFreeMode": "Distraction Free Mode",
"editor.markup.editTable": "Edit in Table Editor",
"editor.markup.header": "Header", "editor.markup.header": "Header",
"editor.markup.headerLevel": "Header {level}", "editor.markup.headerLevel": "Header {level}",
"editor.markup.heading": "Heading {level}", "editor.markup.heading": "Heading {level}",
@ -1763,7 +1764,6 @@
"editor.markup.insertHorizontalBar": "Insert Horizontal Bar", "editor.markup.insertHorizontalBar": "Insert Horizontal Bar",
"editor.markup.insertLink": "Insert Link", "editor.markup.insertLink": "Insert Link",
"editor.markup.insertMathExpression": "Insert Math Expression", "editor.markup.insertMathExpression": "Insert Math Expression",
"editor.markup.editTable": "Edit in Table Editor",
"editor.markup.insertTable": "Insert Table", "editor.markup.insertTable": "Insert Table",
"editor.markup.insertTabset": "Insert Tabset", "editor.markup.insertTabset": "Insert Tabset",
"editor.markup.insertVideoAudio": "Insert Video / Audio", "editor.markup.insertVideoAudio": "Insert Video / Audio",

@ -23,3 +23,9 @@ props:
hint: Send a verification email to the user with a validation link when registering (if registration is enabled). hint: Send a verification email to the user with a validation link when registering (if registration is enabled).
icon: received icon: received
default: true default: true
allowForgotPassword:
type: Boolean
title: Allow Forgot Password
hint: Users who have forgotten their password can request a reset link by email from the login screen. Turn this off where passwords are handed out rather than chosen.
icon: password-reset
default: true

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="voSbtONYyz2N6cssXAFT9a" x1="19.951" x2="27.799" y1="4.653" y2="42.15" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0370c8"/><stop offset=".484" stop-color="#036fc5"/><stop offset=".775" stop-color="#036abd"/><stop offset="1" stop-color="#0362b0"/></linearGradient><path fill="url(#voSbtONYyz2N6cssXAFT9a)" d="M39,7v34c0,1.105-0.895,2-2,2H11c-1.105,0-2-0.895-2-2V7c0-1.105,0.895-2,2-2h26 C38.105,5,39,5.895,39,7z"/><path d="M24,26c-4.418,0-8,3.582-8,8v4c0,1.105,0.895,2,2,2h12c1.105,0,2-0.895,2-2v-4 C32,29.582,28.418,26,24,26z" opacity=".05"/><path d="M24,26.5c-4.142,0-7.5,3.358-7.5,7.5v3.8c0,0.939,0.761,1.7,1.7,1.7h11.6c0.939,0,1.7-0.761,1.7-1.7 V34C31.5,29.858,28.142,26.5,24,26.5z" opacity=".07"/><radialGradient id="voSbtONYyz2N6cssXAFT9b" cx="24" cy="21" r="5" gradientUnits="userSpaceOnUse"><stop offset="0"/><stop offset="1" stop-opacity="0"/></radialGradient><circle cx="24" cy="21" r="5" fill="url(#voSbtONYyz2N6cssXAFT9b)"/><linearGradient id="voSbtONYyz2N6cssXAFT9c" x1="23.289" x2="24.843" y1="3.034" y2="11.704" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#75daff"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#voSbtONYyz2N6cssXAFT9c)" d="M27,3h-6c-0.552,0-1,0.448-1,1v6c0,0.552,0.448,1,1,1h6c0.552,0,1-0.448,1-1V4 C28,3.448,27.552,3,27,3z M24,9c-0.552,0-1-0.448-1-1c0-0.552,0.448-1,1-1s1,0.448,1,1C25,8.552,24.552,9,24,9z"/><linearGradient id="voSbtONYyz2N6cssXAFT9d" x1="20.883" x2="24.655" y1="17.543" y2="39.346" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#75daff"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#voSbtONYyz2N6cssXAFT9d)" d="M20,21c0-2.209,1.791-4,4-4s4,1.791,4,4c0,2.209-1.791,4-4,4S20,23.209,20,21z M24,27 c-3.866,0-7,3.134-7,7v3.6c0,0.773,0.627,1.4,1.4,1.4h11.2c0.773,0,1.4-0.627,1.4-1.4V34C31,30.134,27.866,27,24,27z"/></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#09914a" d="M44,24c0,11.045-8.955,20-20,20S4,35.045,4,24S12.955,4,24,4S44,12.955,44,24z"/><linearGradient id="wNnN53lrjZSLZlIPnrNqHa" x1="10.251" x2="15.3" y1="10.763" y2="30.307" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f2f2f2"/><stop offset=".148" stop-color="#eef1ef"/><stop offset=".282" stop-color="#e4ece8"/><stop offset=".409" stop-color="#d1e4da"/><stop offset=".533" stop-color="#b7dac8"/><stop offset=".654" stop-color="#96ccb0"/><stop offset=".773" stop-color="#6dbb92"/><stop offset=".889" stop-color="#3ea770"/><stop offset="1" stop-color="#09914a"/></linearGradient><path fill="url(#wNnN53lrjZSLZlIPnrNqHa)" d="M24,24L9.999,38.282C2.112,30.55,1.986,17.886,9.718,9.999L24,24z"/><circle cx="24" cy="24" r="17" fill="#f2f2f2"/><path fill="#d83b01" d="M24,36.75c-0.414,0-0.75-0.336-0.75-0.75V24c0-0.414,0.336-0.75,0.75-0.75s0.75,0.336,0.75,0.75v12 C24.75,36.414,24.414,36.75,24,36.75z"/><path fill="#45494d" d="M24,24.75c-0.192,0-0.384-0.073-0.53-0.22c-0.293-0.293-0.293-0.768,0-1.061l8.485-8.485 c0.293-0.293,0.768-0.293,1.061,0s0.293,0.768,0,1.061L24.53,24.53C24.384,24.677,24.192,24.75,24,24.75z"/><path fill="#45494d" d="M23.999,25.25c-0.181,0-0.365-0.039-0.54-0.123l-7.787-3.735c-0.623-0.299-0.885-1.045-0.586-1.668 c0.298-0.622,1.044-0.887,1.667-0.586l7.787,3.735c0.623,0.299,0.885,1.045,0.586,1.668C24.912,24.988,24.465,25.25,23.999,25.25z"/><circle cx="24" cy="24" r="2" fill="#1e2021"/><path fill="#09914a" d="M17.287,12.963l-8.419,1.089c-0.534,0.069-0.989-0.386-0.92-0.92l1.089-8.419 c0.087-0.676,0.913-0.958,1.395-0.475l7.33,7.33C18.244,12.05,17.963,12.875,17.287,12.963z"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="jv689zNUBazMNK6AOyXtga" x1="6" x2="42" y1="41" y2="41" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c8d3de"/><stop offset="1" stop-color="#c8d3de"/></linearGradient><path fill="url(#jv689zNUBazMNK6AOyXtga)" d="M42,39H6v2c0,1.105,0.895,2,2,2h32c1.105,0,2-0.895,2-2V39z"/><linearGradient id="jv689zNUBazMNK6AOyXtgb" x1="14.095" x2="31.385" y1="10.338" y2="43.787" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fcfcfc"/><stop offset=".495" stop-color="#f4f4f4"/><stop offset=".946" stop-color="#e8e8e8"/><stop offset="1" stop-color="#e8e8e8"/></linearGradient><path fill="url(#jv689zNUBazMNK6AOyXtgb)" d="M42,39H6V20L24,3l18,17V39z"/><path fill="#de490d" d="M13,25h10c0.552,0,1,0.448,1,1v17H12V26C12,25.448,12.448,25,13,25z"/><path d="M24,4c-0.474,0-0.948,0.168-1.326,0.503l-5.359,4.811L6,20v5.39L24,9.428L42,25.39V20L30.685,9.314 l-5.359-4.811C24.948,4.168,24.474,4,24,4z" opacity=".05"/><path d="M24,3c-0.474,0-0.948,0.167-1.326,0.5l-5.359,4.784L6,18.909v5.359L24,8.397l18,15.871v-5.359 L30.685,8.284L25.326,3.5C24.948,3.167,24.474,3,24,3z" opacity=".07"/><linearGradient id="jv689zNUBazMNK6AOyXtgc" x1="24" x2="24" y1="1.684" y2="23.696" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#d43a02"/><stop offset="1" stop-color="#b9360c"/></linearGradient><path fill="url(#jv689zNUBazMNK6AOyXtgc)" d="M44.495,19.507L25.326,2.503C24.948,2.168,24.474,2,24,2s-0.948,0.168-1.326,0.503 L3.505,19.507c-0.42,0.374-0.449,1.02-0.064,1.43l1.636,1.745c0.369,0.394,0.984,0.424,1.39,0.067L24,7.428L41.533,22.75 c0.405,0.356,1.021,0.327,1.39-0.067l1.636-1.745C44.944,20.527,44.915,19.881,44.495,19.507z"/><linearGradient id="jv689zNUBazMNK6AOyXtgd" x1="28.05" x2="35.614" y1="25.05" y2="32.614" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#33bef0"/><stop offset="1" stop-color="#0a85d9"/></linearGradient><path fill="url(#jv689zNUBazMNK6AOyXtgd)" d="M29,25h6c0.552,0,1,0.448,1,1v6c0,0.552-0.448,1-1,1h-6c-0.552,0-1-0.448-1-1v-6 C28,25.448,28.448,25,29,25z"/></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><circle cx="24" cy="24" r="2" fill="#0078d4"/><linearGradient id="u86~y8WlEM9fdnhAWXl77a" x1="18.17" x2="18.17" y1="4.118" y2="48.04" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#u86~y8WlEM9fdnhAWXl77a)" d="M19.839,31.74c-0.288,0-0.579-0.083-0.836-0.255C16.497,29.801,15,27.003,15,24 s1.497-5.801,4.003-7.485c0.687-0.461,1.62-0.28,2.082,0.409c0.462,0.688,0.279,1.62-0.408,2.082C19,20.131,18,21.998,18,24 s1,3.869,2.677,4.995c0.688,0.462,0.87,1.394,0.408,2.082C20.796,31.508,20.321,31.74,19.839,31.74z"/><linearGradient id="u86~y8WlEM9fdnhAWXl77b" x1="29.83" x2="29.83" y1="4.118" y2="48.04" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#u86~y8WlEM9fdnhAWXl77b)" d="M28.161,31.74c-0.482,0-0.957-0.232-1.246-0.664c-0.462-0.688-0.279-1.62,0.408-2.082 C29,27.869,30,26.002,30,24s-1-3.869-2.677-4.995c-0.688-0.462-0.87-1.394-0.408-2.082c0.461-0.689,1.396-0.87,2.082-0.409 C31.503,18.199,33,20.997,33,24s-1.497,5.801-4.003,7.485C28.74,31.658,28.449,31.74,28.161,31.74z"/><linearGradient id="u86~y8WlEM9fdnhAWXl77c" x1="13.505" x2="13.505" y1="4.118" y2="48.04" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#u86~y8WlEM9fdnhAWXl77c)" d="M16.509,36.74c-0.287,0-0.576-0.082-0.833-0.253C11.496,33.692,9,29.024,9,24 s2.496-9.692,6.676-12.487c0.686-0.459,1.62-0.276,2.081,0.414c0.46,0.688,0.275,1.62-0.413,2.081C13.998,16.244,12,19.979,12,24 s1.998,7.756,5.344,9.993c0.688,0.46,0.873,1.392,0.413,2.081C17.468,36.506,16.992,36.74,16.509,36.74z"/><linearGradient id="u86~y8WlEM9fdnhAWXl77d" x1="34.495" x2="34.495" y1="4.118" y2="48.04" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#u86~y8WlEM9fdnhAWXl77d)" d="M31.491,36.74c-0.483,0-0.959-0.234-1.248-0.667c-0.46-0.688-0.275-1.62,0.413-2.081 C34.002,31.756,36,28.021,36,24s-1.998-7.756-5.344-9.993c-0.688-0.46-0.873-1.392-0.413-2.081c0.461-0.69,1.392-0.873,2.081-0.414 C36.504,14.308,39,18.976,39,24s-2.496,9.692-6.676,12.487C32.068,36.658,31.778,36.74,31.491,36.74z"/><linearGradient id="u86~y8WlEM9fdnhAWXl77e" x1="8.84" x2="8.84" y1="4.118" y2="48.04" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#u86~y8WlEM9fdnhAWXl77e)" d="M13.179,41.72c-0.286,0-0.575-0.082-0.831-0.251C6.494,37.569,3,31.039,3,24 s3.494-13.569,9.348-17.469c0.688-0.458,1.62-0.273,2.08,0.417c0.46,0.689,0.273,1.621-0.416,2.08C8.995,12.37,6,17.967,6,24 s2.995,11.63,8.012,14.972c0.689,0.459,0.876,1.391,0.416,2.08C14.139,41.486,13.663,41.72,13.179,41.72z"/><linearGradient id="u86~y8WlEM9fdnhAWXl77f" x1="39.16" x2="39.16" y1="4.118" y2="48.04" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#u86~y8WlEM9fdnhAWXl77f)" d="M34.821,41.72c-0.484,0-0.96-0.234-1.249-0.668c-0.46-0.689-0.273-1.621,0.416-2.08 C39.005,35.63,42,30.033,42,24s-2.995-11.63-8.012-14.972c-0.689-0.459-0.876-1.391-0.416-2.08c0.46-0.69,1.392-0.875,2.08-0.417 C41.506,10.431,45,16.961,45,24s-3.494,13.569-9.348,17.469C35.396,41.639,35.107,41.72,34.821,41.72z"/></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="AkEixl0fFF2Red42g8M2Fa" x1="12.727" x2="4.186" y1="33.727" y2="25.186" gradientUnits="userSpaceOnUse"><stop offset=".365" stop-color="#199ae0"/><stop offset=".699" stop-color="#1898de"/><stop offset=".819" stop-color="#1691d8"/><stop offset=".905" stop-color="#1186cc"/><stop offset=".974" stop-color="#0a75bc"/><stop offset="1" stop-color="#076cb3"/></linearGradient><path fill="url(#AkEixl0fFF2Red42g8M2Fa)" d="M0.29,24.701l9.509,9.509c0.387,0.387,1.014,0.387,1.401,0l2.009-2.009 c0.387-0.387,0.387-1.014,0-1.401L3.701,21.29c-0.387-0.387-1.014-0.387-1.401,0L0.29,23.299 C-0.097,23.686-0.097,24.314,0.29,24.701z"/><linearGradient id="AkEixl0fFF2Red42g8M2Fb" x1="1.359" x2="12.357" y1="25.641" y2="14.643" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#AkEixl0fFF2Red42g8M2Fb)" d="M3.701,26.71l9.509-9.509c0.387-0.387,0.387-1.014,0-1.401l-2.009-2.009 c-0.387-0.387-1.014-0.387-1.401,0L0.29,23.299c-0.387,0.387-0.387,1.014,0,1.401l2.009,2.009 C2.686,27.097,3.314,27.097,3.701,26.71z"/><linearGradient id="AkEixl0fFF2Red42g8M2Fc" x1="689.727" x2="681.186" y1="33.727" y2="25.186" gradientTransform="matrix(-1 0 0 1 725 0)" gradientUnits="userSpaceOnUse"><stop offset=".365" stop-color="#199ae0"/><stop offset=".699" stop-color="#1898de"/><stop offset=".819" stop-color="#1691d8"/><stop offset=".905" stop-color="#1186cc"/><stop offset=".974" stop-color="#0a75bc"/><stop offset="1" stop-color="#076cb3"/></linearGradient><path fill="url(#AkEixl0fFF2Red42g8M2Fc)" d="M47.71,24.701l-9.509,9.509c-0.387,0.387-1.014,0.387-1.401,0l-2.009-2.009 c-0.387-0.387-0.387-1.014,0-1.401l9.509-9.509c0.387-0.387,1.014-0.387,1.401,0l2.009,2.009 C48.097,23.686,48.097,24.314,47.71,24.701z"/><linearGradient id="AkEixl0fFF2Red42g8M2Fd" x1="678.359" x2="689.357" y1="25.641" y2="14.643" gradientTransform="matrix(-1 0 0 1 725 0)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#AkEixl0fFF2Red42g8M2Fd)" d="M44.299,26.71l-9.509-9.509c-0.387-0.387-0.387-1.014,0-1.401l2.009-2.009 c0.387-0.387,1.014-0.387,1.401,0l9.509,9.509c0.387,0.387,0.387,1.014,0,1.401l-2.009,2.009 C45.314,27.097,44.686,27.097,44.299,26.71z"/><path fill="#0078d4" d="M30.25,2.5h-3.61c-0.473,0-0.882,0.332-0.979,0.795l-8.644,41.301 c-0.098,0.466,0.258,0.904,0.734,0.904h3.61c0.473,0,0.882-0.332,0.979-0.795l8.644-41.301C31.081,2.938,30.726,2.5,30.25,2.5z"/></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="Lmh0kZS7YksqX284AbgOOa" x1="16.86" x2="29.576" y1="-563.533" y2="-603.546" gradientTransform="matrix(1 0 0 -1 0 -562)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c77740"/><stop offset="1" stop-color="#b0622b"/></linearGradient><path fill="url(#Lmh0kZS7YksqX284AbgOOa)" d="M38,4H26c0,1.105-0.895,2-2,2s-2-0.895-2-2H10C8.895,4,8,4.895,8,6v36c0,1.105,0.895,2,2,2h28 c1.105,0,2-0.895,2-2V6C40,4.895,39.105,4,38,4z"/><linearGradient id="Lmh0kZS7YksqX284AbgOOb" x1="24" x2="24" y1="-598.966" y2="-602.893" gradientTransform="matrix(1 0 0 -1 0 -562)" gradientUnits="userSpaceOnUse"><stop offset=".442" stop-color="#878786"/><stop offset=".594" stop-color="#9f9f9e"/><stop offset=".859" stop-color="#c3c3c3"/><stop offset="1" stop-color="#d1d1d1"/></linearGradient><path fill="url(#Lmh0kZS7YksqX284AbgOOb)" d="M37,42H11c-0.552,0-1-0.448-1-1v-9h28v9C38,41.552,37.552,42,37,42z"/><path fill="#f3f3f3" d="M37,40H11c-0.552,0-1-0.448-1-1V7c0-0.552,0.448-1,1-1h26c0.552,0,1,0.448,1,1v32 C38,39.552,37.552,40,37,40z"/><linearGradient id="Lmh0kZS7YksqX284AbgOOc" x1="-450.93" x2="-449.046" y1="860.928" y2="853.091" gradientTransform="matrix(-1 0 0 1 -426 -851)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c3cdd9"/><stop offset="1" stop-color="#9fa7b0"/></linearGradient><path fill="url(#Lmh0kZS7YksqX284AbgOOc)" d="M31,8V4h-4.184C26.403,2.837,25.304,2,24,2s-2.403,0.837-2.816,2H17v4c0,0.552,0.448,1,1,1h12 C30.552,9,31,8.552,31,8z M24,4c0.552,0,1,0.448,1,1s-0.448,1-1,1s-1-0.448-1-1S23.448,4,24,4z"/><path fill="#c94f60" d="M32.802,17.926l-1.729-1.729c-0.263-0.263-0.691-0.263-0.954,0l-0.814,0.815l2.683,2.683l0.815-0.814 C33.066,18.618,33.066,18.191,32.802,17.926"/><linearGradient id="Lmh0kZS7YksqX284AbgOOd" x1="15" x2="18.962" y1="31.993" y2="31.993" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#dedede"/><stop offset="1" stop-color="#d6d6d6"/></linearGradient><path fill="url(#Lmh0kZS7YksqX284AbgOOd)" d="M15.902,30.414L15,34l3.586-0.903l0.376-3.111L15.902,30.414z"/><path fill="#edbe00" d="M29.699,21.983L18.587,33.097l-2.683-2.683L27.016,19.3L29.699,21.983z"/><linearGradient id="Lmh0kZS7YksqX284AbgOOe" x1="29.501" x2="29.501" y1="17.181" y2="22.121" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#dedede"/><stop offset="1" stop-color="#d6d6d6"/></linearGradient><path fill="url(#Lmh0kZS7YksqX284AbgOOe)" d="M27.014,19.301l2.289-2.29l2.685,2.683l-2.289,2.29L27.014,19.301z"/><path fill="#787878" d="M15.457,32.187L15,34l1.813-0.457L15.457,32.187z"/></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><circle cx="40" cy="9" r="1" fill="#64717c"/><circle cx="36" cy="9" r="1" fill="#64717c"/><circle cx="40" cy="13" r="1" fill="#64717c"/><circle cx="40" cy="17" r="1" fill="#64717c"/><circle cx="40" cy="25" r="1" fill="#64717c"/><circle cx="40" cy="29" r="1" fill="#64717c"/><circle cx="40" cy="33" r="1" fill="#64717c"/><circle cx="40" cy="37" r="1" fill="#64717c"/><circle cx="40" cy="41" r="1" fill="#64717c"/><circle cx="36" cy="41" r="1" fill="#64717c"/><circle cx="32" cy="41" r="1" fill="#64717c"/><circle cx="28" cy="41" r="1" fill="#64717c"/><circle cx="40" cy="21" r="1" fill="#64717c"/><path fill="#50e6ff" d="M23,8v34H9c-1.105,0-2-0.895-2-2V10c0-1.105,0.895-2,2-2H23z"/><linearGradient id="dRcwZ02OpsMOf2NkRFIUha" x1="24.832" x2="30.98" y1="5.725" y2="40.593" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#dRcwZ02OpsMOf2NkRFIUha)" d="M23,8l8.629-3.451C32.285,4.286,33,4.77,33,5.477v31.169c0,0.818-0.498,1.553-1.257,1.857 L23,42V8z"/><linearGradient id="dRcwZ02OpsMOf2NkRFIUhb" x1="29.541" x2="14.544" y1="21.499" y2="21.499" gradientUnits="userSpaceOnUse"><stop offset=".478" stop-color="#ad4bd5"/><stop offset="1" stop-color="#912fbd"/></linearGradient><path fill="url(#dRcwZ02OpsMOf2NkRFIUhb)" d="M29.78,20.969l-4.131-4.131c-0.236-0.236-0.64-0.068-0.64,0.265V20h-8.011L16.5,22.999h8.51 v2.897c0,0.334,0.404,0.501,0.64,0.265l4.131-4.131C30.073,21.737,30.073,21.262,29.78,20.969z"/><linearGradient id="dRcwZ02OpsMOf2NkRFIUhc" x1="-588.523" x2="-585.524" y1="113.841" y2="113.841" gradientTransform="translate(602.523 -87.841)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c965eb"/><stop offset="1" stop-color="#c767e5"/></linearGradient><path fill="url(#dRcwZ02OpsMOf2NkRFIUhc)" d="M16.999,31.5V20C15.124,21.499,14,22.624,14,24.123V31.5c0,0.276,0.224,0.5,0.5,0.5h1.999 C16.775,32,16.999,31.776,16.999,31.5z"/></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="GwuMQJpzjGUV7n3q2Qpbla" x1="13.48" x2="31.634" y1="11.593" y2="37.853" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#7dd8f3"/><stop offset="1" stop-color="#45b0d0"/></linearGradient><path fill="url(#GwuMQJpzjGUV7n3q2Qpbla)" d="M4,38V15h40v23c0,1.1-0.9,2-2,2H6C4.9,40,4,39.1,4,38z"/><path fill="#0d86ad" d="M39.5,23h-13c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h13c0.276,0,0.5,0.224,0.5,0.5 v1C40,22.776,39.776,23,39.5,23z"/><path fill="#0d86ad" d="M39.5,27h-13c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h13c0.276,0,0.5,0.224,0.5,0.5 v1C40,26.776,39.776,27,39.5,27z"/><path fill="#0d86ad" d="M39.5,31h-13c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h13c0.276,0,0.5,0.224,0.5,0.5 v1C40,30.776,39.776,31,39.5,31z"/><path fill="#0d86ad" d="M36.5,35h-10c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h10c0.276,0,0.5,0.224,0.5,0.5 v1C37,34.776,36.776,35,36.5,35z"/><linearGradient id="GwuMQJpzjGUV7n3q2Qpblb" x1="4.614" x2="42.936" y1="7.741" y2="15.533" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0077d2"/><stop offset="1" stop-color="#0b59a2"/></linearGradient><path fill="url(#GwuMQJpzjGUV7n3q2Qpblb)" d="M44,10v5H4v-5c0-1.1,0.9-2,2-2h36C43.1,8,44,8.9,44,10z"/><linearGradient id="GwuMQJpzjGUV7n3q2Qpblc" x1="16" x2="42" y1="11.5" y2="11.5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#7dd8f3"/><stop offset="1" stop-color="#45b0d0"/></linearGradient><path fill="url(#GwuMQJpzjGUV7n3q2Qpblc)" d="M16.5,13h25c0.276,0,0.5-0.224,0.5-0.5v-2c0-0.276-0.224-0.5-0.5-0.5h-25 c-0.276,0-0.5,0.224-0.5,0.5v2C16,12.776,16.224,13,16.5,13z"/><linearGradient id="GwuMQJpzjGUV7n3q2Qpbld" x1="6.751" x2="8.032" y1="10.416" y2="12.269" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#75daff"/><stop offset="1" stop-color="#49bef1"/></linearGradient><circle cx="7.5" cy="11.5" r="1.5" fill="url(#GwuMQJpzjGUV7n3q2Qpbld)"/><linearGradient id="GwuMQJpzjGUV7n3q2Qpble" x1="11.751" x2="13.032" y1="10.416" y2="12.269" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#75daff"/><stop offset="1" stop-color="#49bef1"/></linearGradient><circle cx="12.5" cy="11.5" r="1.5" fill="url(#GwuMQJpzjGUV7n3q2Qpble)"/><radialGradient id="GwuMQJpzjGUV7n3q2Qpblf" cx="24.519" cy="32.852" r="8.922" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ba84f5"/><stop offset=".129" stop-color="#b584f3"/><stop offset=".291" stop-color="#a585ee"/><stop offset=".47" stop-color="#8c87e6"/><stop offset=".662" stop-color="#6889db"/><stop offset=".862" stop-color="#3b8bcd"/><stop offset="1" stop-color="#178dc2"/></radialGradient><path fill="url(#GwuMQJpzjGUV7n3q2Qpblf)" d="M21.222,21H8.778C8.348,21,8,21.348,8,21.778v12.444C8,34.652,8.348,35,8.778,35h12.444 C21.652,35,22,34.652,22,34.222V21.778C22,21.348,21.652,21,21.222,21z"/><path fill="#436dcd" d="M18.136,27.636c-0.447-0.447-1.168-0.457-1.627-0.022l-3.842,3.64V35h8.556 C21.652,35,22,34.652,22,34.222V31.5L18.136,27.636z"/><circle cx="19" cy="24" r="1" fill="#fff"/><linearGradient id="GwuMQJpzjGUV7n3q2Qpblg" x1="14.965" x2="14.965" y1="25.718" y2="35.161" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#124787"/><stop offset=".923" stop-color="#173b75"/><stop offset="1" stop-color="#173a73"/></linearGradient><path fill="url(#GwuMQJpzjGUV7n3q2Qpblg)" d="M8.778,35h12.444c0.316,0,0.586-0.189,0.708-0.459l-8.46-8.46 c-0.447-0.447-1.168-0.457-1.627-0.022L8,29.699v4.523C8,34.652,8.348,35,8.778,35z"/></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

@ -112,8 +112,11 @@
no-caps no-caps
icon="la:user-plus" icon="la:user-plus"
@click="switchTo(`register`)" /> @click="switchTo(`register`)" />
<!-- -> Off where the strategy says so: a wiki that hands passwords out rather than letting
them be chosen has nothing for this to do -->
<w-btn <w-btn
class="acrylic-btn w-full" class="acrylic-btn w-full"
v-if="selectedStrategy.activeStrategy.allowForgotPassword"
flat flat
color="primary" color="primary"
:label="t(`auth.forgotPasswordLink`)" :label="t(`auth.forgotPasswordLink`)"

@ -121,7 +121,7 @@
t('editor.markup.superscript') t('editor.markup.superscript')
}}</w-tooltip> }}</w-tooltip>
</w-btn> </w-btn>
<w-btn icon="mdi:alpha-t-box-outline" padding="xs sm" flat> <w-btn icon="mdi:format-quote-close" padding="xs sm" flat>
<w-tooltip anchor="top middle" self="bottom middle">{{ <w-tooltip anchor="top middle" self="bottom middle">{{
t('editor.markup.blockquoteAdmonitions') t('editor.markup.blockquoteAdmonitions')
}}</w-tooltip> }}</w-tooltip>

@ -13,7 +13,11 @@
style="min-height: 64px"> style="min-height: 64px">
<!-- -> 64px, the size the icon has when the page is merely being read; see the branch below --> <!-- -> 64px, the size the icon has when the page is merely being read; see the branch below -->
<w-icon :name="pageStore.icon" size="64px" /> <w-icon :name="pageStore.icon" size="64px" />
<w-menu content-class="shadow-7"><icon-picker-dialog v-model="pageStore.icon" /></w-menu> <!-- -> Not `v-model`: writing the store is only half of what picking an icon means here, and
the other half is telling the editor the page changed. See `setIcon`. -->
<w-menu content-class="shadow-7">
<icon-picker-dialog :model-value="pageStore.icon" @update:model-value="setIcon" />
</w-menu>
</w-btn> </w-btn>
<w-icon class="rounded" v-else :name="pageStore.icon" size="64px" color="primary" /> <w-icon class="rounded" v-else :name="pageStore.icon" size="64px" color="primary" />
</div> </div>
@ -451,6 +455,19 @@ async function seedEditables() {
syncEditable(descriptionEl.value, pageStore.description) syncEditable(descriptionEl.value, pageStore.description)
} }
/**
* The icon picked from the header.
*
* The same two steps the title and the description take below, and for the same reason: an icon is part
* of the page, so changing it has to leave the editor holding an unsaved change. Bound through the event
* rather than `v-model` because that wrote the store and nothing else -- Save Changes stayed disabled
* until something else was edited, and closing the editor threw the new icon away without a word.
*/
function setIcon(icon) {
pageStore.icon = icon
editorStore.lastChangeTimestamp = Temporal.Now.instant()
}
function onEditableInput(field, event) { function onEditableInput(field, event) {
// -> Clearing the field leaves a browser-inserted `<br>` behind, which contributes nothing to the // -> Clearing the field leaves a browser-inserted `<br>` behind, which contributes nothing to the
// text but does hold a second line open under the placeholder // text but does hold a second line open under the placeholder

@ -765,7 +765,20 @@
&::before { &::before {
content: ''; content: '';
position: absolute; position: absolute;
top: 1em; /*
Centred on the CAP BAND of the first line, not on the line box that holds it.
A line box is ascent plus descent, and a title like "Note" or "Caution" inks only the part
between the cap line and the baseline -- so an icon centred on the line came out a pixel high,
and at this size that reads as its bottom edge running flush with the baseline while its top
towers over the capitals. Which is why the warning triangle looked right and nothing else did:
its mass is all at the base, so a bottom-flush box still reads as balanced.
`0.9em` is the padding above the first line, `0.79em` the middle of the cap band within it
(half-leading plus ascent, less half the cap height, for the app's Roboto at 1.6 line-height),
and `0.625em` half the icon.
*/
top: calc(0.9em + 0.79em - 0.625em);
left: 1.1em; left: 1.1em;
width: 1.25em; width: 1.25em;
height: 1.25em; height: 1.25em;

@ -22,26 +22,32 @@ const KINDS = new Map([
]) ])
/** /**
* The marker, which has to be the whole of the blockquote's first line. * The marker, and whatever the author wrote after it on the same line.
* *
* Anything after it on that line means the author wrote a blockquote that happens to open with * That remainder is the admonition's title: `> [!NOTE] Read this first` is headed "Read this first"
* brackets, which is what GitHub decides too and the line is then left exactly as it was typed. * rather than "Note". A deliberate step past GitHub, which renders those words as the first line of the
* quote instead and the step every other implementation of these takes, because a marker's own label
* says only what kind of aside it is, never what this one is about.
*
* Left off, the kind's own label stands in, exactly as before. What is captured is raw markdown and is
* parsed as such (see `titleTokens`), so a title may hold a link or a `code` span like any other line.
*/ */
const MARKER = /^\[!([a-z]+)\][ \t]*(?:\n|$)/i const MARKER = /^\[!([a-z]+)\][ \t]*([^\n]*)(?:\n|$)/i
/** /**
* The label, as three tokens: a paragraph carrying a class, its inline content, and the close. * The title, as three tokens: a paragraph carrying a class, its inline content, and the close.
* *
* The inline token is left with nothing but `content`; the core `inline` rule runs after this one and * The inline token is left with nothing but `content`; the core `inline` rule runs after this one and
* is what turns that into children, the same as for every other paragraph on the page. * is what turns that into children, the same as for every other paragraph on the page which is also
* what lets an author's own title carry markdown, and what keeps it escaped if it carries anything else.
*/ */
function labelTokens(state, label) { function titleTokens(state, title) {
const open = new state.Token('paragraph_open', 'p', 1) const open = new state.Token('paragraph_open', 'p', 1)
open.attrSet('class', 'alert-title') open.attrSet('class', 'alert-title')
open.block = true open.block = true
const inline = new state.Token('inline', '', 0) const inline = new state.Token('inline', '', 0)
inline.content = label inline.content = title
inline.children = [] inline.children = []
const close = new state.Token('paragraph_close', 'p', -1) const close = new state.Token('paragraph_close', 'p', -1)
@ -79,13 +85,16 @@ export default (md) => {
// top of that is what the stylesheet is written to expect // top of that is what the stylesheet is written to expect
tokens[i].attrJoin('class', kind.className) tokens[i].attrJoin('class', kind.className)
// -> A title of nothing but spaces is no title: the kind says what it is instead
const title = marker[2].trim() || kind.label
const rest = tokens[i + 2].content.slice(marker[0].length) const rest = tokens[i + 2].content.slice(marker[0].length)
if (rest) { if (rest) {
tokens[i + 2].content = rest tokens[i + 2].content = rest
tokens.splice(i + 1, 0, ...labelTokens(state, kind.label)) tokens.splice(i + 1, 0, ...titleTokens(state, title))
} else { } else {
// -> The marker was the whole paragraph, so the label takes its place rather than joining it // -> The marker line was the whole paragraph, so the title takes its place rather than joining it
tokens.splice(i + 1, 3, ...labelTokens(state, kind.label)) tokens.splice(i + 1, 3, ...titleTokens(state, title))
} }
} }
}) })

Loading…
Cancel
Save