@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Authentication API Routes
|
||||||
|
*/
|
||||||
|
async function routes (app, options) {
|
||||||
|
app.get('/sites/:siteId/auth/strategies', {
|
||||||
|
schema: {
|
||||||
|
summary: 'List all site authentication strategies',
|
||||||
|
tags: ['Authentication'],
|
||||||
|
params: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
siteId: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
querystring: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
visibleOnly: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, async (req, reply) => {
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/auth/login', {
|
||||||
|
schema: {
|
||||||
|
summary: 'Login',
|
||||||
|
tags: ['Authentication'],
|
||||||
|
body: {
|
||||||
|
type: 'object',
|
||||||
|
required: ['path'],
|
||||||
|
properties: {
|
||||||
|
path: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 255
|
||||||
|
}
|
||||||
|
},
|
||||||
|
examples: [
|
||||||
|
{
|
||||||
|
path: 'foo/bar'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, async (req, reply) => {
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default routes
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Locales API Routes
|
||||||
|
*/
|
||||||
|
async function routes (app, options) {
|
||||||
|
app.get('/', {
|
||||||
|
schema: {
|
||||||
|
summary: 'List all locales',
|
||||||
|
tags: ['Locales']
|
||||||
|
}
|
||||||
|
}, async (req, reply) => {
|
||||||
|
return WIKI.models.locales.getLocales()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/:code/strings', {
|
||||||
|
schema: {
|
||||||
|
summary: 'Get locale strings',
|
||||||
|
tags: ['Locales']
|
||||||
|
}
|
||||||
|
}, async (req, reply) => {
|
||||||
|
return WIKI.models.locales.getStrings(req.params.code)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default routes
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
* Pages API Routes
|
||||||
|
*/
|
||||||
|
async function routes (app, options) {
|
||||||
|
app.get('/sites/:siteId/pages', {
|
||||||
|
schema: {
|
||||||
|
summary: 'List all pages',
|
||||||
|
tags: ['Pages'],
|
||||||
|
params: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
siteId: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, async (req, reply) => {
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/sites/:siteId/pages/:pageIdOrHash', {
|
||||||
|
schema: {
|
||||||
|
summary: 'List all pages',
|
||||||
|
tags: ['Pages'],
|
||||||
|
params: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
siteId: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid'
|
||||||
|
},
|
||||||
|
pageIdOrHash: {
|
||||||
|
type: 'string',
|
||||||
|
oneOf: [
|
||||||
|
{ format: 'uuid' },
|
||||||
|
{ pattern: '^[a-f0-9]+$' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
querystring: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
withContent: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, async (req, reply) => {
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/sites/:siteId/pages/userPermissions', {
|
||||||
|
schema: {
|
||||||
|
summary: 'Get page user permissions',
|
||||||
|
tags: ['Pages'],
|
||||||
|
params: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
siteId: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
type: 'object',
|
||||||
|
required: ['path'],
|
||||||
|
properties: {
|
||||||
|
path: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 255
|
||||||
|
}
|
||||||
|
},
|
||||||
|
examples: [
|
||||||
|
{
|
||||||
|
path: 'foo/bar'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, async (req, reply) => {
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default routes
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
import { defineRelations } from 'drizzle-orm'
|
||||||
|
import * as schema from './schema.mjs'
|
||||||
|
|
||||||
|
export const relations = defineRelations(schema,
|
||||||
|
r => ({
|
||||||
|
users: {
|
||||||
|
groups: r.many.groups({
|
||||||
|
from: r.users.id.through(r.userGroups.userId),
|
||||||
|
to: r.groups.id.through(r.userGroups.groupId)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
groups: {
|
||||||
|
members: r.many.users()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
const localazyMetadata = {
|
||||||
|
projectUrl: "https://localazy.com/p/wiki",
|
||||||
|
baseLocale: "en",
|
||||||
|
languages: [
|
||||||
|
{
|
||||||
|
language: "de",
|
||||||
|
region: "",
|
||||||
|
script: "",
|
||||||
|
isRtl: false,
|
||||||
|
name: "German",
|
||||||
|
localizedName: "Deutsch",
|
||||||
|
pluralType: (n) => { return (n===1) ? "one" : "other"; }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: "en",
|
||||||
|
region: "",
|
||||||
|
script: "",
|
||||||
|
isRtl: false,
|
||||||
|
name: "English",
|
||||||
|
localizedName: "English",
|
||||||
|
pluralType: (n) => { return (n===1) ? "one" : "other"; }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: "fr",
|
||||||
|
region: "",
|
||||||
|
script: "",
|
||||||
|
isRtl: false,
|
||||||
|
name: "French",
|
||||||
|
localizedName: "Français",
|
||||||
|
pluralType: (n) => { return (n===0 || n===1) ? "one" : "other"; }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: "pt",
|
||||||
|
region: "BR",
|
||||||
|
script: "",
|
||||||
|
isRtl: false,
|
||||||
|
name: "Brazilian Portuguese",
|
||||||
|
localizedName: "Português (Brasil)",
|
||||||
|
pluralType: (n) => { return (n>=0 && n<=1) ? "one" : "other"; }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: "ru",
|
||||||
|
region: "",
|
||||||
|
script: "",
|
||||||
|
isRtl: false,
|
||||||
|
name: "Russian",
|
||||||
|
localizedName: "Русский",
|
||||||
|
pluralType: (n) => { return ((n%10===1) && (n%100!==11)) ? "one" : ((n%10>=2 && n%10<=4) && ((n%100<12 || n%100>14))) ? "few" : "many"; }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: "zh",
|
||||||
|
region: "",
|
||||||
|
script: "Hans",
|
||||||
|
isRtl: false,
|
||||||
|
name: "Simplified Chinese",
|
||||||
|
localizedName: "简体中文",
|
||||||
|
pluralType: (n) => { return "other"; }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
cdnHash: "54b977214afbffe2ffeb07d0ccb03558e75e4408",
|
||||||
|
file: "file.json",
|
||||||
|
path: "",
|
||||||
|
library: "",
|
||||||
|
module: "",
|
||||||
|
buildType: "",
|
||||||
|
productFlavors: [],
|
||||||
|
cdnFiles: {
|
||||||
|
"de#": "https://delivery.localazy.com/_a7797965569058078203416ae5aa/_e0/54b977214afbffe2ffeb07d0ccb03558e75e4408/de/file.json",
|
||||||
|
"en#": "https://delivery.localazy.com/_a7797965569058078203416ae5aa/_e0/54b977214afbffe2ffeb07d0ccb03558e75e4408/en/file.json",
|
||||||
|
"fr#": "https://delivery.localazy.com/_a7797965569058078203416ae5aa/_e0/54b977214afbffe2ffeb07d0ccb03558e75e4408/fr/file.json",
|
||||||
|
"pt_BR#": "https://delivery.localazy.com/_a7797965569058078203416ae5aa/_e0/54b977214afbffe2ffeb07d0ccb03558e75e4408/pt-BR/file.json",
|
||||||
|
"ru#": "https://delivery.localazy.com/_a7797965569058078203416ae5aa/_e0/54b977214afbffe2ffeb07d0ccb03558e75e4408/ru/file.json",
|
||||||
|
"zh#Hans": "https://delivery.localazy.com/_a7797965569058078203416ae5aa/_e0/54b977214afbffe2ffeb07d0ccb03558e75e4408/zh-Hans/file.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default localazyMetadata;
|
||||||
@ -0,0 +1,108 @@
|
|||||||
|
import { find } from 'lodash-es'
|
||||||
|
import { stat, readFile } from 'node:fs/promises'
|
||||||
|
import path from 'node:path'
|
||||||
|
import { DateTime } from 'luxon'
|
||||||
|
import { locales as localesTable } from '../db/schema.mjs'
|
||||||
|
import { eq, sql } from 'drizzle-orm'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locales model
|
||||||
|
*/
|
||||||
|
class Locales {
|
||||||
|
async refreshFromDisk ({ force = false } = {}) {
|
||||||
|
try {
|
||||||
|
const localesMeta = (await import('../locales/metadata.mjs')).default
|
||||||
|
WIKI.logger.info(`Found ${localesMeta.languages.length} locales: [ OK ]`)
|
||||||
|
|
||||||
|
const dbLocales = await WIKI.db.select({
|
||||||
|
code: localesTable.code,
|
||||||
|
updatedAt: localesTable.updatedAt
|
||||||
|
}).from(localesTable).orderBy(localesTable.code)
|
||||||
|
|
||||||
|
let localFilesSkipped = 0
|
||||||
|
for (const lang of localesMeta.languages) {
|
||||||
|
// -> Build filename
|
||||||
|
const langFilenameParts = [lang.language]
|
||||||
|
if (lang.region) {
|
||||||
|
langFilenameParts.push(lang.region)
|
||||||
|
}
|
||||||
|
if (lang.script) {
|
||||||
|
langFilenameParts.push(lang.script)
|
||||||
|
}
|
||||||
|
const langFilename = langFilenameParts.join('-')
|
||||||
|
|
||||||
|
// -> Get DB version
|
||||||
|
const dbLang = find(dbLocales, ['code', langFilename])
|
||||||
|
|
||||||
|
// -> Get File version
|
||||||
|
const flPath = path.join(WIKI.SERVERPATH, `locales/${langFilename}.json`)
|
||||||
|
try {
|
||||||
|
const flStat = await stat(flPath)
|
||||||
|
const flUpdatedAt = DateTime.fromJSDate(flStat.mtime)
|
||||||
|
|
||||||
|
// -> Load strings
|
||||||
|
if (!dbLang || DateTime.fromJSDate(dbLang.updatedAt) < flUpdatedAt || force) {
|
||||||
|
WIKI.logger.info(`Loading locale ${langFilename} into DB...`)
|
||||||
|
const flStrings = JSON.parse(await readFile(flPath, 'utf8'))
|
||||||
|
await WIKI.db.insert(localesTable).values({
|
||||||
|
code: langFilename,
|
||||||
|
name: lang.name,
|
||||||
|
nativeName: lang.localizedName,
|
||||||
|
language: lang.language,
|
||||||
|
region: lang.region,
|
||||||
|
script: lang.script,
|
||||||
|
isRTL: lang.isRtl,
|
||||||
|
strings: flStrings
|
||||||
|
}).onConflictDoUpdate({ target: localesTable.code, set: { strings: flStrings, updatedAt: sql`now()` } })
|
||||||
|
WIKI.logger.info(`Locale ${langFilename} loaded successfully. [ OK ]`)
|
||||||
|
} else {
|
||||||
|
WIKI.logger.info(`Locale ${langFilename} is newer in the DB. Skipping disk version. [ OK ]`)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
localFilesSkipped++
|
||||||
|
WIKI.logger.warn(`Locale ${langFilename} not found on disk. Missing strings file. [ SKIPPED ]`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (localFilesSkipped > 0) {
|
||||||
|
WIKI.logger.warn(`${localFilesSkipped} locales were defined in the metadata file but not found on disk. [ SKIPPED ]`)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
WIKI.logger.warn('Failed to load locales from disk: [ FAILED ]')
|
||||||
|
WIKI.logger.warn(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLocales ({ cache = true } = {}) {
|
||||||
|
if (!WIKI.cache.has('locales') || !cache) {
|
||||||
|
const locales = await WIKI.db.select({
|
||||||
|
code: localesTable.code,
|
||||||
|
isRTL: localesTable.isRTL,
|
||||||
|
language: localesTable.language,
|
||||||
|
name: localesTable.name,
|
||||||
|
nativeName: localesTable.nativeName,
|
||||||
|
createdAt: localesTable.createdAt,
|
||||||
|
updatedAt: localesTable.updatedAt,
|
||||||
|
completeness: localesTable.completeness
|
||||||
|
}).from(localesTable).orderBy(localesTable.code)
|
||||||
|
WIKI.cache.set('locales', locales)
|
||||||
|
for (const locale of locales) {
|
||||||
|
WIKI.cache.set(`locale:${locale.code}`, locale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return WIKI.cache.get('locales')
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStrings (locale) {
|
||||||
|
const results = await WIKI.db.select({ strings: localesTable.strings }).from(localesTable).where(eq(localesTable.code, locale)).limit(1)
|
||||||
|
return results.length === 1 ? results[0].strings : []
|
||||||
|
}
|
||||||
|
|
||||||
|
async reloadCache () {
|
||||||
|
WIKI.logger.info('Reloading locales cache...')
|
||||||
|
const locales = await WIKI.models.locales.getLocales({ cache: false })
|
||||||
|
WIKI.logger.info(`Loaded ${locales.length} locales into cache [ OK ]`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const locales = new Locales()
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
.DS_Store
|
||||||
|
.thumbs.db
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Quasar core related directories
|
||||||
|
.quasar
|
||||||
|
/dist
|
||||||
|
/quasar.config.*.temporary.compiled*
|
||||||
|
|
||||||
|
# local .env files
|
||||||
|
.env.local*
|
||||||
|
|
||||||
|
# Cordova related directories and files
|
||||||
|
/src-cordova/node_modules
|
||||||
|
/src-cordova/platforms
|
||||||
|
/src-cordova/plugins
|
||||||
|
/src-cordova/www
|
||||||
|
|
||||||
|
# Capacitor related directories and files
|
||||||
|
/src-capacitor/www
|
||||||
|
/src-capacitor/node_modules
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
|
||||||
|
# Yarn
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/sdks
|
||||||
|
!.yarn/versions
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
audit = false
|
||||||
|
fund = false
|
||||||
|
save-exact = true
|
||||||
|
save-prefix = ""
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"editorconfig.editorconfig",
|
||||||
|
"johnsoncodehk.volar",
|
||||||
|
"wayou.vscode-todo-highlight"
|
||||||
|
],
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
"octref.vetur",
|
||||||
|
"hookyqr.beautify",
|
||||||
|
"dbaeumer.jshint",
|
||||||
|
"ms-vscode.vscode-typescript-tslint-plugin"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"editor.bracketPairColorization.enabled": true,
|
||||||
|
"editor.guides.bracketPairs": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
||||||
|
"editor.codeActionsOnSave": [
|
||||||
|
"source.fixAll.eslint"
|
||||||
|
],
|
||||||
|
"eslint.validate": [
|
||||||
|
"javascript",
|
||||||
|
"javascriptreact",
|
||||||
|
"typescript",
|
||||||
|
"vue"
|
||||||
|
],
|
||||||
|
"i18n-ally.localesPaths": "src/i18n/locales"
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
import js from '@eslint/js'
|
||||||
|
import neostandard from 'neostandard'
|
||||||
|
import pluginVue from 'eslint-plugin-vue'
|
||||||
|
import pluginVuePug from 'eslint-plugin-vue-pug'
|
||||||
|
import vueParser from 'vue-eslint-parser'
|
||||||
|
import { FlatCompat } from '@eslint/eslintrc'
|
||||||
|
|
||||||
|
const compat = new FlatCompat()
|
||||||
|
|
||||||
|
export default [
|
||||||
|
js.configs.recommended,
|
||||||
|
...pluginVue.configs['flat/essential'],
|
||||||
|
...pluginVuePug.configs['flat/recommended'],
|
||||||
|
...neostandard(),
|
||||||
|
{
|
||||||
|
ignores: [
|
||||||
|
'/dist',
|
||||||
|
'/.quasar',
|
||||||
|
'/node_modules'
|
||||||
|
],
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 'latest',
|
||||||
|
sourceType: 'module',
|
||||||
|
parser: vueParser,
|
||||||
|
globals: {
|
||||||
|
__statics: 'readonly',
|
||||||
|
__QUASAR_SSR__: 'readonly',
|
||||||
|
__QUASAR_SSR_SERVER__: 'readonly',
|
||||||
|
__QUASAR_SSR_CLIENT__: 'readonly',
|
||||||
|
__QUASAR_SSR_PWA__: 'readonly',
|
||||||
|
process: 'readonly',
|
||||||
|
Capacitor: 'readonly',
|
||||||
|
chrome: 'readonly',
|
||||||
|
APOLLO_CLIENT: 'readonly',
|
||||||
|
EVENT_BUS: 'readonly'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// allow async-await
|
||||||
|
'generator-star-spacing': 'off',
|
||||||
|
// allow paren-less arrow functions
|
||||||
|
'arrow-parens': 'off',
|
||||||
|
'one-var': 'off',
|
||||||
|
'no-void': 'off',
|
||||||
|
'multiline-ternary': 'off',
|
||||||
|
|
||||||
|
'import/first': 'off',
|
||||||
|
'import/named': 'error',
|
||||||
|
'import/namespace': 'error',
|
||||||
|
'import/default': 'error',
|
||||||
|
'import/export': 'error',
|
||||||
|
'import/extensions': 'off',
|
||||||
|
'import/no-unresolved': 'off',
|
||||||
|
'import/no-extraneous-dependencies': 'off',
|
||||||
|
|
||||||
|
'prefer-promise-reject-errors': 'off',
|
||||||
|
|
||||||
|
'no-unused-vars': 'off',
|
||||||
|
'vue/multi-word-component-names': 'off',
|
||||||
|
|
||||||
|
// allow debugger during development only
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||||
|
|
||||||
|
// disable bogus rules
|
||||||
|
'vue/valid-template-root': 'off',
|
||||||
|
'vue/no-parsing-error': 'off',
|
||||||
|
'vue-pug/no-parsing-error': 'off',
|
||||||
|
'vue/valid-v-for': 'off',
|
||||||
|
'vue/html-quotes': ['warn', 'single'],
|
||||||
|
'vue/max-attributes-per-line': 'off'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="/_site/favicon" />
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<meta name="msapplication-tap-highlight" content="no">
|
||||||
|
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
|
||||||
|
<title>Wiki.js</title>
|
||||||
|
<!--preload-links-->
|
||||||
|
<link href="/_assets/fonts/roboto/roboto.css" rel="stylesheet" />
|
||||||
|
<style type="text/css">
|
||||||
|
@keyframes initspinner {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.init-loading {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(255,255,255,.75);
|
||||||
|
z-index: 2000000000;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.body--dark .init-loading {
|
||||||
|
background-color: rgba(0,0,0,.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
.init-loading:before {
|
||||||
|
content: '';
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
margin-top: -25px;
|
||||||
|
margin-left: -25px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top: 2px solid #1976D2;
|
||||||
|
border-right: 2px solid transparent;
|
||||||
|
animation: initspinner .6s linear infinite;
|
||||||
|
z-index: 2000000000;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<noscript>
|
||||||
|
<style type="text/css">
|
||||||
|
.init-loading {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-drawer-container {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll.relative-position {
|
||||||
|
position: static !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll.relative-position > .absolute {
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</noscript>
|
||||||
|
</head>
|
||||||
|
<body class="wiki-root">
|
||||||
|
<div class="init-loading"></div>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"jsx": "preserve",
|
||||||
|
"paths": {
|
||||||
|
"src/*": [
|
||||||
|
"src/*"
|
||||||
|
],
|
||||||
|
"app/*": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"components/*": [
|
||||||
|
"src/components/*"
|
||||||
|
],
|
||||||
|
"layouts/*": [
|
||||||
|
"src/layouts/*"
|
||||||
|
],
|
||||||
|
"pages/*": [
|
||||||
|
"src/pages/*"
|
||||||
|
],
|
||||||
|
"assets/*": [
|
||||||
|
"src/assets/*"
|
||||||
|
],
|
||||||
|
"boot/*": [
|
||||||
|
"src/boot/*"
|
||||||
|
],
|
||||||
|
"stores/*": [
|
||||||
|
"src/stores/*"
|
||||||
|
],
|
||||||
|
"vue$": [
|
||||||
|
"node_modules/vue/dist/vue.runtime.esm-bundler.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
".quasar",
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"vueCompilerOptions": {
|
||||||
|
"target": 3,
|
||||||
|
"plugins": [
|
||||||
|
"@vue/language-plugin-pug"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
{
|
||||||
|
"name": "wiki-ux",
|
||||||
|
"version": "3.0.0",
|
||||||
|
"description": "The most powerful and extensible open source Wiki software",
|
||||||
|
"productName": "Wiki.js",
|
||||||
|
"author": "Nicolas Giard <nick@requarks.io>",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite --force",
|
||||||
|
"build": "NODE_OPTIONS=--max-old-space-size=8192 vite build --emptyOutDir",
|
||||||
|
"ncu": "ncu -i",
|
||||||
|
"ncu-u": "ncu -u"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "1.5.1",
|
||||||
|
"@mdi/font": "7.4.47",
|
||||||
|
"@quasar/extras": "1.17.0",
|
||||||
|
"@simplewebauthn/browser": "13.2.2",
|
||||||
|
"@tanstack/vue-query": "5.92.9",
|
||||||
|
"@xterm/xterm": "6.0.0",
|
||||||
|
"browser-fs-access": "0.38.0",
|
||||||
|
"clipboard": "2.0.11",
|
||||||
|
"codemirror": "5.65.11",
|
||||||
|
"codemirror-asciidoc": "1.0.4",
|
||||||
|
"dependency-graph": "1.0.0",
|
||||||
|
"filesize": "11.0.13",
|
||||||
|
"filesize-parser": "1.5.1",
|
||||||
|
"fuse.js": "7.1.0",
|
||||||
|
"highlight.js": "11.11.1",
|
||||||
|
"js-cookie": "3.0.5",
|
||||||
|
"jwt-decode": "4.0.0",
|
||||||
|
"katex": "0.16.33",
|
||||||
|
"ky": "1.14.3",
|
||||||
|
"lodash-es": "4.17.23",
|
||||||
|
"lowlight": "3.3.0",
|
||||||
|
"luxon": "3.7.2",
|
||||||
|
"markdown-it": "14.1.1",
|
||||||
|
"markdown-it-abbr": "2.0.0",
|
||||||
|
"markdown-it-attrs": "4.3.1",
|
||||||
|
"markdown-it-decorate": "1.2.2",
|
||||||
|
"markdown-it-emoji": "3.0.0",
|
||||||
|
"markdown-it-expand-tabs": "1.0.13",
|
||||||
|
"markdown-it-footnote": "4.0.0",
|
||||||
|
"markdown-it-imsize": "2.0.1",
|
||||||
|
"markdown-it-mark": "4.0.0",
|
||||||
|
"markdown-it-mdc": "0.2.12",
|
||||||
|
"markdown-it-multimd-table": "4.2.3",
|
||||||
|
"markdown-it-sub": "2.0.0",
|
||||||
|
"markdown-it-sup": "2.0.0",
|
||||||
|
"markdown-it-task-lists": "2.1.1",
|
||||||
|
"mitt": "3.0.1",
|
||||||
|
"monaco-editor": "0.55.1",
|
||||||
|
"pako": "2.1.0",
|
||||||
|
"pinia": "3.0.4",
|
||||||
|
"prosemirror-commands": "1.7.1",
|
||||||
|
"prosemirror-history": "1.5.0",
|
||||||
|
"prosemirror-keymap": "1.2.3",
|
||||||
|
"prosemirror-model": "1.25.4",
|
||||||
|
"prosemirror-schema-list": "1.5.1",
|
||||||
|
"prosemirror-state": "1.4.4",
|
||||||
|
"prosemirror-transform": "1.11.0",
|
||||||
|
"prosemirror-view": "1.41.6",
|
||||||
|
"pug": "3.0.3",
|
||||||
|
"quasar": "2.18.6",
|
||||||
|
"slugify": "1.6.6",
|
||||||
|
"socket.io-client": "4.8.3",
|
||||||
|
"sortablejs": "1.15.7",
|
||||||
|
"sortablejs-vue3": "1.3.0",
|
||||||
|
"tabulator-tables": "6.3.1",
|
||||||
|
"tippy.js": "6.3.7",
|
||||||
|
"twemoji": "14.0.2",
|
||||||
|
"typescript": "5.9.3",
|
||||||
|
"uuid": "13.0.0",
|
||||||
|
"v-network-graph": "0.9.22",
|
||||||
|
"vue": "3.5.29",
|
||||||
|
"vue-i18n": "11.2.8",
|
||||||
|
"vue-router": "5.0.3",
|
||||||
|
"vue3-otp-input": "0.5.40",
|
||||||
|
"vuedraggable": "4.1.0",
|
||||||
|
"zxcvbn": "4.4.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@intlify/unplugin-vue-i18n": "11.0.7",
|
||||||
|
"@quasar/app-vite": "2.4.1",
|
||||||
|
"@quasar/vite-plugin": "1.10.0",
|
||||||
|
"@types/lodash": "4.17.24",
|
||||||
|
"@vue/language-plugin-pug": "3.2.5",
|
||||||
|
"autoprefixer": "10.4.27",
|
||||||
|
"browserlist": "latest",
|
||||||
|
"npm-check-updates": "19.6.3",
|
||||||
|
"sass": "1.97.3",
|
||||||
|
"vite-plugin-vue-devtools": "8.0.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18.0",
|
||||||
|
"npm": ">= 6.13.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import autoprefixer from 'autoprefixer'
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||||
|
|
||||||
|
export default {
|
||||||
|
plugins: [
|
||||||
|
// https://github.com/postcss/autoprefixer
|
||||||
|
autoprefixer({
|
||||||
|
overrideBrowserslist: [
|
||||||
|
'last 4 Chrome versions',
|
||||||
|
'last 4 Firefox versions',
|
||||||
|
'last 4 Edge versions',
|
||||||
|
'last 4 Safari versions',
|
||||||
|
'last 4 Android versions',
|
||||||
|
'last 4 ChromeAndroid versions',
|
||||||
|
'last 4 FirefoxAndroid versions',
|
||||||
|
'last 4 iOS versions'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// https://github.com/elchininet/postcss-rtlcss
|
||||||
|
// If you want to support RTL css, then
|
||||||
|
// 1. yarn/npm install postcss-rtlcss
|
||||||
|
// 2. optionally set quasar.config.js > framework > lang to an RTL language
|
||||||
|
// 3. uncomment the following line:
|
||||||
|
// require('postcss-rtlcss')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 382 KiB |
@ -0,0 +1,40 @@
|
|||||||
|
/* roboto-300 - vietnamese_latin-ext_latin_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local(''),
|
||||||
|
url('/_assets/fonts/roboto/roboto-all-300.woff2') format('woff2')
|
||||||
|
}
|
||||||
|
/* roboto-regular - vietnamese_latin-ext_latin_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local(''),
|
||||||
|
url('/_assets/fonts/roboto/roboto-all-regular.woff2') format('woff2')
|
||||||
|
}
|
||||||
|
/* roboto-500 - vietnamese_latin-ext_latin_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local(''),
|
||||||
|
url('/_assets/fonts/roboto/roboto-all-500.woff2') format('woff2')
|
||||||
|
}
|
||||||
|
/* roboto-700 - vietnamese_latin-ext_latin_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local(''),
|
||||||
|
url('/_assets/fonts/roboto/roboto-all-700.woff2') format('woff2')
|
||||||
|
}
|
||||||
|
/* roboto-900 - vietnamese_latin-ext_latin_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
src: local(''),
|
||||||
|
url('/_assets/fonts/roboto/roboto-all-900.woff2') format('woff2')
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-display: swap;
|
||||||
|
src: url(/_assets/fonts/rubik/rubik-variable-cyrillic-ext.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-display: swap;
|
||||||
|
src: url(/_assets/fonts/rubik/rubik-variable-cyrillic.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* hebrew */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-display: swap;
|
||||||
|
src: url(/_assets/fonts/rubik/rubik-variable-hebrew.woff2) format('woff2');
|
||||||
|
unicode-range: U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-display: swap;
|
||||||
|
src: url(/_assets/fonts/rubik/rubik-variable-latin-ext.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-display: swap;
|
||||||
|
src: url(/_assets/fonts/rubik/rubik-variable-latin.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.wiki-root {
|
||||||
|
font-family: 'Rubik', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 353 B |
|
After Width: | Height: | Size: 965 B |
|
After Width: | Height: | Size: 376 B |
|
After Width: | Height: | Size: 689 B |
|
After Width: | Height: | Size: 452 B |
|
After Width: | Height: | Size: 632 B |
|
After Width: | Height: | Size: 440 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 748 B |
|
After Width: | Height: | Size: 390 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 676 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 288 B |
|
After Width: | Height: | Size: 494 B |
|
After Width: | Height: | Size: 533 B |
|
After Width: | Height: | Size: 791 B |
|
After Width: | Height: | Size: 344 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 925 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 865 B |
|
After Width: | Height: | Size: 876 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 727 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 881 B |
|
After Width: | Height: | Size: 980 B |
|
After Width: | Height: | Size: 664 B |
|
After Width: | Height: | Size: 364 B |
|
After Width: | Height: | Size: 426 B |
|
After Width: | Height: | Size: 490 B |
|
After Width: | Height: | Size: 243 B |
|
After Width: | Height: | Size: 581 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 363 B |
|
After Width: | Height: | Size: 358 B |
|
After Width: | Height: | Size: 544 B |
|
After Width: | Height: | Size: 607 B |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 453 B |
|
After Width: | Height: | Size: 2.1 KiB |