1
0
Fork 0
mirror of https://github.com/codex-team/codex.docs.git synced 2025-07-19 05:09:41 +02:00

Landing + mobile adoptation (#38)

* Landing + mobile adoptation

* replace svg

* small updates

* use landing as iframe

* Delete .codexdocsrc

* remove unused

* updates

* Delete _index.twig

* update header shrink in chrome

* Delete .codexdocsrc

* remove focus
This commit is contained in:
Peter Savchenko 2019-02-15 17:56:56 +03:00 committed by GitHub
parent d1e48cbb64
commit 044c24c950
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 429 additions and 1068 deletions

View file

@ -23,14 +23,14 @@ class Docs {
* @constructor
*/
constructor() {
console.log('CodeX Docs initialized');
this.writing = new Writing();
this.page = new Page();
document.addEventListener('DOMContentLoaded', (event) => {
this.docReady();
});
console.log('CodeX Docs initialized');
}
/**

View file

@ -1,9 +1,18 @@
import CodeXEditor from 'codex.editor';
/**
* Tools for the Editor
*/
import Header from 'codex.editor.header';
import CodeTool from 'codex.editor.code';
import InlineCode from 'codex.editor.inline-code';
import Quote from 'codex.editor.quote';
import Marker from 'codex.editor.marker';
import ListTool from 'codex.editor.list';
import CodeTool from 'codex.editor.code';
import Delimiter from 'codex.editor.delimiter';
import InlineCode from 'codex.editor.inline-code';
import List from 'codex.editor.list';
import RawTool from 'codex.editor.raw';
import ImageTool from 'codex.editor.image';
import Embed from 'codex.editor.embed';
/**
* Class for working with Editor.js
@ -11,32 +20,59 @@ import ListTool from 'codex.editor.list';
export default class Editor {
/**
* Creates Editor instance
* @property {object} initialData - data to start with
* @param {object} editorConfig - configuration object for Editor.js
* @param {object} data.blocks - data to start with
* @param {object} options
* @param {string} options.headerPlaceholder - placeholder for Header tool
*/
constructor({initialData}) {
this.editor = new CodeXEditor({
constructor(editorConfig = {}, options = {}) {
const defaultConfig = {
tools: {
header: {
class: Header,
inlineToolbar: ['link', 'marker'],
config: {
placeholder: 'Enter a title'
placeholder: options.headerPlaceholder || ''
}
},
code: CodeTool,
// image: {
// class: ImageTool,
// inlineToolbar: true,
// config: {
// endpoints: {
// byFile: '/editor/transport',
// byUrl: '/editor/transport'
// }
// }
// },
list: {
class: List,
inlineToolbar: true
},
quote: {
class: Quote,
inlineToolbar: true
},
code: {
class: CodeTool,
shortcut: 'CMD+SHIFT+D'
},
inlineCode: {
class: InlineCode,
shortcut: 'CMD+SHIFT+I'
shortcut: 'CMD+SHIFT+C'
},
Marker: {
rawTool: {
class: RawTool,
shortcut: 'CMD+SHIFT+R'
},
marker: {
class: Marker,
shortcut: 'CMD+SHIFT+M'
},
list: {
class: ListTool,
inlineToolbar: true
}
delimiter: Delimiter,
embed: Embed
},
data: initialData || {
data: {
blocks: [
{
type: 'header',
@ -47,7 +83,9 @@ export default class Editor {
}
]
}
});
};
this.editor = new CodeXEditor(Object.assign(defaultConfig, editorConfig));
}
/**

View file

@ -66,7 +66,7 @@ export default class Writing {
this.nodes.removeButton.addEventListener('click', () => {
const isUserAgree = confirm("Are you sure?");
if (!isUserAgree) {
return
return;
}
this.removeButtonClicked();
@ -85,8 +85,12 @@ export default class Writing {
async loadEditor() {
const {default: Editor} = await import(/* webpackChunkName: "editor" */ './../classes/editor');
return new Editor({
initialData: this.page ? this.page.body : null
const editorConfig = this.page ? {
data: this.page.body
} : {};
return new Editor(editorConfig, {
headerPlaceholder: 'Enter a title'
});
}

View file

@ -2,6 +2,16 @@
font-size: 15px;
color: var(--color-text-second);
@media (--mobile) {
font-size: 13px;
display: none;
margin-top: 20px;
}
&--toggled {
display: block !important;
}
a {
text-decoration: none;
}
@ -9,9 +19,21 @@
&__section {
margin-bottom: 30px;
@media (--mobile) {
margin-bottom: 20px;
}
&:last-of-type {
margin-bottom: 0;
}
&-title {
margin-bottom: 15px;
color: var(--color-link-active);
@media (--mobile) {
margin-bottom: 10px;
}
}
&-list {
@ -26,3 +48,18 @@
}
}
}
.docs-aside-toggler {
display: none;
font-size: 13px;
cursor: pointer;
color: var(--color-text-second);
@media (--mobile) {
display: block;
}
svg {
margin-right: 10px;
}
}

View file

@ -1,9 +1,12 @@
.docs-header {
display: flex;
flex-shrink: 0;
padding: 0 var(--layout-padding-horisontal);
border-bottom: 1px solid var(--color-line-gray);
font-size: 15.8px;
line-height: 50px;
flex-wrap: wrap;
position: relative;
a {
display: inline-block;
@ -18,10 +21,40 @@
&__menu {
display: flex;
margin: 0 0 0 auto;
padding-left: 0;
@media (--mobile) {
flex-basis: 100%;
font-size: 12px;
}
li {
display: inline-flex;
align-items: center;
list-style: none;
margin-left: 20px;
@media (--mobile) {
margin-left: 0;
margin-right: 15px;
}
}
&-add {
@media (--mobile) {
position: absolute;
right: 15px;
top: 15px;
line-height: 1em;
margin: 0 !important;
}
a {
@media (--mobile) {
font-size: 0;
padding: 8px;
margin-right: 0;
}
}
}
a:not(.docs-header__button) {

View file

@ -0,0 +1,30 @@
/**
* Index page landing iframe
*/
.landing-body {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.landing-loader {
position: absolute;
left: 50%;
top: 50%;
z-index: -1;
transform: translate(-50%, -50%);
& > svg {
width: 80px;
height: 80px;
}
}
.landing-frame {
width: 100%;
height: 100%;
opacity: 0;
transition: opacity 500ms ease;
will-change: opacity;
}

View file

@ -6,10 +6,18 @@
display: flex;
color: var(--color-text-second);
@media (--mobile) {
font-size: 13px;
}
&-nav {
color: inherit;
text-decoration: none;
@media (--mobile) {
display: none;
}
&:hover {
color: var(--color-link-active);
}
@ -24,6 +32,10 @@
&-time {
margin-left: auto;
@media (--mobile) {
margin-left: 0;
}
}
&-button {

View file

@ -2,14 +2,31 @@
display: flex;
padding: 0 var(--layout-padding-horisontal);
@media (--mobile) {
flex-wrap: wrap;
}
&__aside {
width: var(--layout-width-aside);
@media (--mobile) {
width: 100%;
flex-basis: 100%;
padding: 20px var(--layout-padding-horisontal) !important;
margin: 0 calc(-1 * var(--layout-padding-horisontal));
border-bottom: 1px solid var(--color-line-gray);
}
}
&__content {
flex-grow: 2;
word-wrap: break-word;
@media (--mobile) {
width: 100%;
flex-basis: 100%;
}
&-inner {
max-width: var(--layout-width-main-col);
margin: 0 auto;
@ -19,5 +36,9 @@
&__aside,
&__content {
padding: var(--layout-padding-vertical) 0;
@media (--mobile) {
padding: 20px 0;
}
}
}

View file

@ -5,6 +5,7 @@
@import url('components/aside.pcss');
@import url('components/writing.pcss');
@import url('components/page.pcss');
@import url('components/landing.pcss');
body {
font-family: system-ui, Helvetica, Arial, Verdana;

View file

@ -14,6 +14,11 @@
--layout-width-aside: 200px;
--layout-width-main-col: 650px;
@media (--mobile) {
--layout-padding-horisontal: 15px;
--layout-padding-vertical: 15px;
}
--button {
display: inline-block;
padding: 9px 15px;
@ -25,6 +30,7 @@
line-height: 1em;
text-decoration: none;
cursor: pointer;
white-space: nowrap;
svg {
margin: 0 0.3em 0 -0.05em;
@ -51,3 +57,11 @@
}
}
}
/**
* Custom media queries
*/
@custom-media --desktop all and (min-width: 1050px);
@custom-media --tablet all and (max-width: 1050px);
@custom-media --mobile all and (max-width: 980px);
@custom-media --retina all and (-webkit-min-device-pixel-ratio: 1.5);

View file

@ -0,0 +1,60 @@
<svg class="ldi-zbvw97" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 80 80" preserveAspectRatio="xMidYMid">
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80" style="transform-origin:50px 50px 0">
<g style="transform-origin:50px 50px 0">
<g style="transform-origin:50px 50px 0;transform:scale(.6)">
<g style="transform-origin:50px 50px 0">
<style>
.st3{fill:#dff0fc}
.st5{fill:#69cdff}
</style>
<g style="transform-origin:50px 50px 0">
<g class="ld ld-spin" style="transform-origin:50px 50px 0;animation-duration:1.4s;animation-delay:-1.346153846153846s;animation-direction:normal">
<path class="st3" d="M69.4 28.7c-3-2.8-6.5-4.8-10.3-6-4.6-1.5-7.7-5.8-7.7-10.6V7.5c4.9.2 9.7 1.1 14.2 2.9 7.4 2.9 9.5 12.6 3.8 18.3z" fill="#dff0fc"/>
</g>
</g>
<g style="transform-origin:50px 50px 0">
<g class="ld ld-spin" style="transform-origin:50px 50px 0;animation-duration:1.4s;animation-delay:-1.2923076923076924s;animation-direction:normal">
<path class="st5" d="M33 11c-4.4 1.9-8.5 4.6-12.1 8l3.2 3.2c3.4 3.4 8.6 4.2 12.9 2.1 3.6-1.8 7.5-2.8 11.6-3 0-8.1-8.2-13.5-15.6-10.3z" fill="#69cdff"/>
</g>
</g>
<g style="transform-origin:50px 50px 0">
<g class="ld ld-spin" style="transform-origin:50px 50px 0;animation-duration:1.4s;animation-delay:-1.2384615384615383s;animation-direction:normal">
<path class="st3" d="M10.4 34.4c-1.8 4.5-2.7 9.3-2.9 14.2H12c4.8 0 9.1-3.1 10.6-7.7 1.3-3.8 3.3-7.3 6.1-10.3-5.7-5.7-15.4-3.6-18.3 3.8z" fill="#dff0fc"/>
</g>
</g>
<g style="transform-origin:50px 50px 0">
<g class="ld ld-spin" style="transform-origin:50px 50px 0;animation-duration:1.4s;animation-delay:-1.1846153846153846s;animation-direction:normal">
<path class="st5" d="M11 67c1.9 4.4 4.6 8.5 8 12.1l3.2-3.2c3.4-3.4 4.2-8.6 2.1-12.9-1.8-3.6-2.8-7.5-3-11.6-8.1 0-13.5 8.2-10.3 15.6z" fill="#69cdff"/>
</g>
</g>
<g style="transform-origin:50px 50px 0">
<g class="ld ld-spin" style="transform-origin:50px 50px 0;animation-duration:1.4s;animation-delay:-1.1307692307692307s;animation-direction:normal">
<path class="st5" d="M89 33c-1.9-4.4-4.6-8.5-8-12.1l-3.2 3.2c-3.4 3.4-4.2 8.6-2.1 12.9 1.8 3.6 2.8 7.5 3 11.6 8.1 0 13.5-8.2 10.3-15.6z" fill="#69cdff"/>
</g>
</g>
<g style="transform-origin:50px 50px 0">
<g class="ld ld-spin" style="transform-origin:50px 50px 0;animation-duration:1.4s;animation-delay:-1.0769230769230769s;animation-direction:normal">
<path class="st3" d="M89.6 65.6c1.8-4.5 2.7-9.3 2.9-14.2H88c-4.8 0-9.1 3.1-10.6 7.7-1.3 3.8-3.3 7.3-6.1 10.3 5.7 5.7 15.4 3.6 18.3-3.8z" fill="#dff0fc"/>
</g>
</g>
<g style="transform-origin:50px 50px 0">
<g class="ld ld-spin" style="transform-origin:50px 50px 0;animation-duration:1.4s;animation-delay:-1.023076923076923s;animation-direction:normal">
<path class="st5" d="M67 89c4.4-1.9 8.5-4.6 12.1-8l-3.2-3.2c-3.4-3.4-8.6-4.2-12.9-2.1-3.6 1.8-7.5 2.8-11.6 3 0 8.1 8.2 13.5 15.6 10.3z" fill="#69cdff"/>
</g>
</g>
<g style="transform-origin:50px 50px 0">
<g class="ld ld-spin" style="transform-origin:50px 50px 0;animation-duration:1.4s;animation-delay:-.9692307692307691s;animation-direction:normal">
<path class="st3" d="M34.4 89.6c4.5 1.8 9.3 2.7 14.2 2.9V88c0-4.8-3.1-9.1-7.7-10.6-3.8-1.3-7.3-3.3-10.3-6.1-5.7 5.7-3.6 15.4 3.8 18.3z" fill="#dff0fc"/>
</g>
</g>
</g>
</g>
</g>
<style>
.ld-spin {
will-change: transform;
}
@keyframes ld-spin{0%{-webkit-transform:rotate(0);transform:rotate(0);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}50%{-webkit-transform:rotate(180deg);transform:rotate(180deg);animation-timing-function:cubic-bezier(.215,.61,.355,1)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes ld-spin{0%{-webkit-transform:rotate(0);transform:rotate(0);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}50%{-webkit-transform:rotate(180deg);transform:rotate(180deg);animation-timing-function:cubic-bezier(.215,.61,.355,1)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}path{stroke-width:0}.ld.ld-spin{-webkit-animation:ld-spin 1s infinite;animation:ld-spin 1s infinite}
</style>
</svg>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -0,0 +1 @@
<svg width="13" height="10" viewBox="0 0 13 10" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h13v2H0V0zm0 4h13v2H0V4zm0 4h13v2H0V8z" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 164 B

View file

@ -1,4 +1,4 @@
const {aliases: aliasesDb} = require('../utils/database/index');
const { aliases: aliasesDb } = require('../utils/database/index');
const binaryMD5 = require('../utils/crypto');
/**
@ -40,10 +40,10 @@ class Alias {
*/
static async get(aliasName) {
const hash = binaryMD5(aliasName);
let data = await aliasesDb.findOne({hash: hash, deprecated: false});
let data = await aliasesDb.findOne({ hash: hash, deprecated: false });
if (!data) {
data = await aliasesDb.findOne({hash: hash});
data = await aliasesDb.findOne({ hash: hash });
}
return new Alias(data);
@ -79,7 +79,7 @@ class Alias {
this._id = insertedRow._id;
} else {
await aliasesDb.update({_id: this._id}, this.data);
await aliasesDb.update({ _id: this._id }, this.data);
}
return this;
@ -91,7 +91,7 @@ class Alias {
* @param {AliasData} aliasData
*/
set data(aliasData) {
const {id, type, hash, deprecated} = aliasData;
const { id, type, hash, deprecated } = aliasData;
this.id = id || this.id;
this.type = type || this.type;
@ -131,7 +131,7 @@ class Alias {
* @returns {Promise<Alias>}
*/
async destroy() {
await aliasesDb.remove({_id: this._id});
await aliasesDb.remove({ _id: this._id });
delete this._id;

View file

@ -1,4 +1,4 @@
const {pages: pagesDb} = require('../utils/database/index');
const { pages: pagesDb } = require('../utils/database/index');
const translateString = require('../utils/translation');
/**
@ -27,7 +27,7 @@ class Page {
* @returns {Promise<Page>}
*/
static async get(_id) {
const data = await pagesDb.findOne({_id});
const data = await pagesDb.findOne({ _id });
return new Page(data);
}
@ -38,7 +38,7 @@ class Page {
* @returns {Promise<Page>}
*/
static async getByUri(uri) {
const data = await pagesDb.findOne({uri});
const data = await pagesDb.findOne({ uri });
return new Page(data);
}
@ -78,7 +78,7 @@ class Page {
* @param {PageData} pageData
*/
set data(pageData) {
const {body, parent, uri} = pageData;
const { body, parent, uri } = pageData;
this.body = body || this.body;
this.title = this.extractTitleFromBody();
@ -141,7 +141,7 @@ class Page {
* @returns {Promise<Page>}
*/
get parent() {
return pagesDb.findOne({_id: this._parent})
return pagesDb.findOne({ _id: this._parent })
.then(data => new Page(data));
}
@ -151,7 +151,7 @@ class Page {
* @returns {Promise<Page[]>}
*/
get children() {
return pagesDb.find({parent: this._id})
return pagesDb.find({ parent: this._id })
.then(data => data.map(page => new Page(page)));
}
@ -168,7 +168,7 @@ class Page {
this._id = insertedRow._id;
} else {
await pagesDb.update({_id: this._id}, this.data);
await pagesDb.update({ _id: this._id }, this.data);
}
return this;
@ -180,7 +180,7 @@ class Page {
* @returns {Promise<Page>}
*/
async destroy() {
await pagesDb.remove({_id: this._id});
await pagesDb.remove({ _id: this._id });
delete this._id;

View file

@ -1,4 +1,4 @@
const {pagesOrder: db} = require('../utils/database/index');
const { pagesOrder: db } = require('../utils/database/index');
/**
* @typedef {Object} PageOrderData
@ -21,7 +21,7 @@ class PageOrder {
* @returns {PageOrder}
*/
static async get(pageId) {
const order = await db.findOne({page: pageId});
const order = await db.findOne({ page: pageId });
let data = {};
@ -172,7 +172,7 @@ class PageOrder {
this._id = insertedRow._id;
} else {
await db.update({_id: this._id}, this.data);
await db.update({ _id: this._id }, this.data);
}
return this;
@ -182,7 +182,7 @@ class PageOrder {
* Remove page data from the database
*/
async destroy() {
await db.remove({_id: this._id});
await db.remove({ _id: this._id });
delete this._id;

View file

@ -3,7 +3,7 @@ const router = express.Router();
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('index', { title: 'Express' });
res.render('pages/index');
});
module.exports = router;
module.exports = router;

View file

@ -40,8 +40,8 @@ module.exports = class RCParser {
return RCParser.DEFAULTS;
}
const file = fs.readFileSync(rcPath, {encoding: 'UTF-8'});
const rConfig = {};
const file = fs.readFileSync(rcPath, { encoding: 'UTF-8' });
const rConfig = RCParser.DEFAULTS;
let userConfig;
try {
@ -51,8 +51,11 @@ module.exports = class RCParser {
return RCParser.DEFAULTS;
}
rConfig.title = userConfig.title || RCParser.DEFAULTS.title;
rConfig.menu = userConfig.menu || RCParser.DEFAULTS.menu;
for (let option in userConfig) {
if (userConfig.hasOwnProperty(option)) {
rConfig[option] = userConfig[option] || RCParser.DEFAULTS[option] || undefined;
}
}
if (!(rConfig.menu instanceof Array)) {
console.log('Menu section in the rc file must be an array.');
@ -70,7 +73,7 @@ module.exports = class RCParser {
return false;
}
const {title, uri} = option;
const { title, uri } = option;
if (!title || typeof title !== 'string') {
console.log(`Menu option #${i} title must be a string.`);

View file

@ -1,3 +1,6 @@
<div class="docs-aside-toggler" onclick="document.querySelector('.docs-aside').classList.toggle('docs-aside--toggled')">
{{ svg('menu') }} Table of contents
</div>
<div class="docs-aside">
{% for firstLevelPage in menu %}
<section class="docs-aside__section">

View file

@ -3,7 +3,7 @@
{{ config.title }}
</a>
<ul class="docs-header__menu">
<li>
<li class="docs-header__menu-add">
<a class="docs-header__button" href="/page/new">
{{ svg('plus') }}
Add Page

View file

@ -1,6 +0,0 @@
{% extends 'layout.twig' %}
{% block body %}
{{title}}
<p>Welcome to {{title}}</p>
{% endblock %}

View file

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<title>{{ config.title }}</title>
<link rel="stylesheet" href="/dist/main.css" />
</head>
<body>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html style="height: 100%">
<head>
<title>{{ config.title }}</title>
<link rel="stylesheet" href="/dist/main.css" />
<link rel="preload" href="{{ config.landingFrameSrc }}" as="document">
</head>
<body class="landing-body">
{% include "components/header.twig" %}
<div class="landing-loader" id="frame-loader">
{{ svg('loader') }}
</div>
<iframe class="landing-frame" src="{{ config.landingFrameSrc }}" seamless frameborder="0" onload="this.style.opacity = 1; setTimeout(document.getElementById('frame-loader').remove(), 500)"></iframe>
</body>
</html>