1
0
Fork 0
mirror of https://github.com/codex-team/codex.docs.git synced 2025-08-09 07:25:21 +02:00

Merge branch 'main' into feat/sidebar-search

This commit is contained in:
Umang G. Patel 2022-08-28 18:50:04 +05:30 committed by GitHub
commit ba9e854086
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 2672 additions and 24642 deletions

23384
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
{ {
"name": "codex.docs", "name": "codex.docs",
"license": "Apache-2.0", "license": "Apache-2.0",
"type": "module",
"browserslist": [ "browserslist": [
"last 2 versions", "last 2 versions",
"> 1%" "> 1%"
@ -12,11 +13,12 @@
"build-frontend": "webpack --mode=production", "build-frontend": "webpack --mode=production",
"build-frontend:dev": "webpack --mode=development --watch", "build-frontend:dev": "webpack --mode=development --watch",
"test:js": "cross-env NODE_ENV=testing mocha --recursive ./dist/test --exit", "test:js": "cross-env NODE_ENV=testing mocha --recursive ./dist/test --exit",
"test": "cross-env NODE_ENV=testing ts-mocha ./src/test/*.ts ./src/test/**/*.ts --exit", "test": "cross-env NODE_ENV=testing ts-mocha -n loader=ts-node/esm ./src/test/*.ts ./src/test/**/*.ts --exit ",
"lint": "eslint --fix --ext .ts ./src/backend", "lint": "eslint --fix --ext .ts ./src/backend",
"editor-upgrade": "yarn add -D @editorjs/{editorjs,header,code,delimiter,list,link,image,table,inline-code,marker,warning,checklist,raw}@latest" "editor-upgrade": "yarn add -D @editorjs/{editorjs,header,code,delimiter,list,link,image,table,inline-code,marker,warning,checklist,raw}@latest"
}, },
"dependencies": { "dependencies": {
"@codexteam/shortcuts": "^1.2.0",
"@hawk.so/javascript": "^3.0.1", "@hawk.so/javascript": "^3.0.1",
"@hawk.so/nodejs": "^3.1.2", "@hawk.so/nodejs": "^3.1.2",
"config": "^3.3.6", "config": "^3.3.6",
@ -25,7 +27,7 @@
"debug": "^4.3.2", "debug": "^4.3.2",
"dotenv": "^16.0.0", "dotenv": "^16.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"file-type": "^16.5.2", "file-type": "^16.5.4",
"http-errors": "^2.0.0", "http-errors": "^2.0.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"mime": "^3.0.0", "mime": "^3.0.0",
@ -34,7 +36,7 @@
"multer": "^1.4.2", "multer": "^1.4.2",
"nedb": "^1.8.0", "nedb": "^1.8.0",
"node-cache": "^5.1.2", "node-cache": "^5.1.2",
"node-fetch": "^2.6.1", "node-fetch": "^3.2.10",
"open-graph-scraper": "^4.9.0", "open-graph-scraper": "^4.9.0",
"twig": "^1.15.4", "twig": "^1.15.4",
"uuid4": "^2.0.2" "uuid4": "^2.0.2"
@ -48,7 +50,7 @@
"@editorjs/checklist": "^1.3.0", "@editorjs/checklist": "^1.3.0",
"@editorjs/code": "^2.7.0", "@editorjs/code": "^2.7.0",
"@editorjs/delimiter": "^1.2.0", "@editorjs/delimiter": "^1.2.0",
"@editorjs/editorjs": "^2.23.2", "@editorjs/editorjs": "^2.25.0",
"@editorjs/embed": "^2.5.1", "@editorjs/embed": "^2.5.1",
"@editorjs/header": "^2.6.2", "@editorjs/header": "^2.6.2",
"@editorjs/image": "^2.6.2", "@editorjs/image": "^2.6.2",
@ -98,7 +100,7 @@
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
"highlight.js": "^11.1.0", "highlight.js": "^11.1.0",
"mini-css-extract-plugin": "^2.6.0", "mini-css-extract-plugin": "^2.6.0",
"mocha": "^5.2.0", "mocha": "^10.0.0",
"mocha-sinon": "^2.1.2", "mocha-sinon": "^2.1.2",
"module-dispatcher": "^2.0.0", "module-dispatcher": "^2.0.0",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
@ -118,10 +120,10 @@
"postcss-nesting": "^10.1.3", "postcss-nesting": "^10.1.3",
"postcss-smart-import": "^0.7.6", "postcss-smart-import": "^0.7.6",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"sinon": "^11.1.2", "sinon": "^14.0.0",
"ts-mocha": "^8.0.0", "ts-mocha": "^10.0.0",
"ts-node": "^10.1.0", "ts-node": "^10.9.1",
"typescript": "^4.3.5", "typescript": "^4.7.4",
"webpack": "^5.70.0", "webpack": "^5.70.0",
"webpack-cli": "^4.9.2" "webpack-cli": "^4.9.2"
} }

View file

@ -1,17 +1,24 @@
import express, { NextFunction, Request, Response } from 'express'; import express, { NextFunction, Request, Response } from 'express';
import path from 'path'; import path from 'path';
import { fileURLToPath } from 'url';
import cookieParser from 'cookie-parser'; import cookieParser from 'cookie-parser';
import morgan from 'morgan'; import morgan from 'morgan';
import rcParser from './utils/rcparser'; import rcParser from './utils/rcparser.js';
import routes from './routes'; import routes from './routes/index.js';
import HttpException from './exceptions/httpException'; import HttpException from './exceptions/httpException.js';
import * as dotenv from 'dotenv'; import * as dotenv from 'dotenv';
import config from 'config'; import config from 'config';
import HawkCatcher from '@hawk.so/nodejs'; import { default as HawkCatcher } from '@hawk.so/nodejs';
import os from 'os'; import os from 'os';
import appConfig from 'config'; import appConfig from 'config';
import { downloadFavicon, FaviconData } from './utils/downloadFavicon'; import { downloadFavicon, FaviconData } from './utils/downloadFavicon.js';
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
dotenv.config(); dotenv.config();
const app = express(); const app = express();
@ -34,7 +41,7 @@ if (process.env.HAWK_TOKEN_CLIENT) {
// view engine setup // view engine setup
app.set('views', path.join(__dirname, './', 'views')); app.set('views', path.join(__dirname, './', 'views'));
app.set('view engine', 'twig'); app.set('view engine', 'twig');
require('./utils/twig'); import('./utils/twig.js');
const downloadedFaviconFolder = os.tmpdir(); const downloadedFaviconFolder = os.tmpdir();

View file

@ -1,4 +1,4 @@
import Alias from '../models/alias'; import Alias from '../models/alias.js';
/** /**
* @class Aliases * @class Aliases

View file

@ -1,9 +1,9 @@
import Page, { PageData } from '../models/page'; import Page, { PageData } from '../models/page.js';
import Alias from '../models/alias'; import Alias from '../models/alias.js';
import PagesOrder from './pagesOrder'; import PagesOrder from './pagesOrder.js';
import PageOrder from '../models/pageOrder'; import PageOrder from '../models/pageOrder.js';
import HttpException from '../exceptions/httpException'; import HttpException from '../exceptions/httpException.js';
import PagesFlatArray from '../models/pagesFlatArray'; import PagesFlatArray from '../models/pagesFlatArray.js';
type PageDataFields = keyof PageData; type PageDataFields = keyof PageData;

View file

@ -1,6 +1,6 @@
import PageOrder from '../models/pageOrder'; import PageOrder from '../models/pageOrder.js';
import Page from '../models/page'; import Page from '../models/page.js';
import PagesFlatArray from '../models/pagesFlatArray'; import PagesFlatArray from '../models/pagesFlatArray.js';
/** /**
* @class PagesOrder * @class PagesOrder

View file

@ -3,9 +3,9 @@ import fetch from 'node-fetch';
import fs from 'fs'; import fs from 'fs';
import nodePath from 'path'; import nodePath from 'path';
import config from 'config'; import config from 'config';
import File, { FileData } from '../models/file'; import File, { FileData } from '../models/file.js';
import crypto from '../utils/crypto'; import crypto from '../utils/crypto.js';
import deepMerge from '../utils/objects'; import deepMerge from '../utils/objects.js';
const random16 = crypto.random16; const random16 = crypto.random16;

View file

@ -1,5 +1,5 @@
import crypto from '../utils/crypto'; import crypto from '../utils/crypto.js';
import database from '../utils/database/index'; import database from '../utils/database/index.js';
const binaryMD5 = crypto.binaryMD5; const binaryMD5 = crypto.binaryMD5;
const aliasesDb = database['aliases']; const aliasesDb = database['aliases'];

View file

@ -1,4 +1,4 @@
import database from '../utils/database/index'; import database from '../utils/database/index.js';
const filesDb = database['files']; const filesDb = database['files'];

View file

@ -1,5 +1,5 @@
import urlify from '../utils/urlify'; import urlify from '../utils/urlify.js';
import database from '../utils/database/index'; import database from '../utils/database/index.js';
const pagesDb = database['pages']; const pagesDb = database['pages'];

View file

@ -1,4 +1,4 @@
import database from '../utils/database/index'; import database from '../utils/database/index.js';
const db = database['pagesOrder']; const db = database['pagesOrder'];

View file

@ -1,5 +1,5 @@
import Page from './page'; import Page from './page.js';
import PageOrder from './pageOrder'; import PageOrder from './pageOrder.js';
import NodeCache from 'node-cache'; import NodeCache from 'node-cache';
// Create cache for flat array // Create cache for flat array

View file

@ -1,9 +1,9 @@
import express, { Request, Response } from 'express'; import express, { Request, Response } from 'express';
import Aliases from '../controllers/aliases'; import Aliases from '../controllers/aliases.js';
import Pages from '../controllers/pages'; import Pages from '../controllers/pages.js';
import Alias from '../models/alias'; import Alias from '../models/alias.js';
import verifyToken from './middlewares/token'; import verifyToken from './middlewares/token.js';
import PagesFlatArray from '../models/pagesFlatArray'; import PagesFlatArray from '../models/pagesFlatArray.js';
const router = express.Router(); const router = express.Router();

View file

@ -1,7 +1,7 @@
import express from 'express'; import express from 'express';
import pagesAPI from './pages'; import pagesAPI from './pages.js';
import transportAPI from './transport'; import transportAPI from './transport.js';
import linksAPI from './links'; import linksAPI from './links.js';
const router = express.Router(); const router = express.Router();

View file

@ -1,7 +1,7 @@
import express, { Request, Response } from 'express'; import express, { Request, Response } from 'express';
import multerFunc from 'multer'; import multerFunc from 'multer';
import Pages from '../../controllers/pages'; import Pages from '../../controllers/pages.js';
import PagesOrder from '../../controllers/pagesOrder'; import PagesOrder from '../../controllers/pagesOrder.js';
const router = express.Router(); const router = express.Router();
const multer = multerFunc(); const multer = multerFunc();

View file

@ -3,8 +3,8 @@ import multer, { StorageEngine } from 'multer';
import mime from 'mime'; import mime from 'mime';
import mkdirp from 'mkdirp'; import mkdirp from 'mkdirp';
import config from 'config'; import config from 'config';
import Transport from '../../controllers/transport'; import Transport from '../../controllers/transport.js';
import { random16 } from '../../utils/crypto'; import { random16 } from '../../utils/crypto.js';
const router = Router(); const router = Router();

View file

@ -1,5 +1,5 @@
import express, { Request, Response } from 'express'; import express, { Request, Response } from 'express';
import verifyToken from './middlewares/token'; import verifyToken from './middlewares/token.js';
const router = express.Router(); const router = express.Router();

View file

@ -1,10 +1,10 @@
import express from 'express'; import express from 'express';
import home from './home'; import home from './home.js';
import pages from './pages'; import pages from './pages.js';
import auth from './auth'; import auth from './auth.js';
import aliases from './aliases'; import aliases from './aliases.js';
import api from './api'; import api from './api/index.js';
import pagesMiddleware from './middlewares/pages'; import pagesMiddleware from './middlewares/pages.js';
const router = express.Router(); const router = express.Router();

View file

@ -1,9 +1,9 @@
import { NextFunction, Request, Response } from 'express'; import { NextFunction, Request, Response } from 'express';
import Pages from '../../controllers/pages'; import Pages from '../../controllers/pages.js';
import PagesOrder from '../../controllers/pagesOrder'; import PagesOrder from '../../controllers/pagesOrder.js';
import Page from '../../models/page'; import Page from '../../models/page.js';
import asyncMiddleware from '../../utils/asyncMiddleware'; import asyncMiddleware from '../../utils/asyncMiddleware.js';
import PageOrder from '../../models/pageOrder'; import PageOrder from '../../models/pageOrder.js';
/** /**
* Process one-level pages list to parent-children list * Process one-level pages list to parent-children list

View file

@ -1,9 +1,9 @@
import express, { NextFunction, Request, Response } from 'express'; import express, { NextFunction, Request, Response } from 'express';
import Pages from '../controllers/pages'; import Pages from '../controllers/pages.js';
import PagesOrder from '../controllers/pagesOrder'; import PagesOrder from '../controllers/pagesOrder.js';
import verifyToken from './middlewares/token'; import verifyToken from './middlewares/token.js';
import allowEdit from './middlewares/locals'; import allowEdit from './middlewares/locals.js';
import PagesFlatArray from '../models/pagesFlatArray'; import PagesFlatArray from '../models/pagesFlatArray.js';
const router = express.Router(); const router = express.Router();

View file

@ -1,9 +1,9 @@
import Datastore from 'nedb'; import Datastore from 'nedb';
import { AliasData } from '../../models/alias'; import { AliasData } from '../../models/alias.js';
import { FileData } from '../../models/file'; import { FileData } from '../../models/file.js';
import { PageData } from '../../models/page'; import { PageData } from '../../models/page.js';
import { PageOrderData } from '../../models/pageOrder'; import { PageOrderData } from '../../models/pageOrder.js';
import initDb from './initDb'; import initDb from './initDb.js';
/** /**
* @typedef Options - optional params * @typedef Options - optional params

View file

@ -1,6 +1,6 @@
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import fetch from 'node-fetch'; import fetch, { RequestInit } from 'node-fetch';
/** /**
* Uploaded favicon data * Uploaded favicon data
@ -61,7 +61,7 @@ export async function downloadFavicon(destination: string, faviconFolder: string
}, 5000); }, 5000);
// Make get request to url // Make get request to url
const res = await fetch(destination, { signal: controller.signal }); const res = await fetch(destination, { signal: controller.signal as RequestInit['signal'] });
// Get buffer data from response // Get buffer data from response
const fileData = await res.buffer(); const fileData = await res.buffer();

View file

@ -1,6 +1,14 @@
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import config from 'config'; import config from 'config';
import { fileURLToPath } from 'url';
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const rcPath = path.resolve(__dirname, '../../../', config.get('rcFile') || './.codexdocsrc'); const rcPath = path.resolve(__dirname, '../../../', config.get('rcFile') || './.codexdocsrc');

View file

@ -3,8 +3,16 @@
*/ */
import twig from 'twig'; import twig from 'twig';
import fs from 'fs'; import fs from 'fs';
import urlify from './urlify'; import urlify from './urlify.js';
import path from 'path'; import path from 'path';
import { fileURLToPath } from 'url';
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default (function () { export default (function () {
'use strict'; 'use strict';

View file

@ -1,4 +1,4 @@
import translateString from './translation'; import translateString from './translation.js';
/** /**
* Convert text to URL-like string * Convert text to URL-like string

View file

@ -55,4 +55,8 @@
</div> </div>
</aside> </aside>
<div class="docs-sidebar__slider">
{{ svg('arrow-left') }}
</div>
</div> </div>

View file

@ -1,7 +1,7 @@
/** /**
* Module dependencies. * Module dependencies.
*/ */
import app from '../backend/app'; import app from '../backend/app.js';
import http from 'http'; import http from 'http';
import config from 'config'; import config from 'config';
import Debug from 'debug'; import Debug from 'debug';

View file

@ -1,10 +1,11 @@
import { Storage } from '../utils/storage'; import { Storage } from '../utils/storage';
import Shortcut from '@codexteam/shortcuts';
/** /**
* Local storage key * Local storage key
*/ */
const LOCAL_STORAGE_KEY = 'docs_sidebar_state'; const LOCAL_STORAGE_KEY = 'docs_sidebar_state';
const SIDEBAR_VISIBILITY_KEY = 'docs_sidebar_visibility';
/** /**
* Section list item height in px * Section list item height in px
@ -36,6 +37,9 @@ export default class Sidebar {
sectionListItemActive: 'docs-sidebar__section-list-item--active', sectionListItemActive: 'docs-sidebar__section-list-item--active',
sectionListItemSlelected: 'docs-sidebar__section-list-item--selected', sectionListItemSlelected: 'docs-sidebar__section-list-item--selected',
sidebarToggler: 'docs-sidebar__toggler', sidebarToggler: 'docs-sidebar__toggler',
sidebarSlider: 'docs-sidebar__slider',
sidebarCollapsed: 'docs-sidebar--collapsed',
sidebarAnimated: 'docs-sidebar--animated',
sidebarContent: 'docs-sidebar__content', sidebarContent: 'docs-sidebar__content',
sidebarContentHidden: 'docs-sidebar__content--hidden', sidebarContentHidden: 'docs-sidebar__content--hidden',
sidebarContentInvisible: 'docs-sidebar__content--invisible', sidebarContentInvisible: 'docs-sidebar__content--invisible',
@ -53,9 +57,11 @@ export default class Sidebar {
* Stores refs to HTML elements needed for correct sidebar work * Stores refs to HTML elements needed for correct sidebar work
*/ */
this.nodes = { this.nodes = {
sidebar: null,
sections: [], sections: [],
sidebarContent: null, sidebarContent: null,
toggler: null, toggler: null,
slider: null,
search:null, search:null,
searchResults: [], searchResults: [],
selectedSearchResultIndex: null, selectedSearchResultIndex: null,
@ -64,6 +70,14 @@ export default class Sidebar {
const storedState = this.sidebarStorage.get(); const storedState = this.sidebarStorage.get();
this.sectionsState = storedState ? JSON.parse(storedState) : {}; this.sectionsState = storedState ? JSON.parse(storedState) : {};
// Initialize localStorage that contains sidebar visibility
this.sidebarVisibilityStorage = new Storage(SIDEBAR_VISIBILITY_KEY);
// Get current sidebar visibility from storage
const storedVisibility = this.sidebarVisibilityStorage.get();
// Sidebar visibility
this.isVisible = storedVisibility !== 'false';
} }
/** /**
@ -73,11 +87,14 @@ export default class Sidebar {
* @param {HTMLElement} moduleEl - module element * @param {HTMLElement} moduleEl - module element
*/ */
init(settings, moduleEl) { init(settings, moduleEl) {
this.nodes.sidebar = moduleEl;
this.nodes.sections = Array.from(moduleEl.querySelectorAll('.' + Sidebar.CSS.section)); this.nodes.sections = Array.from(moduleEl.querySelectorAll('.' + Sidebar.CSS.section));
this.nodes.sections.forEach(section => this.initSection(section)); this.nodes.sections.forEach(section => this.initSection(section));
this.nodes.sidebarContent = moduleEl.querySelector('.' + Sidebar.CSS.sidebarContent); this.nodes.sidebarContent = moduleEl.querySelector('.' + Sidebar.CSS.sidebarContent);
this.nodes.toggler = moduleEl.querySelector('.' + Sidebar.CSS.sidebarToggler); this.nodes.toggler = moduleEl.querySelector('.' + Sidebar.CSS.sidebarToggler);
this.nodes.toggler.addEventListener('click', () => this.toggleSidebar()); this.nodes.toggler.addEventListener('click', () => this.toggleSidebar());
this.nodes.slider = moduleEl.querySelector('.' + Sidebar.CSS.sidebarSlider);
this.nodes.slider.addEventListener('click', () => this.handleSliderClick());
this.nodes.search = moduleEl.querySelector('.' + Sidebar.CSS.sidebarSearch); this.nodes.search = moduleEl.querySelector('.' + Sidebar.CSS.sidebarSearch);
let className = Sidebar.CSS.sidebarSearchWrapperOther; let className = Sidebar.CSS.sidebarSearchWrapperOther;
@ -97,7 +114,6 @@ export default class Sidebar {
this.search(''); this.search('');
// Add event listener for keyboard events. // Add event listener for keyboard events.
document.addEventListener('keydown', e => this.keyboardListener(e)); document.addEventListener('keydown', e => this.keyboardListener(e));
this.ready(); this.ready();
} }
@ -135,7 +151,7 @@ export default class Sidebar {
const itemsCount = sectionList.children.length; const itemsCount = sectionList.children.length;
sectionList.style.maxHeight = `${ itemsCount * ITEM_HEIGHT }px`; sectionList.style.maxHeight = `${itemsCount * ITEM_HEIGHT}px`;
} }
/** /**
@ -199,12 +215,52 @@ export default class Sidebar {
this.nodes.sidebarContent.classList.toggle(Sidebar.CSS.sidebarContentHidden); this.nodes.sidebarContent.classList.toggle(Sidebar.CSS.sidebarContentHidden);
} }
/**
* Initializes sidebar
*
* @returns {void}
*/
initSidebar() {
if (!this.isVisible) {
this.nodes.sidebar.classList.add(Sidebar.CSS.sidebarCollapsed);
}
/**
* prevent sidebar animation on page load
* Since animated class contains transition, hiding will be animated with it
* To prevent awkward animation when visibility is set to false, we need to remove animated class
*/
setTimeout(() => {
this.nodes.sidebar.classList.add(Sidebar.CSS.sidebarAnimated);
}, 200);
// add event listener to execute keyboard shortcut
// eslint-disable-next-line no-new
new Shortcut({
name: 'CMD+.',
on: document.body,
callback: () => this.handleSliderClick(),
});
}
/**
* Slides sidebar
*
* @returns {void}
*/
handleSliderClick() {
this.isVisible = !this.isVisible;
this.sidebarVisibilityStorage.set(this.isVisible);
this.nodes.sidebar.classList.toggle(Sidebar.CSS.sidebarCollapsed);
}
/** /**
* Displays sidebar when ready * Displays sidebar when ready
* *
* @returns {void} * @returns {void}
*/ */
ready() { ready() {
this.initSidebar();
this.nodes.sidebarContent.classList.remove(Sidebar.CSS.sidebarContentInvisible); this.nodes.sidebarContent.classList.remove(Sidebar.CSS.sidebarContentInvisible);
} }

View file

@ -1,6 +1,34 @@
.docs-sidebar { .docs-sidebar {
width: 100vw; width: 100vw;
&--animated {
.docs-sidebar__content {
transition: transform 200ms ease-in-out;
will-change: transform;
}
.docs-sidebar__slider {
transition: transform 200ms ease-in-out;
will-change: transform;
}
}
&--collapsed {
@media (--desktop) {
.docs-sidebar__content {
transform: translateX(-100%);
}
}
.docs-sidebar__slider {
transform: translateX(20px);
svg {
transform: rotate(180deg);
}
}
}
@media (--desktop) { @media (--desktop) {
width: var(--layout-sidebar-width); width: var(--layout-sidebar-width);
} }
@ -228,6 +256,24 @@
} }
} }
&__slider {
display: none;
position: fixed;
transform: translateX(calc(var(--layout-sidebar-width) + 20px));
bottom: 20px;
width: 32px;
height: 32px;
border-radius: 8px;
cursor: pointer;
background-color: var(--color-link-hover);
@media (--desktop) {
display: flex;
justify-content: center;
align-items: center;
}
}
&__logo { &__logo {
display: none; display: none;
margin-top: auto; margin-top: auto;

View file

@ -0,0 +1,3 @@
<svg width="7" height="11" viewBox="0 0 7 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.95579 10.2458C6.14204 10.0584 6.24658 9.80498 6.24658 9.5408C6.24658 9.27661 6.14204 9.02316 5.95579 8.8358L2.41579 5.2458L5.95579 1.7058C6.14204 1.51844 6.24658 1.26498 6.24658 1.0008C6.24658 0.736612 6.14204 0.483161 5.95579 0.295798C5.86283 0.20207 5.75223 0.127675 5.63037 0.0769067C5.50851 0.026138 5.3778 0 5.24579 0C5.11378 0 4.98307 0.026138 4.86121 0.0769067C4.73935 0.127675 4.62875 0.20207 4.53579 0.295798L0.295789 4.5358C0.202061 4.62876 0.127667 4.73936 0.0768978 4.86122C0.0261292 4.98308 -9.32772e-06 5.11379 -9.32772e-06 5.2458C-9.32772e-06 5.37781 0.0261292 5.50852 0.0768978 5.63037C0.127667 5.75223 0.202061 5.86284 0.295789 5.9558L4.53579 10.2458C4.62875 10.3395 4.73935 10.4139 4.86121 10.4647C4.98307 10.5155 5.11378 10.5416 5.24579 10.5416C5.3778 10.5416 5.50851 10.5155 5.63037 10.4647C5.75223 10.4139 5.86283 10.3395 5.95579 10.2458Z" fill="#060C26"/>
</svg>

After

Width:  |  Height:  |  Size: 991 B

View file

@ -3,7 +3,7 @@ import config from 'config';
import { expect } from 'chai'; import { expect } from 'chai';
import Datastore from 'nedb'; import Datastore from 'nedb';
import { Database } from '../backend/utils/database'; import { Database } from '../backend/utils/database/index.js';
interface Document { interface Document {
data?: any; data?: any;

View file

@ -1,7 +1,7 @@
import chaiHTTP from 'chai-http'; import chaiHTTP from 'chai-http';
import chai, { expect } from 'chai'; import chai, { expect } from 'chai';
import server from '../bin/server'; import server from '../bin/server.js';
const app = server.app; const app = server.app;

View file

@ -2,12 +2,20 @@ import { expect } from 'chai';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import config from 'config'; import config from 'config';
import Alias from '../../backend/models/alias'; import Alias from '../../backend/models/alias.js';
import { binaryMD5 } from '../../backend/utils/crypto'; import { binaryMD5 } from '../../backend/utils/crypto.js';
import database from '../../backend/utils/database'; import database from '../../backend/utils/database/index.js';
import { fileURLToPath } from 'url';
const aliases = database['aliases']; const aliases = database['aliases'];
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
describe('Alias model', () => { describe('Alias model', () => {
after(() => { after(() => {
const pathToDB = path.resolve(__dirname, '../../../', config.get('database'), './aliases.db'); const pathToDB = path.resolve(__dirname, '../../../', config.get('database'), './aliases.db');

View file

@ -2,8 +2,16 @@ import { expect } from 'chai';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import config from 'config'; import config from 'config';
import File from '../../backend/models/file'; import File from '../../backend/models/file.js';
import database from '../../backend/utils/database'; import database from '../../backend/utils/database/index.js';
import { fileURLToPath } from 'url';
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const files = database['files']; const files = database['files'];

View file

@ -2,9 +2,17 @@ import { expect } from 'chai';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import config from 'config'; import config from 'config';
import Page from '../../backend/models/page'; import Page from '../../backend/models/page.js';
import translateString from '../../backend/utils/translation'; import translateString from '../../backend/utils/translation.js';
import database from '../../backend/utils/database'; import database from '../../backend/utils/database/index.js';
import { fileURLToPath } from 'url';
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const pages = database['pages']; const pages = database['pages'];

View file

@ -2,8 +2,16 @@ import { expect } from 'chai';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import config from 'config'; import config from 'config';
import PageOrder from '../../backend/models/pageOrder'; import PageOrder from '../../backend/models/pageOrder.js';
import database from '../../backend/utils/database'; import database from '../../backend/utils/database/index.js';
import { fileURLToPath } from 'url';
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const pagesOrder = database['pagesOrder']; const pagesOrder = database['pagesOrder'];

View file

@ -4,7 +4,7 @@ import path from 'path';
import config from 'config'; import config from 'config';
import sinon = require('sinon'); import sinon = require('sinon');
import rcParser from '../backend/utils/rcparser'; import rcParser from '../backend/utils/rcparser.js';
const rcPath = path.resolve(process.cwd(), config.get('rcFile')); const rcPath = path.resolve(process.cwd(), config.get('rcFile'));

View file

@ -3,7 +3,15 @@ import path from 'path';
import config from 'config'; import config from 'config';
import chai from 'chai'; import chai from 'chai';
import chaiHTTP from 'chai-http'; import chaiHTTP from 'chai-http';
import server from '../../bin/server'; import server from '../../bin/server.js';
import { fileURLToPath } from 'url';
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const {expect} = chai; const {expect} = chai;
const app = server.app; const app = server.app;

View file

@ -3,11 +3,20 @@ import path from 'path';
import config from 'config'; import config from 'config';
import chai from 'chai'; import chai from 'chai';
import chaiHTTP from 'chai-http'; import chaiHTTP from 'chai-http';
import server from '../../bin/server'; import server from '../../bin/server.js';
import model from '../../backend/models/page'; import model from '../../backend/models/page.js';
import Page from '../../backend/models/page'; import Page from '../../backend/models/page.js';
import PageOrder from '../../backend/models/pageOrder'; import PageOrder from '../../backend/models/pageOrder.js';
import translateString from '../../backend/utils/translation'; import translateString from '../../backend/utils/translation.js';
import { fileURLToPath } from 'url';
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const {expect} = chai; const {expect} = chai;
const app = server.app; const app = server.app;

View file

@ -5,8 +5,17 @@ import chai from 'chai';
import chaiHTTP from 'chai-http'; import chaiHTTP from 'chai-http';
import rimraf from 'rimraf'; import rimraf from 'rimraf';
import config from 'config'; import config from 'config';
import server from '../../bin/server'; import server from '../../bin/server.js';
import model from '../../backend/models/file'; import model from '../../backend/models/file.js';
import { fileURLToPath } from 'url';
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const {expect} = chai; const {expect} = chai;
const app = server.app; const app = server.app;

View file

@ -4,9 +4,11 @@
/* Basic Options */ /* Basic Options */
// "incremental": true, /* Enable incremental compilation */ // "incremental": true, /* Enable incremental compilation */
"target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ "target": "ES2021", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ "module": "Node16", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */ "lib": [ /* Specify library files to be included in the compilation. */
"ESNext" /* ESNext includes new Level-4 features that were recently added to the ECMA-262 JS spec */
],
// "allowJs": true, /* Allow javascript files to be compiled. */ // "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */ // "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
@ -44,13 +46,16 @@
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
/* Module Resolution Options */ /* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ "moduleResolution": "NodeNext", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */ // "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */ "types": [ /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ "node",
"mocha"
],
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
@ -69,5 +74,12 @@
"skipLibCheck": true, /* Skip type checking of declaration files. */ "skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}, },
"include": ["src/**/*"] "include": ["src/**/*"],
"ts-node": {
/**
* Tell ts-node CLI to install the --loader automatically, explained below
* https://typestrong.org/ts-node/docs/imports/
*/
"esm": true
}
} }

View file

@ -1,5 +1,12 @@
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); import MiniCssExtractPlugin from 'mini-css-extract-plugin';
const path = require('path'); import path from 'path';
import { fileURLToPath } from 'url';
/**
* The __dirname CommonJS variables are not available in ES modules.
* https://nodejs.org/api/esm.html#no-__filename-or-__dirname
*/
const __dirname = path.dirname(fileURLToPath(import.meta.url));
/** /**
* Options for the Babel * Options for the Babel
@ -22,7 +29,7 @@ const babelLoader = {
}, },
}; };
module.exports = () => { export default () => {
return { return {
entry: './src/frontend/js/app.js', entry: './src/frontend/js/app.js',
output: { output: {
@ -53,9 +60,18 @@ module.exports = () => {
loader: 'postcss-loader', loader: 'postcss-loader',
}, },
], ],
}, { },
{
test: /\.js$/, test: /\.js$/,
exclude: /(node_modules|bower_components)/, exclude: /(node_modules|bower_components)/,
resolve: {
/**
* Disable mandatory to specify full paths with extensions using '"type": "module"' in package.json
* @see https://github.com/webpack/webpack/issues/11467#issuecomment-691873586
* @see https://stackoverflow.com/questions/69427025/programmatic-webpack-jest-esm-cant-resolve-module-without-js-file-exten
*/
fullySpecified: false,
},
use: [ use: [
babelLoader, babelLoader,
], ],

3470
yarn.lock

File diff suppressed because it is too large Load diff