feat: page alias, theme layout options, code block themes

pull/6775/head
NGPixel 2 years ago
parent 80b1cbff5c
commit 3da8fb417c
No known key found for this signature in database
GPG Key ID: B755FB6870B30F63

@ -168,7 +168,7 @@ export async function up (knex) {
table.boolean('isRTL').notNullable().defaultTo(false)
table.string('name').notNullable()
table.string('nativeName').notNullable()
table.integer('availability').notNullable().defaultTo(0)
table.integer('completeness').notNullable().defaultTo(0)
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
})
@ -606,6 +606,7 @@ export async function up (knex) {
},
theme: {
dark: false,
codeBlocksTheme: 'github-dark',
colorPrimary: '#1976D2',
colorSecondary: '#02C39A',
colorAccent: '#FF9800',

@ -187,6 +187,31 @@ export default {
throw new Error('ERR_PAGE_NOT_FOUND')
}
},
/**
* FETCH PATH FROM ALIAS
*/
async pathFromAlias (obj, args, context, info) {
const alias = args.alias?.trim()
if (!alias) {
throw new Error('ERR_ALIAS_MISSING')
}
if (!WIKI.sites[args.siteId]) {
throw new Error('ERR_INVALID_SITE_ID')
}
const page = await WIKI.db.pages.query().findOne({
alias: args.alias,
siteId: args.siteId
}).select('id', 'path', 'localeCode')
if (!page) {
throw new Error('ERR_ALIAS_NOT_FOUND')
}
return {
id: page.id,
path: WIKI.sites[args.siteId].config.localeNamespacing ? `${page.localeCode}/${page.path}` : page.path
}
},
/**
* FETCH TAGS
*/

@ -41,12 +41,6 @@ extend type Query {
password: String
): Page
tags: [PageTag]!
searchTags(
query: String!
): [String]!
pageTree(
path: String
parent: Int
@ -59,6 +53,17 @@ extend type Query {
locale: String!
): [PageLinkItem]
pathFromAlias(
siteId: UUID!
alias: String!
): PageAliasPath
searchTags(
query: String!
): [String]!
tags: [PageTag]!
checkConflicts(
id: Int!
checkoutDate: Date!
@ -71,6 +76,7 @@ extend type Query {
extend type Mutation {
createPage(
alias: String
allowComments: Boolean
allowContributions: Boolean
allowRatings: Boolean
@ -165,6 +171,7 @@ type PageMigrationResponse {
}
type Page {
alias: String
allowComments: Boolean
allowContributions: Boolean
allowRatings: Boolean
@ -329,6 +336,7 @@ input PageRelationInput {
}
input PageUpdateInput {
alias: String
allowComments: Boolean
allowContributions: Boolean
allowRatings: Boolean
@ -355,6 +363,11 @@ input PageUpdateInput {
tocDepth: PageTocDepthInput
}
type PageAliasPath {
id: UUID
path: String
}
type PageTocDepth {
min: Int
max: Int

@ -118,6 +118,7 @@ type SiteEditor {
type SiteTheme {
dark: Boolean
codeBlocksTheme: String
colorPrimary: String
colorSecondary: String
colorAccent: String
@ -210,6 +211,7 @@ input SiteDefaultsInput {
input SiteThemeInput {
dark: Boolean
codeBlocksTheme: String
colorPrimary: String
colorSecondary: String
colorAccent: String

File diff suppressed because it is too large Load Diff

@ -0,0 +1,9 @@
[
{
"code": "en",
"name": "English",
"nativeName": "English",
"rtl": false,
"completeness": 100
}
]

@ -19,7 +19,7 @@ export class Locale extends Model {
nativeName: {type: 'string'},
createdAt: {type: 'string'},
updatedAt: {type: 'string'},
availability: {type: 'integer'}
completeness: {type: 'integer'}
}
}
}

@ -19,6 +19,7 @@ import { Tag } from './tags.mjs'
import { User } from './users.mjs'
const pageRegex = /^[a-zA0-90-9-_/]*$/
const aliasRegex = /^[a-zA0-90-9-_]*$/
const frontmatterRegex = {
html: /^(<!-{2}(?:\n|\r)([\w\W]+?)(?:\n|\r)-{2}>)?(?:\n|\r)*([\w\W]*)*/,
@ -236,7 +237,7 @@ export class Page extends Model {
static async createPage(opts) {
// -> Validate site
if (!WIKI.sites[opts.siteId]) {
throw new WIKI.Error.Custom('InvalidSiteId', 'Site ID is invalid.')
throw new Error('ERR_INVALID_SITE_ID')
}
// -> Remove trailing slash
@ -262,13 +263,31 @@ export class Page extends Model {
locale: opts.locale,
path: opts.path
})) {
throw new WIKI.Error.PageDeleteForbidden()
throw new Error('ERR_FORBIDDEN')
}
// -> Check for duplicate
const dupCheck = await WIKI.db.pages.query().select('id').where('localeCode', opts.locale).where('path', opts.path).first()
const dupCheck = await WIKI.db.pages.query().findOne({
siteId: opts.siteId,
localeCode: opts.locale,
path: opts.path
}).select('id')
if (dupCheck) {
throw new WIKI.Error.PageDuplicateCreate()
throw new Error('ERR_PAGE_DUPLICATE_PATH')
}
// -> Check for alias
if (opts.alias) {
if (!aliasRegex.test(opts.alias)) {
throw new Error('ERR_PAGE_INVALID_ALIAS')
}
const dupAliasCheck = await WIKI.db.pages.query().findOne({
siteId: opts.siteId,
alias: opts.alias
}).select('id')
if (dupAliasCheck) {
throw new Error('ERR_PAGE_DUPLICATE_ALIAS')
}
}
// -> Check for empty content
@ -302,6 +321,7 @@ export class Page extends Model {
// -> Create page
const page = await WIKI.db.pages.query().insert({
alias: opts.alias,
authorId: opts.user.id,
content: opts.content,
creatorId: opts.user.id,
@ -449,6 +469,24 @@ export class Page extends Model {
historyData.affectedFields.push('icon')
}
if ('alias' in opts.patch) {
patch.alias = opts.patch.alias.trim()
historyData.affectedFields.push('alias')
if (patch.alias.length > 255) {
throw new Error('ERR_PAGE_ALIAS_TOO_LONG')
} else if (!aliasRegex.test(patch.alias)) {
throw new Error('ERR_PAGE_INVALID_ALIAS')
}
const dupAliasCheck = await WIKI.db.pages.query().where({
siteId: ogPage.siteId,
alias: patch.alias
}).andWhereNot('id', ogPage.id).select('id').first()
if (dupAliasCheck) {
throw new Error('ERR_PAGE_DUPLICATE_ALIAS')
}
}
if ('content' in opts.patch) {
patch.content = opts.patch.content
historyData.affectedFields.push('content')

@ -91,6 +91,7 @@ export class Site extends Model {
},
theme: {
dark: false,
codeBlocksTheme: 'github-dark',
colorPrimary: '#1976D2',
colorSecondary: '#02C39A',
colorAccent: '#FF9800',

@ -1,4 +1,4 @@
title: Git
title: Local Git
icon: '/_assets/icons/ultraviolet-git.svg'
banner: '/_assets/storage/git.jpg'
description: Git is a version control system for tracking changes in computer files and coordinating work on those files among multiple people. If using GitHub, use the GitHub module instead!

File diff suppressed because it is too large Load Diff

@ -34,10 +34,10 @@
"node": ">=18.0"
},
"dependencies": {
"@azure/storage-blob": "12.13.0",
"@azure/storage-blob": "12.14.0",
"@exlinc/keycloak-passport": "1.0.2",
"@graphql-tools/schema": "9.0.17",
"@graphql-tools/utils": "9.2.1",
"@graphql-tools/schema": "10.0.0",
"@graphql-tools/utils": "10.0.0",
"@joplin/turndown-plugin-gfm": "1.0.47",
"@root/csr": "0.8.1",
"@root/keypairs": "0.10.3",
@ -48,7 +48,7 @@
"apollo-server": "3.6.7",
"apollo-server-express": "3.6.7",
"auto-load": "3.0.4",
"aws-sdk": "2.1353.0",
"aws-sdk": "2.1381.0",
"bcryptjs": "2.4.3",
"body-parser": "1.20.2",
"chalk": "5.2.0",
@ -66,34 +66,34 @@
"custom-error-instance": "2.1.2",
"dependency-graph": "0.11.0",
"diff": "5.1.0",
"diff2html": "3.4.34",
"dompurify": "3.0.1",
"diff2html": "3.4.35",
"dompurify": "3.0.3",
"dotize": "0.3.0",
"emoji-regex": "10.2.1",
"eventemitter2": "6.4.9",
"express": "4.18.2",
"express-brute": "1.0.1",
"express-session": "1.17.3",
"file-type": "18.2.1",
"file-type": "18.4.0",
"filesize": "10.0.7",
"fs-extra": "11.1.1",
"getos": "3.2.1",
"graphql": "16.6.0",
"graphql-list-fields": "2.0.2",
"graphql-rate-limit-directive": "2.0.3",
"graphql-tools": "8.3.19",
"graphql-tools": "9.0.0",
"graphql-upload": "16.0.2",
"he": "1.2.0",
"highlight.js": "11.7.0",
"i18next": "22.4.14",
"highlight.js": "11.8.0",
"i18next": "22.5.0",
"i18next-node-fs-backend": "2.1.3",
"image-size": "1.0.2",
"js-base64": "3.7.5",
"js-binary": "1.2.0",
"js-yaml": "4.1.0",
"jsdom": "21.1.1",
"jsdom": "22.0.0",
"jsonwebtoken": "9.0.0",
"katex": "0.16.4",
"katex": "0.16.7",
"klaw": "4.1.0",
"knex": "2.4.2",
"lodash": "4.17.21",
@ -108,7 +108,7 @@
"markdown-it-footnote": "3.0.3",
"markdown-it-imsize": "2.0.1",
"markdown-it-mark": "3.0.1",
"markdown-it-multimd-table": "4.2.1",
"markdown-it-multimd-table": "4.2.2",
"markdown-it-sub": "1.0.0",
"markdown-it-sup": "1.0.0",
"markdown-it-task-lists": "2.1.1",
@ -119,11 +119,11 @@
"nanoid": "4.0.2",
"node-2fa": "2.0.3",
"node-cache": "5.1.2",
"nodemailer": "6.9.1",
"nodemailer": "6.9.2",
"objection": "3.0.1",
"passport": "0.6.0",
"passport-auth0": "1.4.3",
"passport-azure-ad": "4.3.4",
"passport-azure-ad": "4.3.5",
"passport-cas": "0.1.1",
"passport-discord": "0.1.4",
"passport-dropbox-oauth2": "1.1.0",
@ -142,14 +142,14 @@
"passport-slack-oauth2": "1.1.1",
"passport-twitch-strategy": "2.2.0",
"pem-jwk": "2.0.0",
"pg": "8.10.0",
"pg": "8.11.0",
"pg-hstore": "2.3.4",
"pg-pubsub": "0.8.1",
"pg-query-stream": "4.4.0",
"pg-query-stream": "4.5.0",
"pg-tsquery": "8.4.1",
"poolifier": "2.4.4",
"poolifier": "2.4.14",
"punycode": "2.3.0",
"puppeteer-core": "19.8.5",
"puppeteer-core": "20.2.1",
"qr-image": "3.2.0",
"rate-limiter-flexible": "2.4.1",
"remove-markdown": "0.5.0",
@ -158,12 +158,12 @@
"safe-regex": "2.1.1",
"sanitize-filename": "1.6.3",
"scim-query-filter-parser": "2.0.4",
"semver": "7.3.8",
"semver": "7.5.1",
"serve-favicon": "2.5.0",
"sharp": "0.32.0",
"simple-git": "3.17.0",
"sharp": "0.32.1",
"simple-git": "3.18.0",
"socket.io": "4.6.1",
"ssh2": "1.11.0",
"ssh2": "1.13.0",
"ssh2-promise": "1.0.3",
"striptags": "3.2.0",
"tar-fs": "2.1.1",
@ -173,10 +173,10 @@
"uuid": "9.0.0",
"validate.js": "0.13.1",
"xss": "1.0.14",
"yargs": "17.7.1"
"yargs": "17.7.2"
},
"devDependencies": {
"eslint": "8.38.0",
"eslint": "8.41.0",
"eslint-config-requarks": "1.0.7",
"eslint-config-standard": "17.0.0",
"eslint-plugin-import": "2.27.5",

@ -54,7 +54,7 @@ export async function render (input, config) {
const highlighted = lang ? hljs.highlight(str, { language: lang, ignoreIllegals: true }) : { value: str }
const lineCount = highlighted.value.match(/\n/g).length
const lineNums = lineCount > 1 ? `<span aria-hidden="true" class="line-numbers-rows">${times(lineCount, n => '<span></span>').join('')}</span>` : ''
return `<pre class="codeblock ${lineCount > 1 && 'line-numbers'}"><code class="language-${lang}">${highlighted.value}${lineNums}</code></pre>`
return `<pre class="codeblock hljs ${lineCount > 1 && 'line-numbers'}"><code class="language-${lang}">${highlighted.value}${lineNums}</code></pre>`
}
}
})

1444
ux/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -13,37 +13,37 @@
"ncu-u": "ncu -u -x codemirror,codemirror-asciidoc"
},
"dependencies": {
"@apollo/client": "3.7.11",
"@apollo/client": "3.7.14",
"@lezer/common": "1.0.2",
"@mdi/font": "7.2.96",
"@quasar/extras": "1.16.2",
"@tiptap/core": "2.0.2",
"@tiptap/extension-code-block": "2.0.2",
"@tiptap/extension-code-block-lowlight": "2.0.2",
"@tiptap/extension-color": "2.0.2",
"@tiptap/extension-dropcursor": "2.0.2",
"@tiptap/extension-font-family": "2.0.2",
"@tiptap/extension-gapcursor": "2.0.2",
"@tiptap/extension-hard-break": "2.0.2",
"@tiptap/extension-highlight": "2.0.2",
"@tiptap/extension-history": "2.0.2",
"@tiptap/extension-image": "2.0.2",
"@tiptap/extension-mention": "2.0.2",
"@tiptap/extension-placeholder": "2.0.2",
"@tiptap/extension-table": "2.0.2",
"@tiptap/extension-table-cell": "2.0.2",
"@tiptap/extension-table-header": "2.0.2",
"@tiptap/extension-table-row": "2.0.2",
"@tiptap/extension-task-item": "2.0.2",
"@tiptap/extension-task-list": "2.0.2",
"@tiptap/extension-text-align": "2.0.2",
"@tiptap/extension-text-style": "2.0.2",
"@tiptap/extension-typography": "2.0.2",
"@tiptap/pm": "2.0.2",
"@tiptap/starter-kit": "2.0.2",
"@tiptap/vue-3": "2.0.2",
"@quasar/extras": "1.16.4",
"@tiptap/core": "2.0.3",
"@tiptap/extension-code-block": "2.0.3",
"@tiptap/extension-code-block-lowlight": "2.0.3",
"@tiptap/extension-color": "2.0.3",
"@tiptap/extension-dropcursor": "2.0.3",
"@tiptap/extension-font-family": "2.0.3",
"@tiptap/extension-gapcursor": "2.0.3",
"@tiptap/extension-hard-break": "2.0.3",
"@tiptap/extension-highlight": "2.0.3",
"@tiptap/extension-history": "2.0.3",
"@tiptap/extension-image": "2.0.3",
"@tiptap/extension-mention": "2.0.3",
"@tiptap/extension-placeholder": "2.0.3",
"@tiptap/extension-table": "2.0.3",
"@tiptap/extension-table-cell": "2.0.3",
"@tiptap/extension-table-header": "2.0.3",
"@tiptap/extension-table-row": "2.0.3",
"@tiptap/extension-task-item": "2.0.3",
"@tiptap/extension-task-list": "2.0.3",
"@tiptap/extension-text-align": "2.0.3",
"@tiptap/extension-text-style": "2.0.3",
"@tiptap/extension-typography": "2.0.3",
"@tiptap/pm": "2.0.3",
"@tiptap/starter-kit": "2.0.3",
"@tiptap/vue-3": "2.0.3",
"apollo-upload-client": "17.0.0",
"browser-fs-access": "0.33.0",
"browser-fs-access": "0.34.0",
"clipboard": "2.0.11",
"codemirror": "5.65.11",
"codemirror-asciidoc": "1.0.4",
@ -53,12 +53,12 @@
"fuse.js": "6.6.2",
"graphql": "16.6.0",
"graphql-tag": "2.12.6",
"highlight.js": "11.7.0",
"js-cookie": "3.0.1",
"highlight.js": "11.8.0",
"js-cookie": "3.0.5",
"jwt-decode": "3.1.2",
"katex": "0.16.4",
"katex": "0.16.7",
"lodash-es": "4.17.21",
"lowlight": "2.8.1",
"lowlight": "2.9.0",
"luxon": "3.3.0",
"markdown-it": "13.0.1",
"markdown-it-abbr": "1.0.4",
@ -69,34 +69,34 @@
"markdown-it-footnote": "3.0.3",
"markdown-it-imsize": "2.0.1",
"markdown-it-mark": "3.0.1",
"markdown-it-multimd-table": "4.2.1",
"markdown-it-multimd-table": "4.2.2",
"markdown-it-sub": "1.0.0",
"markdown-it-sup": "1.0.0",
"markdown-it-task-lists": "2.1.1",
"mitt": "3.0.0",
"monaco-editor": "0.37.1",
"monaco-editor": "0.38.0",
"pako": "2.1.0",
"pinia": "2.0.33",
"prosemirror-commands": "1.5.1",
"prosemirror-history": "1.3.0",
"prosemirror-keymap": "1.2.1",
"prosemirror-model": "1.19.0",
"prosemirror-schema-list": "1.2.2",
"prosemirror-state": "1.4.2",
"prosemirror-transform": "1.7.1",
"prosemirror-view": "1.30.2",
"pinia": "2.1.3",
"prosemirror-commands": "1.5.2",
"prosemirror-history": "1.3.2",
"prosemirror-keymap": "1.2.2",
"prosemirror-model": "1.19.1",
"prosemirror-schema-list": "1.2.3",
"prosemirror-state": "1.4.3",
"prosemirror-transform": "1.7.2",
"prosemirror-view": "1.31.3",
"pug": "3.0.2",
"quasar": "2.11.10",
"quasar": "2.12.0",
"slugify": "1.6.6",
"socket.io-client": "4.6.1",
"tabulator-tables": "5.4.4",
"tippy.js": "6.3.7",
"twemoji": "14.0.2",
"uuid": "9.0.0",
"v-network-graph": "0.9.1",
"vue": "3.2.47",
"v-network-graph": "0.9.3",
"vue": "3.3.4",
"vue-i18n": "9.2.2",
"vue-router": "4.1.6",
"vue-router": "4.2.1",
"vue3-otp-input": "0.4.1",
"vuedraggable": "4.1.0",
"xterm": "5.1.0",
@ -104,17 +104,17 @@
},
"devDependencies": {
"@intlify/unplugin-vue-i18n": "0.10.0",
"@quasar/app-vite": "1.2.1",
"@types/lodash": "4.14.192",
"@volar/vue-language-plugin-pug": "1.2.0",
"@quasar/app-vite": "1.4.3",
"@types/lodash": "4.14.194",
"@volar/vue-language-plugin-pug": "1.6.5",
"autoprefixer": "10.4.14",
"browserlist": "latest",
"eslint": "8.37.0",
"eslint": "8.41.0",
"eslint-config-standard": "17.0.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-n": "15.7.0",
"eslint-plugin-n": "16.0.0",
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-vue": "9.10.0"
"eslint-plugin-vue": "9.13.0"
},
"engines": {
"node": ">= 18.0",

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M10 11L1.75 20 10 29M30 11L38.25 20 30 29M15 35L25 5"/></svg>

After

Width:  |  Height:  |  Size: 250 B

@ -75,7 +75,7 @@ module.exports = configure(function (/* ctx */) {
vueRouterMode: 'history', // available values: 'hash', 'history'
// vueRouterBase,
// vueDevtools,
// vueOptionsAPI: true,
vueOptionsAPI: false,
rebuildCache: true, // rebuilds Vite/linter/etc cache on startup
@ -90,28 +90,21 @@ module.exports = configure(function (/* ctx */) {
extendViteConf (viteConf) {
viteConf.build.assetsDir = '_assets'
// viteConf.resolve.alias.vue = '/workspace/ux/node_modules/vue/dist/vue.esm-bundler.js'
// viteConf.build.rollupOptions = {
// ...viteConf.build.rollupOptions ?? {},
// external: [
// /^\/_site\//
// ]
// }
viteConf.build.rollupOptions = {
...viteConf.build.rollupOptions ?? {},
output: {
manualChunks: {
lodash: ['lodash-es', 'lodash'],
quasar: ['quasar', 'quasar/src/components']
}
}
}
viteConf.optimizeDeps.include = [
'prosemirror-state',
'prosemirror-transform',
'prosemirror-model',
'prosemirror-view'
]
// viteConf.build.rollupOptions = {
// external: ['monaco-editor'],
// output: {
// globals: {
// 'monaco-editor': 'monaco-editor'
// }
// }
// }
},
// viteVuePluginOptions: {},
@ -139,7 +132,8 @@ module.exports = configure(function (/* ctx */) {
},
hmr: {
clientPort: userConfig.dev.hmrClientPort
}
},
vueDevtools: true
},
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework

@ -55,12 +55,15 @@ watch(() => userStore.cvd, () => {
// THEME
function applyTheme () {
async function applyTheme () {
// -> Dark Mode
if (userStore.appearance === 'site') {
$q.dark.set(siteStore.theme.dark)
} else {
$q.dark.set(userStore.appearance === 'dark')
}
// -> CSS Vars
setCssVar('primary', userStore.getAccessibleColor('primary', siteStore.theme.colorPrimary))
setCssVar('secondary', userStore.getAccessibleColor('secondary', siteStore.theme.colorSecondary))
setCssVar('accent', userStore.getAccessibleColor('accent', siteStore.theme.colorAccent))
@ -68,6 +71,21 @@ function applyTheme () {
setCssVar('sidebar', userStore.getAccessibleColor('sidebar', siteStore.theme.colorSidebar))
setCssVar('positive', userStore.getAccessibleColor('positive', '#02C39A'))
setCssVar('negative', userStore.getAccessibleColor('negative', '#f03a47'))
// -> Highlight.js Theme
if (siteStore.theme.codeBlocksTheme) {
const desiredHljsTheme = userStore.cvd !== 'none' ? 'github' : siteStore.theme.codeBlocksTheme
const hljsStyleEl = document.querySelector('#hljs-theme')
if (hljsStyleEl) {
hljsStyleEl.remove()
}
const newHljsStyleEl = document.createElement('style')
newHljsStyleEl.id = 'hljs-theme'
newHljsStyleEl.innerHTML = (await import(`../node_modules/highlight.js/styles/${desiredHljsTheme}.css`)).default
document.head.appendChild(newHljsStyleEl)
}
}
// INIT SITE STORE

@ -92,6 +92,7 @@
)
q-tooltip Bookmark Page
q-btn.q-ml-md(
v-if='siteStore.theme.showSharingMenu'
flat
dense
icon='las la-share-alt'
@ -101,6 +102,7 @@
q-tooltip Share
social-sharing-menu
q-btn.q-ml-md(
v-if='siteStore.theme.showPrintBtn'
flat
dense
icon='las la-print'
@ -297,7 +299,8 @@ async function saveChangesCommit (closeAfter = false) {
} catch (err) {
$q.notify({
type: 'negative',
message: 'Failed to save page changes.'
message: 'Failed to save page changes.',
caption: err.message
})
}
$q.loading.hide()

@ -62,6 +62,13 @@ q-card.page-properties-dialog
name='las la-icons'
color='primary'
)
q-input(
v-model='pageStore.alias'
:label='t(`editor.props.alias`)'
outlined
dense
prefix='/a/'
)
q-card-section.alt-card(id='refCardPublishState')
.text-overline.q-pb-xs.items-center.flex #[q-icon.q-mr-sm(name='las la-power-off', size='xs')] {{t('editor.props.publishState')}}
q-form.q-gutter-md

@ -15,7 +15,7 @@
// ---------------------------------
a {
color: $blue-8;
color: var(--q-primary);
&.is-internal-link.is-invalid-page {
color: $red-8;
@ -438,7 +438,7 @@
}
}
// ---------------------------------
// ---------------------------------
// TASK LISTS
// ---------------------------------
@ -514,22 +514,17 @@
// }
pre.codeblock {
border: none;
border: 1px solid rgba(0,0,0,.2);
border-radius: 5px;
box-shadow: initial;
background-color: $dark-5;
padding: 1rem;
margin: 1rem 0;
overflow: auto;
@at-root .body--dark & {
background-color: $dark-5;
}
> code {
background-color: transparent;
// background-color: transparent;
padding: 0;
color: #FFF;
// color: #FFF;
box-shadow: initial;
display: block;
font-size: .85rem;
@ -591,5 +586,3 @@
padding: 5px;
}
}
@import 'highlight.js/styles/atom-one-dark-reasonable.css';

@ -815,6 +815,9 @@
"admin.theme.baseFontHint": "The font used across the site for the interface.",
"admin.theme.bodyHtmlInjection": "Body HTML Injection",
"admin.theme.bodyHtmlInjectionHint": "HTML code to be injected just before the closing body tag.",
"admin.theme.codeBlocks": "Code Blocks",
"admin.theme.codeBlocksAppearance": "Code Blocks Appearance",
"admin.theme.codeBlocksAppearanceHint": "The color theme used to display code blocks on pages.",
"admin.theme.codeInjection": "Code Injection",
"admin.theme.contentFont": "Content Font",
"admin.theme.contentFontHint": "The font used specifically for page content.",
@ -1503,6 +1506,7 @@
"editor.pageRel.title": "Add Page Relation",
"editor.pageRel.titleEdit": "Edit Page Relation",
"editor.pageScripts.title": "Page Scripts",
"editor.props.alias": "Alias",
"editor.props.allowComments": "Allow Comments",
"editor.props.allowCommentsHint": "Enable commenting abilities on this page.",
"editor.props.allowContributions": "Allow Contributions",

@ -3,8 +3,9 @@ q-layout(view='hHh Lpr lff')
header-nav
q-drawer.bg-sidebar(
:modelValue='isSidebarShown'
show-if-above
:show-if-above='siteStore.theme.sidebarPosition !== `off`'
:width='255'
:side='siteStore.theme.sidebarPosition === `right` ? `right` : `left`'
)
.sidebar-actions.flex.items-stretch
q-btn.q-px-sm.col(
@ -144,7 +145,7 @@ const barStyle = {
// COMPUTED
const isSidebarShown = computed(() => {
return siteStore.showSideNav && !(editorStore.isActive && editorStore.hideSideNav)
return siteStore.showSideNav && !siteStore.sideNavIsDisabled && !(editorStore.isActive && editorStore.hideSideNav)
})
// METHODS

@ -91,27 +91,63 @@ q-page.admin-theme
v-model='state.config[`color` + startCase(cl)]'
)
//- -----------------------
//- Code Blocks
//- -----------------------
q-card.q-pb-sm.q-mt-md
q-card-section.flex.items-center
.text-subtitle1 {{t('admin.theme.codeBlocks')}}
q-space
q-btn.acrylic-btn(
icon='las la-redo-alt'
:label='t(`admin.theme.resetDefaults`)'
flat
size='sm'
color='pink'
@click='resetCodeBlocks'
)
q-item
blueprint-icon(icon='code')
q-item-section
q-item-label {{t(`admin.theme.codeBlocksAppearance`)}}
q-item-label(caption) {{t(`admin.theme.codeBlocksAppearanceHint`)}}
q-item-section
q-select(
outlined
v-model='state.config.codeBlocksTheme'
:options='codeThemes'
emit-value
map-options
:virtual-scroll-slice-size='100'
:virtual-scroll-slice-ratio-before='2'
:virtual-scroll-slice-ratio-after='2'
dense
options-dense
:aria-label='t(`admin.theme.codeBlocksAppearance`)'
)
//- -----------------------
//- Theme Layout
//- -----------------------
q-card.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{t('admin.theme.layout')}}
q-item
blueprint-icon(icon='width')
q-item-section
q-item-label {{t(`admin.theme.contentWidth`)}}
q-item-label(caption) {{t(`admin.theme.contentWidthHint`)}}
q-item-section.col-auto
q-btn-toggle(
v-model='state.config.contentWidth'
push
glossy
no-caps
toggle-color='primary'
:options='widthOptions'
)
q-separator.q-my-sm(inset)
template(v-if='flagStore.experimental')
q-item
blueprint-icon(icon='width')
q-item-section
q-item-label {{t(`admin.theme.contentWidth`)}}
q-item-label(caption) {{t(`admin.theme.contentWidthHint`)}}
q-item-section.col-auto
q-btn-toggle(
v-model='state.config.contentWidth'
push
glossy
no-caps
toggle-color='primary'
:options='widthOptions'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='right-navigation-toolbar')
q-item-section
@ -274,6 +310,7 @@ import { setCssVar, useMeta, useQuasar } from 'quasar'
import { onMounted, reactive, watch } from 'vue'
import { useAdminStore } from 'src/stores/admin'
import { useFlagsStore } from 'src/stores/flags'
import { useSiteStore } from 'src/stores/site'
import UtilCodeEditor from '../components/UtilCodeEditor.vue'
@ -285,6 +322,7 @@ const $q = useQuasar()
// STORES
const adminStore = useAdminStore()
const flagStore = useFlagsStore()
const siteStore = useSiteStore()
// I18N
@ -311,6 +349,7 @@ const state = reactive({
colorAccent: '#f03a47',
colorHeader: '#000',
colorSidebar: '#1976D2',
codeBlocksTheme: '',
contentWidth: 'full',
sidebarPosition: 'left',
tocPosition: 'right',
@ -350,6 +389,256 @@ const fonts = [
{ label: 'User System Defaults', value: 'user' }
]
const codeThemes = [
{ label: 'A 11 Y Dark', value: 'a11y-dark' },
{ label: 'A 11 Y Light', value: 'a11y-light' },
{ label: 'Agate', value: 'agate' },
{ label: 'An Old Hope', value: 'an-old-hope' },
{ label: 'Androidstudio', value: 'androidstudio' },
{ label: 'Arduino Light', value: 'arduino-light' },
{ label: 'Arta', value: 'arta' },
{ label: 'Ascetic', value: 'ascetic' },
{ label: 'Atom One Dark', value: 'atom-one-dark' },
{ label: 'Atom One Dark Reasonable', value: 'atom-one-dark-reasonable' },
{ label: 'Atom One Light', value: 'atom-one-light' },
{ label: 'Base16 / 3024', value: 'base16/3024' },
{ label: 'Base16 / Apathy', value: 'base16/apathy' },
{ label: 'Base16 / Apprentice', value: 'base16/apprentice' },
{ label: 'Base16 / Ashes', value: 'base16/ashes' },
{ label: 'Base16 / Atelier Cave', value: 'base16/atelier-cave' },
{ label: 'Base16 / Atelier Cave Light', value: 'base16/atelier-cave-light' },
{ label: 'Base16 / Atelier Dune', value: 'base16/atelier-dune' },
{ label: 'Base16 / Atelier Dune Light', value: 'base16/atelier-dune-light' },
{ label: 'Base16 / Atelier Estuary', value: 'base16/atelier-estuary' },
{ label: 'Base16 / Atelier Estuary Light', value: 'base16/atelier-estuary-light' },
{ label: 'Base16 / Atelier Forest', value: 'base16/atelier-forest' },
{ label: 'Base16 / Atelier Forest Light', value: 'base16/atelier-forest-light' },
{ label: 'Base16 / Atelier Heath', value: 'base16/atelier-heath' },
{ label: 'Base16 / Atelier Heath Light', value: 'base16/atelier-heath-light' },
{ label: 'Base16 / Atelier Lakeside', value: 'base16/atelier-lakeside' },
{ label: 'Base16 / Atelier Lakeside Light', value: 'base16/atelier-lakeside-light' },
{ label: 'Base16 / Atelier Plateau', value: 'base16/atelier-plateau' },
{ label: 'Base16 / Atelier Plateau Light', value: 'base16/atelier-plateau-light' },
{ label: 'Base16 / Atelier Savanna', value: 'base16/atelier-savanna' },
{ label: 'Base16 / Atelier Savanna Light', value: 'base16/atelier-savanna-light' },
{ label: 'Base16 / Atelier Seaside', value: 'base16/atelier-seaside' },
{ label: 'Base16 / Atelier Seaside Light', value: 'base16/atelier-seaside-light' },
{ label: 'Base16 / Atelier Sulphurpool', value: 'base16/atelier-sulphurpool' },
{ label: 'Base16 / Atelier Sulphurpool Light', value: 'base16/atelier-sulphurpool-light' },
{ label: 'Base16 / Atlas', value: 'base16/atlas' },
{ label: 'Base16 / Bespin', value: 'base16/bespin' },
{ label: 'Base16 / Black Metal', value: 'base16/black-metal' },
{ label: 'Base16 / Black Metal Bathory', value: 'base16/black-metal-bathory' },
{ label: 'Base16 / Black Metal Burzum', value: 'base16/black-metal-burzum' },
{ label: 'Base16 / Black Metal Dark Funeral', value: 'base16/black-metal-dark-funeral' },
{ label: 'Base16 / Black Metal Gorgoroth', value: 'base16/black-metal-gorgoroth' },
{ label: 'Base16 / Black Metal Immortal', value: 'base16/black-metal-immortal' },
{ label: 'Base16 / Black Metal Khold', value: 'base16/black-metal-khold' },
{ label: 'Base16 / Black Metal Marduk', value: 'base16/black-metal-marduk' },
{ label: 'Base16 / Black Metal Mayhem', value: 'base16/black-metal-mayhem' },
{ label: 'Base16 / Black Metal Nile', value: 'base16/black-metal-nile' },
{ label: 'Base16 / Black Metal Venom', value: 'base16/black-metal-venom' },
{ label: 'Base16 / Brewer', value: 'base16/brewer' },
{ label: 'Base16 / Bright', value: 'base16/bright' },
{ label: 'Base16 / Brogrammer', value: 'base16/brogrammer' },
{ label: 'Base16 / Brush Trees', value: 'base16/brush-trees' },
{ label: 'Base16 / Brush Trees Dark', value: 'base16/brush-trees-dark' },
{ label: 'Base16 / Chalk', value: 'base16/chalk' },
{ label: 'Base16 / Circus', value: 'base16/circus' },
{ label: 'Base16 / Classic Dark', value: 'base16/classic-dark' },
{ label: 'Base16 / Classic Light', value: 'base16/classic-light' },
{ label: 'Base16 / Codeschool', value: 'base16/codeschool' },
{ label: 'Base16 / Colors', value: 'base16/colors' },
{ label: 'Base16 / Cupcake', value: 'base16/cupcake' },
{ label: 'Base16 / Cupertino', value: 'base16/cupertino' },
{ label: 'Base16 / Danqing', value: 'base16/danqing' },
{ label: 'Base16 / Darcula', value: 'base16/darcula' },
{ label: 'Base16 / Dark Violet', value: 'base16/dark-violet' },
{ label: 'Base16 / Darkmoss', value: 'base16/darkmoss' },
{ label: 'Base16 / Darktooth', value: 'base16/darktooth' },
{ label: 'Base16 / Decaf', value: 'base16/decaf' },
{ label: 'Base16 / Default Dark', value: 'base16/default-dark' },
{ label: 'Base16 / Default Light', value: 'base16/default-light' },
{ label: 'Base16 / Dirtysea', value: 'base16/dirtysea' },
{ label: 'Base16 / Dracula', value: 'base16/dracula' },
{ label: 'Base16 / Edge Dark', value: 'base16/edge-dark' },
{ label: 'Base16 / Edge Light', value: 'base16/edge-light' },
{ label: 'Base16 / Eighties', value: 'base16/eighties' },
{ label: 'Base16 / Embers', value: 'base16/embers' },
{ label: 'Base16 / Equilibrium Dark', value: 'base16/equilibrium-dark' },
{ label: 'Base16 / Equilibrium Gray Dark', value: 'base16/equilibrium-gray-dark' },
{ label: 'Base16 / Equilibrium Gray Light', value: 'base16/equilibrium-gray-light' },
{ label: 'Base16 / Equilibrium Light', value: 'base16/equilibrium-light' },
{ label: 'Base16 / Espresso', value: 'base16/espresso' },
{ label: 'Base16 / Eva', value: 'base16/eva' },
{ label: 'Base16 / Eva Dim', value: 'base16/eva-dim' },
{ label: 'Base16 / Flat', value: 'base16/flat' },
{ label: 'Base16 / Framer', value: 'base16/framer' },
{ label: 'Base16 / Fruit Soda', value: 'base16/fruit-soda' },
{ label: 'Base16 / Gigavolt', value: 'base16/gigavolt' },
{ label: 'Base16 / Github', value: 'base16/github' },
{ label: 'Base16 / Google Dark', value: 'base16/google-dark' },
{ label: 'Base16 / Google Light', value: 'base16/google-light' },
{ label: 'Base16 / Grayscale Dark', value: 'base16/grayscale-dark' },
{ label: 'Base16 / Grayscale Light', value: 'base16/grayscale-light' },
{ label: 'Base16 / Green Screen', value: 'base16/green-screen' },
{ label: 'Base16 / Gruvbox Dark Hard', value: 'base16/gruvbox-dark-hard' },
{ label: 'Base16 / Gruvbox Dark Medium', value: 'base16/gruvbox-dark-medium' },
{ label: 'Base16 / Gruvbox Dark Pale', value: 'base16/gruvbox-dark-pale' },
{ label: 'Base16 / Gruvbox Dark Soft', value: 'base16/gruvbox-dark-soft' },
{ label: 'Base16 / Gruvbox Light Hard', value: 'base16/gruvbox-light-hard' },
{ label: 'Base16 / Gruvbox Light Medium', value: 'base16/gruvbox-light-medium' },
{ label: 'Base16 / Gruvbox Light Soft', value: 'base16/gruvbox-light-soft' },
{ label: 'Base16 / Hardcore', value: 'base16/hardcore' },
{ label: 'Base16 / Harmonic 16 Dark', value: 'base16/harmonic16-dark' },
{ label: 'Base16 / Harmonic 16 Light', value: 'base16/harmonic16-light' },
{ label: 'Base16 / Heetch Dark', value: 'base16/heetch-dark' },
{ label: 'Base16 / Heetch Light', value: 'base16/heetch-light' },
{ label: 'Base16 / Helios', value: 'base16/helios' },
{ label: 'Base16 / Hopscotch', value: 'base16/hopscotch' },
{ label: 'Base16 / Horizon Dark', value: 'base16/horizon-dark' },
{ label: 'Base16 / Horizon Light', value: 'base16/horizon-light' },
{ label: 'Base16 / Humanoid Dark', value: 'base16/humanoid-dark' },
{ label: 'Base16 / Humanoid Light', value: 'base16/humanoid-light' },
{ label: 'Base16 / Ia Dark', value: 'base16/ia-dark' },
{ label: 'Base16 / Ia Light', value: 'base16/ia-light' },
{ label: 'Base16 / Icy Dark', value: 'base16/icy-dark' },
{ label: 'Base16 / Ir Black', value: 'base16/ir-black' },
{ label: 'Base16 / Isotope', value: 'base16/isotope' },
{ label: 'Base16 / Kimber', value: 'base16/kimber' },
{ label: 'Base16 / London Tube', value: 'base16/london-tube' },
{ label: 'Base16 / Macintosh', value: 'base16/macintosh' },
{ label: 'Base16 / Marrakesh', value: 'base16/marrakesh' },
{ label: 'Base16 / Materia', value: 'base16/materia' },
{ label: 'Base16 / Material', value: 'base16/material' },
{ label: 'Base16 / Material Darker', value: 'base16/material-darker' },
{ label: 'Base16 / Material Lighter', value: 'base16/material-lighter' },
{ label: 'Base16 / Material Palenight', value: 'base16/material-palenight' },
{ label: 'Base16 / Material Vivid', value: 'base16/material-vivid' },
{ label: 'Base16 / Mellow Purple', value: 'base16/mellow-purple' },
{ label: 'Base16 / Mexico Light', value: 'base16/mexico-light' },
{ label: 'Base16 / Mocha', value: 'base16/mocha' },
{ label: 'Base16 / Monokai', value: 'base16/monokai' },
{ label: 'Base16 / Nebula', value: 'base16/nebula' },
{ label: 'Base16 / Nord', value: 'base16/nord' },
{ label: 'Base16 / Nova', value: 'base16/nova' },
{ label: 'Base16 / Ocean', value: 'base16/ocean' },
{ label: 'Base16 / Oceanicnext', value: 'base16/oceanicnext' },
{ label: 'Base16 / One Light', value: 'base16/one-light' },
{ label: 'Base16 / Onedark', value: 'base16/onedark' },
{ label: 'Base16 / Outrun Dark', value: 'base16/outrun-dark' },
{ label: 'Base16 / Papercolor Dark', value: 'base16/papercolor-dark' },
{ label: 'Base16 / Papercolor Light', value: 'base16/papercolor-light' },
{ label: 'Base16 / Paraiso', value: 'base16/paraiso' },
{ label: 'Base16 / Pasque', value: 'base16/pasque' },
{ label: 'Base16 / Phd', value: 'base16/phd' },
{ label: 'Base16 / Pico', value: 'base16/pico' },
{ label: 'Base16 / Pop', value: 'base16/pop' },
{ label: 'Base16 / Porple', value: 'base16/porple' },
{ label: 'Base16 / Qualia', value: 'base16/qualia' },
{ label: 'Base16 / Railscasts', value: 'base16/railscasts' },
{ label: 'Base16 / Rebecca', value: 'base16/rebecca' },
{ label: 'Base16 / Ros Pine', value: 'base16/ros-pine' },
{ label: 'Base16 / Ros Pine Dawn', value: 'base16/ros-pine-dawn' },
{ label: 'Base16 / Ros Pine Moon', value: 'base16/ros-pine-moon' },
{ label: 'Base16 / Sagelight', value: 'base16/sagelight' },
{ label: 'Base16 / Sandcastle', value: 'base16/sandcastle' },
{ label: 'Base16 / Seti Ui', value: 'base16/seti-ui' },
{ label: 'Base16 / Shapeshifter', value: 'base16/shapeshifter' },
{ label: 'Base16 / Silk Dark', value: 'base16/silk-dark' },
{ label: 'Base16 / Silk Light', value: 'base16/silk-light' },
{ label: 'Base16 / Snazzy', value: 'base16/snazzy' },
{ label: 'Base16 / Solar Flare', value: 'base16/solar-flare' },
{ label: 'Base16 / Solar Flare Light', value: 'base16/solar-flare-light' },
{ label: 'Base16 / Solarized Dark', value: 'base16/solarized-dark' },
{ label: 'Base16 / Solarized Light', value: 'base16/solarized-light' },
{ label: 'Base16 / Spacemacs', value: 'base16/spacemacs' },
{ label: 'Base16 / Summercamp', value: 'base16/summercamp' },
{ label: 'Base16 / Summerfruit Dark', value: 'base16/summerfruit-dark' },
{ label: 'Base16 / Summerfruit Light', value: 'base16/summerfruit-light' },
{ label: 'Base16 / Synth Midnight Terminal Dark', value: 'base16/synth-midnight-terminal-dark' },
{ label: 'Base16 / Synth Midnight Terminal Light', value: 'base16/synth-midnight-terminal-light' },
{ label: 'Base16 / Tango', value: 'base16/tango' },
{ label: 'Base16 / Tender', value: 'base16/tender' },
{ label: 'Base16 / Tomorrow', value: 'base16/tomorrow' },
{ label: 'Base16 / Tomorrow Night', value: 'base16/tomorrow-night' },
{ label: 'Base16 / Twilight', value: 'base16/twilight' },
{ label: 'Base16 / Unikitty Dark', value: 'base16/unikitty-dark' },
{ label: 'Base16 / Unikitty Light', value: 'base16/unikitty-light' },
{ label: 'Base16 / Vulcan', value: 'base16/vulcan' },
{ label: 'Base16 / Windows 10', value: 'base16/windows-10' },
{ label: 'Base16 / Windows 10 Light', value: 'base16/windows-10-light' },
{ label: 'Base16 / Windows 95', value: 'base16/windows-95' },
{ label: 'Base16 / Windows 95 Light', value: 'base16/windows-95-light' },
{ label: 'Base16 / Windows High Contrast', value: 'base16/windows-high-contrast' },
{ label: 'Base16 / Windows High Contrast Light', value: 'base16/windows-high-contrast-light' },
{ label: 'Base16 / Windows Nt', value: 'base16/windows-nt' },
{ label: 'Base16 / Windows Nt Light', value: 'base16/windows-nt-light' },
{ label: 'Base16 / Woodland', value: 'base16/woodland' },
{ label: 'Base16 / Xcode Dusk', value: 'base16/xcode-dusk' },
{ label: 'Base16 / Zenburn', value: 'base16/zenburn' },
{ label: 'Brown Paper', value: 'brown-paper' },
{ label: 'Codepen Embed', value: 'codepen-embed' },
{ label: 'Color Brewer', value: 'color-brewer' },
{ label: 'Dark', value: 'dark' },
{ label: 'Devibeans', value: 'devibeans' },
{ label: 'Docco', value: 'docco' },
{ label: 'Far', value: 'far' },
{ label: 'Felipec', value: 'felipec' },
{ label: 'Foundation', value: 'foundation' },
{ label: 'Github', value: 'github' },
{ label: 'Github Dark', value: 'github-dark' },
{ label: 'Github Dark Dimmed', value: 'github-dark-dimmed' },
{ label: 'Gml', value: 'gml' },
{ label: 'Googlecode', value: 'googlecode' },
{ label: 'Gradient Dark', value: 'gradient-dark' },
{ label: 'Gradient Light', value: 'gradient-light' },
{ label: 'Grayscale', value: 'grayscale' },
{ label: 'Hybrid', value: 'hybrid' },
{ label: 'Idea', value: 'idea' },
{ label: 'Intellij Light', value: 'intellij-light' },
{ label: 'Ir Black', value: 'ir-black' },
{ label: 'Isbl Editor Dark', value: 'isbl-editor-dark' },
{ label: 'Isbl Editor Light', value: 'isbl-editor-light' },
{ label: 'Kimbie Dark', value: 'kimbie-dark' },
{ label: 'Kimbie Light', value: 'kimbie-light' },
{ label: 'Lightfair', value: 'lightfair' },
{ label: 'Lioshi', value: 'lioshi' },
{ label: 'Magula', value: 'magula' },
{ label: 'Mono Blue', value: 'mono-blue' },
{ label: 'Monokai', value: 'monokai' },
{ label: 'Monokai Sublime', value: 'monokai-sublime' },
{ label: 'Night Owl', value: 'night-owl' },
{ label: 'Nnfx Dark', value: 'nnfx-dark' },
{ label: 'Nnfx Light', value: 'nnfx-light' },
{ label: 'Nord', value: 'nord' },
{ label: 'Obsidian', value: 'obsidian' },
{ label: 'Panda Syntax Dark', value: 'panda-syntax-dark' },
{ label: 'Panda Syntax Light', value: 'panda-syntax-light' },
{ label: 'Paraiso Dark', value: 'paraiso-dark' },
{ label: 'Paraiso Light', value: 'paraiso-light' },
{ label: 'Pojoaque', value: 'pojoaque' },
{ label: 'Purebasic', value: 'purebasic' },
{ label: 'Qtcreator Dark', value: 'qtcreator-dark' },
{ label: 'Qtcreator Light', value: 'qtcreator-light' },
{ label: 'Rainbow', value: 'rainbow' },
{ label: 'Routeros', value: 'routeros' },
{ label: 'School Book', value: 'school-book' },
{ label: 'Shades Of Purple', value: 'shades-of-purple' },
{ label: 'Srcery', value: 'srcery' },
{ label: 'Stackoverflow Dark', value: 'stackoverflow-dark' },
{ label: 'Stackoverflow Light', value: 'stackoverflow-light' },
{ label: 'Sunburst', value: 'sunburst' },
{ label: 'Tokyo Night Dark', value: 'tokyo-night-dark' },
{ label: 'Tokyo Night Light', value: 'tokyo-night-light' },
{ label: 'Tomorrow Night Blue', value: 'tomorrow-night-blue' },
{ label: 'Tomorrow Night Bright', value: 'tomorrow-night-bright' },
{ label: 'Vs', value: 'vs' },
{ label: 'Vs 2015', value: 'vs2015' },
{ label: 'Xcode', value: 'xcode' },
{ label: 'Xt 256', value: 'xt256' }
]
// WATCHERS
watch(() => adminStore.currentSiteId, (newValue) => {
@ -372,6 +661,10 @@ function resetFonts () {
state.config.contentFont = 'roboto'
}
function resetCodeBlocks () {
state.config.codeBlocksTheme = 'github-dark'
}
async function load () {
state.loading++
$q.loading.show()
@ -386,6 +679,7 @@ async function load () {
) {
theme {
baseFont
codeBlocksTheme
contentFont
colorPrimary
colorSecondary
@ -429,6 +723,7 @@ async function save () {
try {
const patchTheme = {
dark: state.config.dark,
codeBlocksTheme: state.config.codeBlocksTheme,
colorPrimary: state.config.colorPrimary,
colorSecondary: state.config.colorSecondary,
colorAccent: state.config.colorAccent,

@ -29,7 +29,9 @@ q-page.column
.text-caption.text-grey-6 Last modified on #[strong {{lastModified}}]
page-header
.page-container.row.no-wrap.items-stretch(style='flex: 1 1 100%;')
.col(style='order: 1;')
.col(
:style='siteStore.theme.tocPosition === `left` ? `order: 2;` : `order: 1;`'
)
q-no-ssr(
v-if='editorStore.isActive'
)
@ -84,7 +86,7 @@ q-page.column
.text-caption {{rel.caption}}
.page-sidebar(
v-if='showSidebar'
style='order: 2;'
:style='siteStore.theme.tocPosition === `left` ? `order: 1;` : `order: 2;`'
)
template(v-if='pageStore.showToc')
//- TOC
@ -242,7 +244,7 @@ const barStyle = {
// COMPUTED
const showSidebar = computed(() => {
return pageStore.showSidebar && siteStore.showSidebar && !editorStore.isActive
return pageStore.showSidebar && siteStore.showSidebar && siteStore.theme.tocPosition !== 'off' && !editorStore.isActive
})
const relationsLeft = computed(() => {
return pageStore.relations ? pageStore.relations.filter(r => r.position === 'left') : []

@ -55,7 +55,7 @@ export class MarkdownRenderer {
const highlighted = lang ? hljs.highlight(str, { language: lang, ignoreIllegals: true }) : { value: str }
const lineCount = highlighted.value.match(/\n/g).length
const lineNums = lineCount > 1 ? `<span aria-hidden="true" class="line-numbers-rows">${times(lineCount, n => '<span></span>').join('')}</span>` : ''
return `<pre class="codeblock ${lineCount > 1 && 'line-numbers'}"><code class="language-${lang}">${highlighted.value}${lineNums}</code></pre>`
return `<pre class="codeblock hljs ${lineCount > 1 && 'line-numbers'}"><code class="language-${lang}">${highlighted.value}${lineNums}</code></pre>`
}
}
})

@ -1,3 +1,4 @@
import { usePageStore } from 'src/stores/page'
const routes = [
{
@ -15,6 +16,19 @@ const routes = [
{ path: '', component: () => import('pages/Login.vue') }
]
},
{
path: '/a/:alias',
component: () => import('../layouts/MainLayout.vue'),
beforeEnter: async (to, from) => {
const pageStore = usePageStore()
try {
const pathPath = await pageStore.pageAlias(to.params.alias)
return `/${pathPath}`
} catch (err) {
return '/_error/notfound'
}
}
},
{
path: '/_profile',
component: () => import('layouts/ProfileLayout.vue'),

@ -8,6 +8,7 @@ import { useEditorStore } from './editor'
const pagePropsFragment = gql`
fragment PageRead on Page {
alias
allowComments
allowContributions
allowRatings
@ -112,6 +113,7 @@ const gqlQueries = {
const gqlMutations = {
createPage: gql`
mutation createPage (
$alias: String
$allowComments: Boolean
$allowContributions: Boolean
$allowRatings: Boolean
@ -138,6 +140,7 @@ const gqlMutations = {
$tocDepth: PageTocDepthInput
) {
createPage (
alias: $alias
allowComments: $allowComments
allowContributions: $allowContributions
allowRatings: $allowRatings
@ -178,6 +181,7 @@ const gqlMutations = {
export const usePageStore = defineStore('page', {
state: () => ({
alias: '',
allowComments: false,
allowContributions: true,
allowRatings: true,
@ -272,6 +276,40 @@ export const usePageStore = defineStore('page', {
throw err
}
},
/**
* PAGE - GET PATH FROM ALIAS
*/
async pageAlias (alias) {
const siteStore = useSiteStore()
try {
const resp = await APOLLO_CLIENT.query({
query: gql`
query fetchPathFromAlias (
$siteId: UUID!
$alias: String!
) {
pathFromAlias (
siteId: $siteId
alias: $alias
) {
id
path
}
}
`,
variables: { siteId: siteStore.id, alias },
fetchPolicy: 'cache-first'
})
const pagePath = cloneDeep(resp?.data?.pathFromAlias)
if (!pagePath?.id) {
throw new Error('ERR_PAGE_NOT_FOUND')
}
return pagePath.path
} catch (err) {
console.warn(err)
throw err
}
},
/**
* PAGE - CREATE
*/
@ -305,6 +343,7 @@ export const usePageStore = defineStore('page', {
title: title ?? '',
description: description ?? '',
icon: 'las la-file-alt',
alias: '',
publishState: 'published',
relations: [],
tags: [],
@ -345,6 +384,7 @@ export const usePageStore = defineStore('page', {
mutation: gqlMutations.createPage,
variables: {
...pick(this, [
'alias',
'allowComments',
'allowContributions',
'allowRatings',
@ -415,6 +455,7 @@ export const usePageStore = defineStore('page', {
id: this.id,
patch: {
...pick(this, [
'alias',
'allowComments',
'allowContributions',
'allowRatings',

@ -47,6 +47,7 @@ export const useSiteStore = defineStore('site', {
colorAccent: '#f03a47',
colorHeader: '#000',
colorSidebar: '#1976D2',
codeBlocksTheme: '',
sidebarPosition: 'left',
tocPosition: 'right',
showSharingMenu: true,
@ -69,7 +70,8 @@ export const useSiteStore = defineStore('site', {
docsBase: 'https://next.js.wiki/docs'
}),
getters: {
overlayIsShown: (state) => Boolean(state.overlay)
overlayIsShown: (state) => Boolean(state.overlay),
sideNavIsDisabled: (state) => Boolean(state.theme.sidebarPosition === 'off')
},
actions: {
openFileManager (opts) {
@ -121,6 +123,7 @@ export const useSiteStore = defineStore('site', {
colorAccent
colorHeader
colorSidebar
codeBlocksTheme
sidebarPosition
tocPosition
showSharingMenu
@ -137,27 +140,29 @@ export const useSiteStore = defineStore('site', {
})
const siteInfo = resp.data.siteByHostname
if (siteInfo) {
this.id = clone(siteInfo.id)
this.hostname = clone(siteInfo.hostname)
this.title = clone(siteInfo.title)
this.description = clone(siteInfo.description)
this.logoText = clone(siteInfo.logoText)
this.company = clone(siteInfo.company)
this.contentLicense = clone(siteInfo.contentLicense)
this.footerExtra = clone(siteInfo.footerExtra)
this.features = {
...this.features,
...clone(siteInfo.features)
}
this.editors = {
asciidoc: clone(siteInfo.editors.asciidoc.isActive),
markdown: clone(siteInfo.editors.markdown.isActive),
wysiwyg: clone(siteInfo.editors.wysiwyg.isActive)
}
this.theme = {
...this.theme,
...clone(siteInfo.theme)
}
this.$patch({
id: clone(siteInfo.id),
hostname: clone(siteInfo.hostname),
title: clone(siteInfo.title),
description: clone(siteInfo.description),
logoText: clone(siteInfo.logoText),
company: clone(siteInfo.company),
contentLicense: clone(siteInfo.contentLicense),
footerExtra: clone(siteInfo.footerExtra),
features: {
...this.features,
...clone(siteInfo.features)
},
editors: {
asciidoc: clone(siteInfo.editors.asciidoc.isActive),
markdown: clone(siteInfo.editors.markdown.isActive),
wysiwyg: clone(siteInfo.editors.wysiwyg.isActive)
},
theme: {
...this.theme,
...clone(siteInfo.theme)
}
})
} else {
throw new Error('Invalid Site')
}

Loading…
Cancel
Save