mirror of
https://github.com/codex-team/codex.docs.git
synced 2025-07-22 14:49:41 +02:00
Compare commits
No commits in common. "main" and "v2.1.0" have entirely different histories.
10 changed files with 25 additions and 90 deletions
|
@ -12,7 +12,6 @@ It's super easy to install and use.
|
||||||
|
|
||||||
- 🤩 [Editor.js](https://editorjs.io/) ecosystem powered
|
- 🤩 [Editor.js](https://editorjs.io/) ecosystem powered
|
||||||
- 📂 Docs nesting — create any structure you need
|
- 📂 Docs nesting — create any structure you need
|
||||||
- 💎 Static rendering
|
|
||||||
- 📱 Nice look on Desktop and Mobile
|
- 📱 Nice look on Desktop and Mobile
|
||||||
- 🔥 Beautiful page URLs. Human-readable and SEO-friendly.
|
- 🔥 Beautiful page URLs. Human-readable and SEO-friendly.
|
||||||
- 🦅 [Hawk](https://hawk.so/?from=docs-demo) is hunting. Errors tracking integrated
|
- 🦅 [Hawk](https://hawk.so/?from=docs-demo) is hunting. Errors tracking integrated
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "codex.docs",
|
"name": "codex.docs",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"version": "2.2.3",
|
"version": "v2.0.0-rc.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
"codex.docs": "dist/backend/app.js"
|
"codex.docs": "dist/backend/app.js"
|
||||||
|
|
|
@ -13,7 +13,6 @@ import fse from 'fs-extra';
|
||||||
import appConfig from './utils/appConfig.js';
|
import appConfig from './utils/appConfig.js';
|
||||||
import Aliases from './controllers/aliases.js';
|
import Aliases from './controllers/aliases.js';
|
||||||
import Pages from './controllers/pages.js';
|
import Pages from './controllers/pages.js';
|
||||||
import { downloadFavicon } from './utils/downloadFavicon.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build static pages from database
|
* Build static pages from database
|
||||||
|
@ -46,42 +45,14 @@ export default async function buildStatic(): Promise<void> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.overwrite) {
|
console.log('Removing old static files');
|
||||||
console.log('Removing old static files');
|
await fse.remove(distPath);
|
||||||
await fse.remove(distPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Building static files');
|
console.log('Building static files');
|
||||||
const pagesOrder = await PagesOrder.getAll();
|
const pagesOrder = await PagesOrder.getAll();
|
||||||
const allPages = await Page.getAll();
|
const allPages = await Page.getAll();
|
||||||
|
|
||||||
try {
|
await mkdirp(distPath);
|
||||||
console.log('Create dist folder');
|
|
||||||
await mkdirp(distPath);
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Error while creating dist folder', e);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Copy public directory');
|
|
||||||
const publicDir = path.resolve(dirname, '../../public');
|
|
||||||
|
|
||||||
console.log(`Copy from ${publicDir} to ${distPath}`);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await fse.copy(publicDir, distPath);
|
|
||||||
console.log('Public directory copied');
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Error while copying public directory');
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
const favicon = appConfig.favicon ? await downloadFavicon(appConfig.favicon, distPath, '') : {
|
|
||||||
destination: '/favicon.png',
|
|
||||||
type: 'image/png',
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders single page
|
* Renders single page
|
||||||
|
@ -91,11 +62,6 @@ export default async function buildStatic(): Promise<void> {
|
||||||
*/
|
*/
|
||||||
async function renderPage(page: Page, isIndex?: boolean): Promise<void> {
|
async function renderPage(page: Page, isIndex?: boolean): Promise<void> {
|
||||||
console.log(`Rendering page ${page.uri}`);
|
console.log(`Rendering page ${page.uri}`);
|
||||||
const pageUri = page.uri;
|
|
||||||
|
|
||||||
if (!pageUri) {
|
|
||||||
throw new Error('Page uri is not defined');
|
|
||||||
}
|
|
||||||
const pageParent = await page.getParent();
|
const pageParent = await page.getParent();
|
||||||
const pageId = page._id;
|
const pageId = page._id;
|
||||||
|
|
||||||
|
@ -106,30 +72,16 @@ export default async function buildStatic(): Promise<void> {
|
||||||
const previousPage = await PagesFlatArray.getPageBefore(pageId);
|
const previousPage = await PagesFlatArray.getPageBefore(pageId);
|
||||||
const nextPage = await PagesFlatArray.getPageAfter(pageId);
|
const nextPage = await PagesFlatArray.getPageAfter(pageId);
|
||||||
const menu = createMenuTree(parentIdOfRootPages, allPages, pagesOrder, 2);
|
const menu = createMenuTree(parentIdOfRootPages, allPages, pagesOrder, 2);
|
||||||
|
|
||||||
const result = await renderTemplate('./views/pages/page.twig', {
|
const result = await renderTemplate('./views/pages/page.twig', {
|
||||||
page,
|
page,
|
||||||
pageParent,
|
pageParent,
|
||||||
previousPage,
|
previousPage,
|
||||||
nextPage,
|
nextPage,
|
||||||
menu,
|
menu,
|
||||||
favicon,
|
|
||||||
config: appConfig.frontend,
|
config: appConfig.frontend,
|
||||||
});
|
});
|
||||||
|
|
||||||
let filename: string;
|
const filename = (isIndex || page.uri === '') ? 'index.html' : `${page.uri}.html`;
|
||||||
|
|
||||||
if (isIndex) {
|
|
||||||
filename = 'index.html';
|
|
||||||
} else if (config?.pagesInsideFolders) { // create folder for each page if pagesInsideFolders is true
|
|
||||||
const pagePath = path.resolve(distPath, pageUri);
|
|
||||||
|
|
||||||
await mkdirp(pagePath);
|
|
||||||
|
|
||||||
filename = path.resolve(pagePath, 'index.html');
|
|
||||||
} else {
|
|
||||||
filename = `${page.uri}.html`;
|
|
||||||
}
|
|
||||||
|
|
||||||
await fs.writeFile(path.resolve(distPath, filename), result);
|
await fs.writeFile(path.resolve(distPath, filename), result);
|
||||||
console.log(`Page ${page.uri} rendered`);
|
console.log(`Page ${page.uri} rendered`);
|
||||||
|
@ -159,16 +111,15 @@ export default async function buildStatic(): Promise<void> {
|
||||||
await renderPage(page);
|
await renderPage(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if index page is enabled
|
await renderIndexPage(config.indexPageUri);
|
||||||
if (config.indexPage.enabled) {
|
|
||||||
await renderIndexPage(config.indexPage.uri);
|
|
||||||
}
|
|
||||||
console.log('Static files built');
|
console.log('Static files built');
|
||||||
|
|
||||||
|
console.log('Copy public directory');
|
||||||
|
await fse.copy(path.resolve(dirname, '../../public'), distPath);
|
||||||
|
|
||||||
if (appConfig.uploads.driver === 'local') {
|
if (appConfig.uploads.driver === 'local') {
|
||||||
console.log('Copy uploads directory');
|
console.log('Copy uploads directory');
|
||||||
await fse.copy(path.resolve(cwd, appConfig.uploads.local.path), path.resolve(distPath, 'uploads'));
|
await fse.copy(path.resolve(cwd, appConfig.uploads.local.path), path.resolve(distPath, 'uploads'));
|
||||||
console.log('Uploads directory copied');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,14 +90,7 @@ const FrontendConfig = z.object({
|
||||||
*/
|
*/
|
||||||
const StaticBuildConfig = z.object({
|
const StaticBuildConfig = z.object({
|
||||||
outputDir: z.string(), // Output directory for static build
|
outputDir: z.string(), // Output directory for static build
|
||||||
overwrite: z.boolean().optional() // Overwrite output directory
|
indexPageUri: z.string(), // URI for index page to render
|
||||||
.default(true),
|
|
||||||
pagesInsideFolders: z.boolean().optional() // Create separate folder for each page
|
|
||||||
.default(true),
|
|
||||||
indexPage: z.object({
|
|
||||||
enabled: z.boolean(), // Is index page enabled
|
|
||||||
uri: z.string(), // Index page uri
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type StaticBuildConfig = z.infer<typeof StaticBuildConfig>;
|
export type StaticBuildConfig = z.infer<typeof StaticBuildConfig>;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs';
|
||||||
import fetch, { RequestInit } from 'node-fetch';
|
import fetch, { RequestInit } from 'node-fetch';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,10 +32,9 @@ function checkIsUrl(str: string): boolean {
|
||||||
*
|
*
|
||||||
* @param destination - url or path of favicon
|
* @param destination - url or path of favicon
|
||||||
* @param faviconFolder - folder to save favicon
|
* @param faviconFolder - folder to save favicon
|
||||||
* @param subRoute - subroute from which the favicon will be served
|
|
||||||
* @returns { Promise<FaviconData> } - Promise with data about favicon
|
* @returns { Promise<FaviconData> } - Promise with data about favicon
|
||||||
*/
|
*/
|
||||||
export async function downloadFavicon(destination: string, faviconFolder: string, subRoute = '/favicon'): Promise<FaviconData> {
|
export async function downloadFavicon(destination: string, faviconFolder: string): Promise<FaviconData> {
|
||||||
// Check of destination is empty
|
// Check of destination is empty
|
||||||
if (!destination) {
|
if (!destination) {
|
||||||
throw Error('Favicon destination is empty');
|
throw Error('Favicon destination is empty');
|
||||||
|
@ -49,10 +48,8 @@ export async function downloadFavicon(destination: string, faviconFolder: string
|
||||||
|
|
||||||
// Check if string is url
|
// Check if string is url
|
||||||
if (!checkIsUrl(destination)) {
|
if (!checkIsUrl(destination)) {
|
||||||
await fs.copyFile(destination, path.join(faviconFolder, filename));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
destination: `${subRoute}/${filename}`,
|
destination: `/${filename}`,
|
||||||
type: `image/${format}`,
|
type: `image/${format}`,
|
||||||
} as FaviconData;
|
} as FaviconData;
|
||||||
}
|
}
|
||||||
|
@ -75,10 +72,14 @@ export async function downloadFavicon(destination: string, faviconFolder: string
|
||||||
const filePath = path.join(faviconFolder, `favicon.${format}`);
|
const filePath = path.join(faviconFolder, `favicon.${format}`);
|
||||||
|
|
||||||
// Save file
|
// Save file
|
||||||
await fs.writeFile(filePath, fileData);
|
await fs.writeFile(filePath, fileData, (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
destination: `${subRoute}/favicon.${format}`,
|
destination: `/favicon/favicon.${format}`,
|
||||||
type: `image/${format}`,
|
type: `image/${format}`,
|
||||||
} as FaviconData;
|
} as FaviconData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="block-code__content">{{ code | escape }}</div>
|
<div class="block-code__content">{{ code | escape }}</div>
|
||||||
</div>
|
</div>
|
||||||
{%
|
{%
|
||||||
include '../../components/copy-button.twig' with {
|
include 'components/copy-button.twig' with {
|
||||||
ariaLabel: 'Copy Code to Clipboard',
|
ariaLabel: 'Copy Code to Clipboard',
|
||||||
class: 'block-code__copy-button',
|
class: 'block-code__copy-button',
|
||||||
textToCopy: code | escape,
|
textToCopy: code | escape,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<h{{ level }} id="{{ text | urlify }}" class="block-header block-header--{{ level }}">
|
<h{{ level }} id="{{ text | urlify }}" class="block-header block-header--{{ level }}">
|
||||||
{%
|
{%
|
||||||
include '../../components/copy-button.twig' with {
|
include 'components/copy-button.twig' with {
|
||||||
ariaLabel: 'Copy Link to the ' ~ text,
|
ariaLabel: 'Copy Link to the ' ~ text,
|
||||||
class: 'block-header__copy-button',
|
class: 'block-header__copy-button',
|
||||||
textToCopy: '#' ~ text | urlify,
|
textToCopy: '#' ~ text | urlify,
|
||||||
|
|
|
@ -40,10 +40,7 @@ html {
|
||||||
|
|
||||||
@media (--not-mobile) {
|
@media (--not-mobile) {
|
||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
|
@apply --squircle;
|
||||||
&:hover {
|
|
||||||
@apply --squircle;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -182,16 +182,13 @@
|
||||||
transition-property: background-color;
|
transition-property: background-color;
|
||||||
transition-duration: 0.1s;
|
transition-duration: 0.1s;
|
||||||
|
|
||||||
|
@apply --squircle;
|
||||||
|
|
||||||
&--selected {
|
&--selected {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
/* border using box-shadow which doesn't increase the height */
|
/* border using box-shadow which doesn't increase the height */
|
||||||
box-shadow: 0 0 0 2px rgba(147, 166, 233, 0.5) inset;
|
box-shadow: 0 0 0 2px rgba(147, 166, 233, 0.5) inset;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--active,
|
|
||||||
&:hover {
|
|
||||||
@apply --squircle;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__section-title > span,
|
&__section-title > span,
|
||||||
|
|
|
@ -31,10 +31,7 @@
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
|
|
||||||
&-item {
|
&-item {
|
||||||
&:hover,
|
@apply --squircle;
|
||||||
&--active {
|
|
||||||
@apply --squircle;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-link-hover);
|
background-color: var(--color-link-hover);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue