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

Merge branch 'main' into fix-horizontal-scroll

This commit is contained in:
Peter Savchenko 2022-09-06 22:59:33 +03:00
commit 82e01bc656
No known key found for this signature in database
GPG key ID: E68306B1AB0F727C
55 changed files with 2060 additions and 25059 deletions

23626
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
{
"name": "codex.docs",
"license": "Apache-2.0",
"type": "module",
"browserslist": [
"last 2 versions",
"> 1%"
@ -12,11 +13,12 @@
"build-frontend": "webpack --mode=production",
"build-frontend:dev": "webpack --mode=development --watch",
"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",
"editor-upgrade": "yarn add -D @editorjs/{editorjs,header,code,delimiter,list,link,image,table,inline-code,marker,warning,checklist,raw}@latest"
},
"dependencies": {
"@codexteam/shortcuts": "^1.2.0",
"@hawk.so/javascript": "^3.0.1",
"@hawk.so/nodejs": "^3.1.2",
"config": "^3.3.6",
@ -34,7 +36,7 @@
"multer": "^1.4.2",
"nedb": "^1.8.0",
"node-cache": "^5.1.2",
"node-fetch": "^2.6.1",
"node-fetch": "^3.2.10",
"open-graph-scraper": "^4.9.0",
"twig": "^1.15.4",
"uuid4": "^2.0.2"
@ -48,7 +50,7 @@
"@editorjs/checklist": "^1.3.0",
"@editorjs/code": "^2.7.0",
"@editorjs/delimiter": "^1.2.0",
"@editorjs/editorjs": "^2.23.2",
"@editorjs/editorjs": "^2.25.0",
"@editorjs/embed": "^2.5.1",
"@editorjs/header": "^2.6.2",
"@editorjs/image": "^2.6.2",
@ -98,7 +100,7 @@
"eslint-plugin-node": "^11.1.0",
"highlight.js": "^11.1.0",
"mini-css-extract-plugin": "^2.6.0",
"mocha": "^5.2.0",
"mocha": "^10.0.0",
"mocha-sinon": "^2.1.2",
"module-dispatcher": "^2.0.0",
"normalize.css": "^8.0.1",
@ -118,10 +120,10 @@
"postcss-nesting": "^10.1.3",
"postcss-smart-import": "^0.7.6",
"rimraf": "^3.0.2",
"sinon": "^11.1.2",
"ts-mocha": "^8.0.0",
"ts-node": "^10.1.0",
"typescript": "^4.3.5",
"sinon": "^14.0.0",
"ts-mocha": "^10.0.0",
"ts-node": "^10.9.1",
"typescript": "^4.7.4",
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2"
}

View file

@ -1,17 +1,24 @@
import express, { NextFunction, Request, Response } from 'express';
import path from 'path';
import { fileURLToPath } from 'url';
import cookieParser from 'cookie-parser';
import morgan from 'morgan';
import rcParser from './utils/rcparser';
import routes from './routes';
import HttpException from './exceptions/httpException';
import rcParser from './utils/rcparser.js';
import routes from './routes/index.js';
import HttpException from './exceptions/httpException.js';
import * as dotenv from 'dotenv';
import config from 'config';
import HawkCatcher from '@hawk.so/nodejs';
import { default as HawkCatcher } from '@hawk.so/nodejs';
import os from 'os';
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();
const app = express();
@ -34,7 +41,7 @@ if (process.env.HAWK_TOKEN_CLIENT) {
// view engine setup
app.set('views', path.join(__dirname, './', 'views'));
app.set('view engine', 'twig');
require('./utils/twig');
import('./utils/twig.js');
const downloadedFaviconFolder = os.tmpdir();

View file

@ -1,4 +1,4 @@
import Alias from '../models/alias';
import Alias from '../models/alias.js';
/**
* @class Aliases
@ -14,10 +14,6 @@ class Aliases {
public static async get(aliasName: string): Promise<Alias> {
const alias = await Alias.get(aliasName);
if (!alias.id) {
throw new Error('Entity with given alias does not exist');
}
return alias;
}
}

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
import crypto from '../utils/crypto';
import database from '../utils/database/index';
import crypto from '../utils/crypto.js';
import database from '../utils/database/index.js';
const binaryMD5 = crypto.binaryMD5;
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'];

View file

@ -1,5 +1,5 @@
import urlify from '../utils/urlify';
import database from '../utils/database/index';
import urlify from '../utils/urlify.js';
import database from '../utils/database/index.js';
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'];

View file

@ -1,5 +1,5 @@
import Page from './page';
import PageOrder from './pageOrder';
import Page from './page.js';
import PageOrder from './pageOrder.js';
import NodeCache from 'node-cache';
// Create cache for flat array
@ -43,7 +43,7 @@ export interface PagesFlatArrayData {
}
/**
* @class PagesFlatArray model - flat array of pages, which are ordered like in sidebar
* @class PagesFlatArray model - flat array of pages, which are ordered like in sidebar
*/
class PagesFlatArray {
/**

View file

@ -1,9 +1,11 @@
import express, { Request, Response } from 'express';
import Aliases from '../controllers/aliases';
import Pages from '../controllers/pages';
import Alias from '../models/alias';
import verifyToken from './middlewares/token';
import PagesFlatArray from '../models/pagesFlatArray';
import Aliases from '../controllers/aliases.js';
import Pages from '../controllers/pages.js';
import Alias from '../models/alias.js';
import verifyToken from './middlewares/token.js';
import PagesFlatArray from '../models/pagesFlatArray.js';
import HttpException from '../exceptions/httpException.js';
const router = express.Router();
@ -24,7 +26,7 @@ router.get('*', verifyToken, async (req: Request, res: Response) => {
const alias = await Aliases.get(url);
if (alias.id === undefined) {
throw new Error('Alias not found');
throw new HttpException(404, 'Alias not found');
}
switch (alias.type) {
@ -46,10 +48,17 @@ router.get('*', verifyToken, async (req: Request, res: Response) => {
}
}
} catch (err) {
res.status(400).json({
success: false,
error: err,
});
if (err instanceof HttpException && (err as HttpException).status === 404) {
res.status(404).render('error', {
message: 'Page not found',
status: 404,
});
} else {
res.status(500).json({
success: false,
error: err,
});
}
}
});

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
import path from 'path';
import fs from 'fs';
import fetch from 'node-fetch';
import fetch, { RequestInit } from 'node-fetch';
/**
* Uploaded favicon data
@ -61,7 +61,7 @@ export async function downloadFavicon(destination: string, faviconFolder: string
}, 5000);
// 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
const fileData = await res.buffer();

View file

@ -1,6 +1,14 @@
import fs from 'fs';
import path from 'path';
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');

View file

@ -3,8 +3,16 @@
*/
import twig from 'twig';
import fs from 'fs';
import urlify from './urlify';
import urlify from './urlify.js';
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 () {
'use strict';

View file

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

View file

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

View file

@ -1,7 +1,10 @@
{% extends 'layout.twig' %}
{% block body %}
<h1>{{message}}</h1>
<h2>{{error.status}}</h2>
<pre>{{error.stack}}</pre>
<div class="error-page">
<h1>
┬┴┬┴┤ {{status}} ├┬┴┬┴
</h1>
<h1>{{message}}</h1>
</div>
{% endblock %}

View file

@ -3,19 +3,22 @@
{% block body %}
<article class="page" data-module="page">
<header class="page__header">
<a href="/" class="page__header-nav">
Documentation
</a>
{% if page._parent %}
<a class="page__header-nav"
{% if pageParent.uri %}
href="/{{ pageParent.uri }}"
{% else %}
href="/page/{{ pageParent._id }}"
{% endif %}>
{{ pageParent.title }}
<div class="page__header-nav">
<a href="/" class="page__header-nav-item">
Documentation
</a>
{% endif %}
{{ svg('arrow-right') }}
{% if page._parent %}
<a class="page__header-nav-item"
{% if pageParent.uri %}
href="/{{ pageParent.uri }}"
{% else %}
href="/page/{{ pageParent._id }}"
{% endif %}>
{{ pageParent.title }}
</a>
{% endif %}
</div>
<time class="page__header-time">
Last edit {{ (page.body.time / 1000) | date("M d Y") }}
</time>
@ -34,7 +37,9 @@
{# Skip first header, because it is already showed as a Title #}
{% if not (loop.first and block.type == 'header') %}
{% if block.type in ['paragraph', 'header', 'image', 'code', 'list', 'delimiter', 'table', 'warning', 'checklist', 'linkTool', 'raw', 'embed'] %}
{% include './blocks/' ~ block.type ~ '.twig' with block.data %}
<div class="page__content-block">
{% include './blocks/' ~ block.type ~ '.twig' with block.data %}
</div>
{% endif %}
{% endif %}
{% endfor %}

View file

@ -1,7 +1,7 @@
/**
* Module dependencies.
*/
import app from '../backend/app';
import app from '../backend/app.js';
import http from 'http';
import config from 'config';
import Debug from 'debug';
@ -96,4 +96,4 @@ function onListening(): void {
export default {
server,
app,
};
};

View file

@ -1,10 +1,11 @@
import { Storage } from '../utils/storage';
import Shortcut from '@codexteam/shortcuts';
/**
* Local storage key
*/
const LOCAL_STORAGE_KEY = 'docs_sidebar_state';
const SIDEBAR_VISIBILITY_KEY = 'docs_sidebar_visibility';
/**
* Section list item height in px
@ -31,6 +32,9 @@ export default class Sidebar {
sectionList: 'docs-sidebar__section-list',
sectionListItemActive: 'docs-sidebar__section-list-item--active',
sidebarToggler: 'docs-sidebar__toggler',
sidebarSlider: 'docs-sidebar__slider',
sidebarCollapsed: 'docs-sidebar--collapsed',
sidebarAnimated: 'docs-sidebar--animated',
sidebarContent: 'docs-sidebar__content',
sidebarContentHidden: 'docs-sidebar__content--hidden',
sidebarContentInvisible: 'docs-sidebar__content--invisible',
@ -45,14 +49,24 @@ export default class Sidebar {
* Stores refs to HTML elements needed for correct sidebar work
*/
this.nodes = {
sidebar: null,
sections: [],
sidebarContent: null,
toggler: null,
slider: null,
};
this.sidebarStorage = new Storage(LOCAL_STORAGE_KEY);
const storedState = this.sidebarStorage.get();
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';
}
/**
@ -62,11 +76,14 @@ export default class Sidebar {
* @param {HTMLElement} moduleEl - module element
*/
init(settings, moduleEl) {
this.nodes.sidebar = moduleEl;
this.nodes.sections = Array.from(moduleEl.querySelectorAll('.' + Sidebar.CSS.section));
this.nodes.sections.forEach(section => this.initSection(section));
this.nodes.sidebarContent = moduleEl.querySelector('.' + Sidebar.CSS.sidebarContent);
this.nodes.toggler = moduleEl.querySelector('.' + Sidebar.CSS.sidebarToggler);
this.nodes.toggler.addEventListener('click', () => this.toggleSidebar());
this.nodes.slider = moduleEl.querySelector('.' + Sidebar.CSS.sidebarSlider);
this.nodes.slider.addEventListener('click', () => this.handleSliderClick());
this.ready();
}
@ -104,7 +121,7 @@ export default class Sidebar {
const itemsCount = sectionList.children.length;
sectionList.style.maxHeight = `${ itemsCount * ITEM_HEIGHT }px`;
sectionList.style.maxHeight = `${itemsCount * ITEM_HEIGHT}px`;
}
/**
@ -168,12 +185,52 @@ export default class Sidebar {
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
*
* @returns {void}
*/
ready() {
this.initSidebar();
this.nodes.sidebarContent.classList.remove(Sidebar.CSS.sidebarContentInvisible);
}
}

View file

@ -0,0 +1,29 @@
.error-page {
font-size: 15px;
text-align: center;
position: absolute;
top: 45%;
left: 50%;
@media (--mobile) {
position: relative;
top: 30vh;
left: 0;
}
@media (--tablet) {
position: relative;
top: 30vh;
left: 0;
}
h1 {
@media (--mobile) {
font-size: 20px;
}
}
p {
margin: 40px 0 20px;
}
}

View file

@ -10,15 +10,14 @@ html {
border-bottom: 1px solid var(--color-line-gray);
font-size: 18px;
flex-wrap: wrap;
height: var(--layout-height-header);
box-sizing: border-box;
position: sticky;
top: 0;
background: white;
z-index: 10;
@media (--mobile){
line-height: 40px;
@media (--not-mobile){
height: var(--layout-height-header);
}
&__menu-link,
@ -36,11 +35,13 @@ html {
}
&__menu-link {
padding: 4px 10px;
font-weight: 500;
transition: background-color .13s;
@apply --squircle;
@media (--not-mobile) {
padding: 4px 10px;
@apply --squircle;
}
&:hover {
background-color: var(--color-link-hover);
@ -55,8 +56,9 @@ html {
font-size: 16px;
@media (--mobile) {
margin-top: 6px;
flex-basis: 100%;
font-size: 12px;
font-size: 14px;
}
li {
@ -85,8 +87,8 @@ html {
@media (--mobile) {
display: block;
position: absolute;
right: 15px;
top: 15px;
right: 0;
top: 13px;
line-height: 1em;
}
}

View file

@ -10,13 +10,13 @@
flex-direction: column;
justify-content: space-between;
background-color: var(--color-link-hover);
border-radius: 10px;
padding: 12px 16px 12px 16px;
color: black;
width: max-content;
font-weight: 500;
font-size: 14px;
@apply --squircle;
&--previous {
align-items: flex-start;
margin-left: 0;
@ -29,13 +29,15 @@
&-direction {
text-transform: capitalize;
color: var(--color-direction-navigation);
color: var(--color-text-second);
font-size: 12px;
font-weight: 400;
line-height: 140%;
margin-bottom: 2px;
}
&-label {
width: 100%;
font-weight: 500;
}
}

View file

@ -1,33 +1,38 @@
.page {
font-size: 15px;
line-height: 1.6;
letter-spacing: 0.005em;
&__header {
display: flex;
align-items: center;
margin-bottom: 20px;
font-size: 14px;
color: var(--color-text-second);
line-height: 1.5em;
@media (--mobile) {
font-size: 13px;
}
&-nav {
color: inherit;
text-decoration: none;
display: flex;
align-items: center;
@media (--mobile) {
display: none;
&-item {
color: inherit;
text-decoration: none;
@media (--mobile) {
display: none;
}
&:hover {
color: var(--color-link-active);
}
}
&:hover {
color: var(--color-link-active);
}
svg {
margin: 0 6px;
&:not(:last-of-type) {
&::after {
content: '»';
margin: 0 0.7em 0 0.45em;
@media (--mobile) {
display: none;
}
}
}
@ -47,11 +52,7 @@
}
&__title {
@apply --font-serif;
font-size: 35px;
font-weight: 900;
letter-spacing: -0.04em;
margin-bottom: -0.1em;
@apply --text-content-title;
}
.cdx-marker {
@ -61,48 +62,20 @@
.inline-code,
.block-header a .inline-code {
display: inline-block;
background: rgba(251,241,241,0.78);
color: #C44545;
padding: 0.1em 0.5em;
border-radius: 2px;
margin: 0 2px;
font-family: Menlo, Monaco, Consolas, Courier New, monospace;
font-size: 0.84em;
line-height: 1.4em;
border-bottom: 0;
&:hover {
background: rgba(251,241,241,0.78);
}
@apply --text-inline-code;
}
&__content {
@apply --text-content-main;
a {
text-decoration: none;
border-bottom: 1px solid #000;
padding-bottom: 1px;
color: inherit;
@apply --text-inline-link;
}
&:hover {
color: var(--color-link-active);
border-bottom-color: var(--color-link-active);
}
.inline-code {
margin: 0;
padding: 0.15em .5em;
border-bottom: 1px dashed rgba(84, 151, 255, 0.99);
color: #1f6fd8;
background-color: #daf1fe;
&:hover {
background-color: #c8edfe;
}
}
&-block {
@apply --content-block;
}
}
}
/**
@ -110,6 +83,8 @@
* ==================
*/
.block-paragraph {
margin: 0;
.inline-code {
-webkit-font-smoothing: initial;
-moz-osx-font-smoothing: initial;
@ -121,21 +96,14 @@
* ==================
*/
.block-header {
@apply --font-serif;
margin: 2.1em 0 0.5em;
@apply --text-header;
&--2 {
font-size: 22px;
font-weight: 600;
@apply --text-header-2;
}
&--3 {
font-size: 18px;
font-weight: 600;
}
& + p {
margin-top: 0.5em;
@apply --text-header-3;
}
a {
@ -185,14 +153,8 @@
* ==================
*/
.block-code {
background: var(--color-bg-light);
border: 1px solid #f1f1f4;
border-radius: 5px;
font-family: var(--font-mono);
line-height: 1.7em;
font-size: 13px;
overflow-x: auto;
margin: 15px 0;
@apply --text-code-block;
@apply --squircle;
&__content {
display: inline-block !important;
@ -200,7 +162,7 @@
word-wrap: normal;
background: transparent !important;
padding: 15px !important;
color: #41314e !important;
color: var(--color-code-main) !important;
min-width: 100%;
box-sizing: border-box;
@ -211,13 +173,31 @@
}
}
.hljs-params {
color: var(--color-code-params);
}
.hljs-number {
color: var(--color-code-number);
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
color: var(--color-code-class);
}
.hljs-name,
.hljs-section{
color: #359f3f;
.hljs-section,
.hljs-selector-tag {
color: var(--color-code-tag);
}
.hljs-tag {
color: #718c77;
color: var(--color-code-main);
}
.hljs-attr,
@ -226,7 +206,13 @@
.hljs-selector-id,
.hljs-selector-pseudo,
.hljs-title {
color: #904eb3;
color: var(--color-code-class);
}
.hljs-attribute,
.hljs-literal,
.hljs-operator {
color: var(--color-code-variable);
}
.hljs-emphasis,
@ -235,8 +221,33 @@
.hljs-strong,
.hljs-template-variable,
.hljs-variable {
color: #c21f04;
color: var(--color-code-string);
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type {
color: var(--color-code-keyword);
}
.hljs-variable.language_ {
color: var(--color-code-variable) ;
}
.hljs-code,
.hljs-comment,
.hljs-formula {
color: var(--color-code-comment);
}
.hljs-regexp {
color: var(--color-code-tag);
}
}
/**
@ -244,10 +255,12 @@
* ==================
*/
.block-list {
margin: 20px 0;
margin: 0;
list-style: outside;
padding-left: 26px;
li {
margin: 10px 0;
li:not(:last-of-type) {
margin-bottom: 8px;
}
}
@ -323,7 +336,6 @@
* ==================
*/
.block-table {
margin: 20px 0;
table-layout: fixed;
width: 100%;
border-radius: 3px;
@ -331,11 +343,12 @@
border: 1px solid var(--color-line-gray);
td {
padding: 8px 10px;
padding: 6px 8px;
border: 1px solid var(--color-line-gray);
}
}
/**
* Warning
* ==================
@ -343,10 +356,9 @@
.block-warning {
display: flex;
padding: 20px;
margin: 30px 0;
border-radius: 7px;
background: #fff9ef;
color: #392e2f;
background: #fffad0;
@apply --squircle;
&__icon {
margin-right: 15px;

View file

@ -1,6 +1,34 @@
.docs-sidebar {
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) {
width: var(--layout-sidebar-width);
}
@ -22,6 +50,10 @@
padding-bottom: 0;
}
@media (--mobile){
margin: 0 -8px;
}
&--hidden {
display: none;
}
@ -78,6 +110,11 @@
font-size: 14px;
line-height: 21px;
height: 29px;
@media (--mobile){
font-size: 16px;
line-height: 21px;
}
}
&__section-title,
@ -88,6 +125,7 @@
padding: 0 8px;
transition-property: background-color;
transition-duration: 0.1s;
@apply --squircle;
}
@ -173,8 +211,6 @@
&__toggler {
font-size: 13px;
cursor: pointer;
color: var(--color-text-second);
padding: 20px 15px;
border-bottom: 1px solid var(--color-line-gray);
@ -188,6 +224,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 {
display: none;
margin-top: auto;
@ -196,6 +250,7 @@
padding-bottom: 20px;
padding-top: 60px;
font-size: 14px;
color: var(--color-text-second);
@media (--desktop) {
display: block;

View file

@ -1,12 +1,13 @@
.table-of-content {
border-left: 1px solid var(--color-line-gray);
padding-left: var(--layout-padding-horizontal);
height: 100%;
max-height: 100%;
overflow: auto;
padding: var(--layout-padding-vertical) var(--layout-padding-horizontal);
padding: 0 var(--layout-padding-horizontal);
margin: var(--layout-padding-vertical) 0;
box-sizing: border-box;
--padding-x: 8px;
&__header {
font-size: 16px;
font-weight: 600;
@ -14,7 +15,7 @@
letter-spacing: -0.01em;
margin-bottom: 12px;
padding: 0 6px;
padding: 0 var(--padding-x);
}
&__list {
@ -27,7 +28,7 @@
list-style: none;
gap: 6px;
gap: 2px;
&-item {
@apply --squircle;
@ -47,7 +48,7 @@
&--indent-4x { margin-left: 24px; }
& > a {
padding: 4px 8px;
padding: 4px var(--padding-x);
display: block;
font-size: 14px;
letter-spacing: -0.01em;

View file

@ -52,25 +52,46 @@
}
.writing-editor {
font-size: 15px;
line-height: 1.6;
letter-spacing: 0.005em;
@apply --text-content-main;
.ce-code__textarea {
color: #41314e;
line-height: 1.6em;
font-size: 12px;
background: var(--color-bg-light);
border: 1px solid #f1f1f4;
box-shadow: none;
@apply --text-code-block;
border: 0;
border-radius: 8px;
}
.ce-paragraph a {
color: inherit;
@apply --text-inline-link;
}
.ce-header {
@apply --font-serif;
@apply --text-header;
padding: 0;
}
h2.ce-header {
@apply --text-header-2;
}
h3.ce-header {
@apply --text-header-3;
}
.cdx-block {
padding: 0;
}
.inline-code {
@apply --text-inline-code;
}
.tc-table {
@apply --text-content-main;
}
.tc-cell {
padding: 6px 8px;
}
.ce-block__content {
@ -79,5 +100,12 @@
}
.codex-editor__redactor .ce-block:first-of-type .ce-header {
font-size: 32px;
@apply --text-content-title;
}
.ce-block {
@apply --content-block;
}

View file

@ -2,27 +2,23 @@
display: inline-block;
width: 100%;
span {
color: inherit !important;
}
&--added {
color: #277030;
background-color: #e2fce7;
color: #70b979;
background-color: #25f84d21;
&::before {
content: '+';
opacity: 0.4;
opacity: 0.8;
}
}
&--removed {
color: rgb(174, 54, 60);
background-color: rgba(255, 230, 230, 1);
color: #f1acaf;
background-color: #95000069;
&::before {
content: '-';
opacity: 0.4;
opacity: 0.8;
}
}
}

View file

@ -8,6 +8,7 @@
@import './components/page.pcss';
@import './components/landing.pcss';
@import './components/auth.pcss';
@import './components/error.pcss';
@import './components/button.pcss';
@import './components/sidebar.pcss';
@import './components/navigator.pcss';

View file

@ -1,7 +1,6 @@
:root {
--color-text-main: #313649;
--color-text-second: #5d6068;
--color-direction-navigation: #717682;
--color-text-main: #060C26;
--color-text-second: #717682;
--color-line-gray: #E8E8EB;
--color-link-active: #2071cc;
--color-link-hover: #F3F6F8;
@ -10,6 +9,19 @@
--color-input-primary: #F3F6F8;
--color-input-border: #477CFF;
/* Code Block styles */
--color-code-bg: #252935;
--color-code-main: #E1EBFE;
--color-code-keyword: #ff6675;
--color-code-class: #bf9dff;
--color-code-variable: #69c6ff;
--color-code-string: #81bcff;
--color-code-params: #ffa259;
--color-code-tag: #74e59d;
--color-code-number: #ff6262;
--color-code-comment: #6c7f93;
--color-button-primary: #3389FF;
--color-button-primary-hover: #2E7AE6;
--color-button-primary-active: #296DCC;
@ -44,11 +56,6 @@
--font-mono: Menlo,Monaco,Consolas,Courier New,monospace;
--font-serif {
font-family: "Lucida Grande","Lucida Sans Unicode","Lucida Sans", Geneva, Arial, sans-serif;
letter-spacing: -0.03em;
}
--button {
display: inline-block;
padding: 9px 15px;
@ -131,6 +138,120 @@
-webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 10.3872C0 1.83334 1.83334 0 10.3872 0H13.6128C22.1667 0 24 1.83334 24 10.3872V13.6128C24 22.1667 22.1667 24 13.6128 24H10.3872C1.83334 24 0 22.1667 0 13.6128V10.3872Z' fill='black'/%3E%3C/svg%3E%0A") 48% 41% 37.9% 53.3%;;
}
}
/**
* The common styles for the Page blocks as well as Editor blocks
*/
--content-block {
padding: 10px 0;
}
/**
* Main page H1 title
*/
--text-content-title {
font-size: 36px;
font-weight: 800;
margin: 0;
}
/**
* Page body font
*/
--text-content-main {
font-size: 16px;
line-height: 150%;
}
/**
* Code on page and in the Editor
*/
--text-code-block {
background: var(--color-code-bg);
color: var(--color-code-main);
font-family: var(--font-mono);
line-height: 1.5em;
font-size: 13px;
overflow-x: auto;
}
/**
* Common styles for text headings (H2, H3, H4)
*/
--text-header {
margin: 18px 0 0;
line-height: 1.35em;
}
/**
* Styles for the H2 at the Page and Editor
*/
--text-header-2 {
font-size: 24px;
font-weight: 700;
}
/**
* Styles for the H3 at the Page and Editor
*/
--text-header-3 {
font-size: 18px;
font-weight: 700;
}
/**
* Styles for the inline code element at the Page and Editor
*/
--text-inline-code {
display: inline-block;
background: rgba(251,241,241,0.78);
color: #C44545;
font-size: 14px;
line-height: 1.4em;
letter-spacing: 0;
padding: 3px 4px 2px;
margin: -1px 2px 0;
font-family: var(--font-mono);
font-size: 0.84em;
border-bottom: 0;
&:hover {
background: rgba(251,241,241,0.78);
}
}
/**
* Styles for regular links inside a text
*/
--text-inline-link {
text-decoration: none;
border-bottom: 1px solid #000;
padding-bottom: 1px;
color: inherit;
&:hover {
color: var(--color-link-active);
border-bottom-color: var(--color-link-active);
}
/**
* When a link contain an inline code, highlight it by its own way
*/
.inline-code {
margin: 0;
padding: 2px 5px;
border-bottom: 1px dashed rgba(84, 151, 255, 0.99);
color: #1f6fd8;
background-color: #daf1fe;
border-radius: 3px !important;
&:hover {
background-color: #c8edfe;
}
}
}
}
/**
@ -140,5 +261,6 @@
@custom-media --desktop all and (min-width: 1050px);
@custom-media --tablet all and (min-width: 980px) and (max-width: 1050px);
@custom-media --mobile all and (max-width: 980px);
@custom-media --not-mobile all and (min-width: 981px);
@custom-media --retina all and (-webkit-min-device-pixel-ratio: 1.5);
@custom-media --can-hover all and (hover:hover);

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

@ -0,0 +1 @@
<svg width="21" height="20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.037 6.08a.833.833 0 0 0 0 1.175l2.95 2.992-2.95 2.95a.833.833 0 1 0 1.183 1.175l3.533-3.534a.832.832 0 0 0 0-1.183L9.22 6.08a.833.833 0 0 0-1.183 0Z" fill="#717682"/></svg>

After

Width:  |  Height:  |  Size: 260 B

View file

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

View file

@ -1,7 +1,7 @@
import chaiHTTP from 'chai-http';
import chai, { expect } from 'chai';
import server from '../bin/server';
import server from '../bin/server.js';
const app = server.app;
@ -16,4 +16,4 @@ describe('Express app', () => {
expect(result).to.have.status(200);
});
});
});

View file

@ -2,12 +2,20 @@ import { expect } from 'chai';
import fs from 'fs';
import path from 'path';
import config from 'config';
import Alias from '../../backend/models/alias';
import { binaryMD5 } from '../../backend/utils/crypto';
import database from '../../backend/utils/database';
import Alias from '../../backend/models/alias.js';
import { binaryMD5 } from '../../backend/utils/crypto.js';
import database from '../../backend/utils/database/index.js';
import { fileURLToPath } from 'url';
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', () => {
after(() => {
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 path from 'path';
import config from 'config';
import File from '../../backend/models/file';
import database from '../../backend/utils/database';
import File from '../../backend/models/file.js';
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'];
@ -159,9 +167,9 @@ describe('File model', () => {
if (savedFile._id !== undefined){
const foundFile = await File.get(savedFile._id);
const { data } = foundFile;
expect(data._id).to.equal(savedFile._id);
expect(data.name).to.equal(savedFile.name);
expect(data.filename).to.equal(savedFile.filename);
@ -188,9 +196,9 @@ describe('File model', () => {
if (savedFile.filename !== undefined){
const foundFile = await File.getByFilename(savedFile.filename);
const { data } = foundFile;
expect(data._id).to.equal(savedFile._id);
expect(data.name).to.equal(savedFile.name);
expect(data.filename).to.equal(savedFile.filename);

View file

@ -2,9 +2,17 @@ import { expect } from 'chai';
import fs from 'fs';
import path from 'path';
import config from 'config';
import Page from '../../backend/models/page';
import translateString from '../../backend/utils/translation';
import database from '../../backend/utils/database';
import Page from '../../backend/models/page.js';
import translateString from '../../backend/utils/translation.js';
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'];

View file

@ -2,8 +2,16 @@ import { expect } from 'chai';
import fs from 'fs';
import path from 'path';
import config from 'config';
import PageOrder from '../../backend/models/pageOrder';
import database from '../../backend/utils/database';
import PageOrder from '../../backend/models/pageOrder.js';
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'];

View file

@ -4,7 +4,7 @@ import path from 'path';
import config from 'config';
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'));

View file

@ -3,7 +3,15 @@ import path from 'path';
import config from 'config';
import chai from 'chai';
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 app = server.app;

View file

@ -3,11 +3,20 @@ import path from 'path';
import config from 'config';
import chai from 'chai';
import chaiHTTP from 'chai-http';
import server from '../../bin/server';
import model from '../../backend/models/page';
import Page from '../../backend/models/page';
import PageOrder from '../../backend/models/pageOrder';
import translateString from '../../backend/utils/translation';
import server from '../../bin/server.js';
import model from '../../backend/models/page.js';
import Page from '../../backend/models/page.js';
import PageOrder from '../../backend/models/pageOrder.js';
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 app = server.app;
@ -516,7 +525,7 @@ describe('Pages REST: ', () => {
page6 = await Page.get(pages[6]);
expect(page6.data._id).to.be.undefined;
page7 = await Page.get(pages[7]);
expect(page7.data._id).to.be.undefined;

View file

@ -5,8 +5,17 @@ import chai from 'chai';
import chaiHTTP from 'chai-http';
import rimraf from 'rimraf';
import config from 'config';
import server from '../../bin/server';
import model from '../../backend/models/file';
import server from '../../bin/server.js';
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 app = server.app;
@ -119,7 +128,7 @@ describe('Transport routes: ', () => {
if (file.path !== undefined){
const getRes = await agent
.get(file.path);
expect(getRes).to.have.status(200);
expect(getRes).to.have.header('content-type', new RegExp(`^${file.mimetype}`));
}
@ -170,7 +179,7 @@ describe('Transport routes: ', () => {
if (file.path !== undefined){
const getRes = await agent
.get(file.path);
expect(getRes).to.have.status(200);
expect(getRes).to.have.header('content-type', file.mimetype);
}

View file

@ -4,9 +4,11 @@
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "ES2015", /* 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'. */
// "lib": [], /* Specify library files to be included in the compilation. */
"target": "ES2021", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', 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. */
"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. */
// "checkJs": true, /* Report errors in .js files. */
// "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. */
/* 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. */
// "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. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "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. */
"types": [ /* Type declaration files to be included in compilation. */
"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'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
@ -69,5 +74,12 @@
"skipLibCheck": true, /* Skip type checking of declaration files. */
"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');
const path = require('path');
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
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
@ -22,7 +29,7 @@ const babelLoader = {
},
};
module.exports = () => {
export default () => {
return {
entry: './src/frontend/js/app.js',
output: {
@ -53,9 +60,18 @@ module.exports = () => {
loader: 'postcss-loader',
},
],
}, {
},
{
test: /\.js$/,
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: [
babelLoader,
],

2492
yarn.lock

File diff suppressed because it is too large Load diff