diff --git a/.gitignore b/.gitignore index 48b8bf90..89c1bd78 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,26 @@ -vendor/ +# Libraries +/vendor +/node_modules +/npm-debug.log +/yarn-error.log + +# Configuration +/config/config.ini + +# Storage +/store/* +!/store/.gitkeep + +# OS specific +[Tt]humbs.db +[Dd]esktop.ini + +# IDE specific +.vscode/ +.vs/ +.idea/ + +# Compiled/copied assets +/public/js +/public/css +/assets/typescript/*.d.ts diff --git a/assets/less/nova/base.less b/assets/less/nova/base.less new file mode 100644 index 00000000..e110ae75 --- /dev/null +++ b/assets/less/nova/base.less @@ -0,0 +1,24 @@ +* { + margin: 0; + position: relative; + box-sizing: border-box; +} + +html, +body { + height: 100%; + font: @base-font-size "Exo 2", sans-serif; +} + +.fa { + font-family: inherit; + + &:before { + font-family: FontAwesome; + } +} + +// .turbolinks-progress-bar { +// height: 5px; +// background-color: green; +// } diff --git a/assets/less/nova/bem/auth.less b/assets/less/nova/bem/auth.less new file mode 100644 index 00000000..eb464d24 --- /dev/null +++ b/assets/less/nova/bem/auth.less @@ -0,0 +1,10 @@ +.auth { + &__avatar { + height: 100px; + width: 100px; + background: no-repeat center center / cover @grey-f; + border-radius: 100%; + box-shadow: 0 @global-shadow-distance @global-shadow-size fade(@grey-1, @global-shadow-opacity); + margin: 6px auto 10px; + } +} diff --git a/assets/less/nova/bem/banner.less b/assets/less/nova/bem/banner.less new file mode 100644 index 00000000..c301b018 --- /dev/null +++ b/assets/less/nova/bem/banner.less @@ -0,0 +1,25 @@ +.banner { + height: 150px; + margin-top: @general-spacing; + background: no-repeat center center / cover @grey-2; + box-shadow: 0 @global-shadow-distance @global-shadow-size fade(@grey-1, @global-shadow-opacity); + display: flex; + flex-flow: column-reverse; + + &--large { + height: 250px; + } + + &--insane { + height: 400px; + } + + &__bottom { + height: 60px; + background: fade(@grey-0, 80%); + display: inline-flex; + flex-flow: row; + align-items: center; + line-height: 1; + } +} diff --git a/assets/less/nova/bem/button.less b/assets/less/nova/bem/button.less new file mode 100644 index 00000000..7f0433c9 --- /dev/null +++ b/assets/less/nova/bem/button.less @@ -0,0 +1,21 @@ +.button { + color: @grey-f; + text-decoration: none; + border: 0; + border-radius: 2px; + font-size: 1.5em; + font-family: inherit; + width: 100%; + background: darken(@purple, 20%); + padding: @general-spacing; + margin-bottom: 8px; + box-shadow: 0 8px 2px darken(@purple, 22%); + cursor: pointer; + transition: margin-bottom .2s, margin-top .2s, box-shadow .2s; + + &:active { + margin-bottom: 2px; + margin-top: 6px; + box-shadow: 0 2px 2px darken(@purple, 22%); + } +} diff --git a/assets/less/nova/bem/container.less b/assets/less/nova/bem/container.less new file mode 100644 index 00000000..6439aaaa --- /dev/null +++ b/assets/less/nova/bem/container.less @@ -0,0 +1,35 @@ +.container { + min-height: 100%; + color: @grey-f; + background: url(@grid) @purple; + // no-repeat center center / cover + text-align: center; + + &__wrapper { + margin: 0 auto; + padding: @general-spacing; + max-width: @container-max-width; + padding-bottom: 59px; // oddly specific number but it works + } + + &__footer { + position: absolute; + bottom: 0; + left: 0; + right: 0; + font-size: .7em; + height: 60px; + padding-top: 20px; + background: linear-gradient(0deg, fade(@grey-0, 60%) 70%, fade(@grey-0, 70%) 80%, fade(@grey-0, 40%) 80%, transparent 90%) transparent; + + &-link { + color: inherit; + text-decoration: none; + margin: 0 @general-spacing; + + &:hover { + text-decoration: underline; + } + } + } +} diff --git a/assets/less/nova/bem/form.less b/assets/less/nova/bem/form.less new file mode 100644 index 00000000..c214f551 --- /dev/null +++ b/assets/less/nova/bem/form.less @@ -0,0 +1,52 @@ +.form { + &__text { + background: fade(@grey-0, 50%); + border: 0; + border-radius: 2px; + font-size: 1.5em; + margin-bottom: @general-spacing; + box-shadow: inset 0 @global-shadow-distance @global-inner-shadow-size fade(@grey-0, @global-shadow-opacity); + padding: @general-spacing; + color: @grey-f; + font-family: inherit; + width: 100%; + } + + &__status { + background: @grey-3; + margin: -@general-spacing; + margin-bottom: @general-spacing; + height: 40px; + display: flex; + align-items: center; + + &-icon { + width: 40px; + height: 40px; + background: fade(@grey-0, 50%); + font-family: FontAwesome; + display: inline-flex; + align-items: center; + justify-content: center; + + &:before { + content: "\f054"; + } + } + + &-text { + flex-grow: 1; + text-align: left; + padding: 0 (@general-spacing * 4); + font-size: .8em; + } + + &--fail { + background: @red; + + .form__status-icon:before { + content: "\f071"; + } + } + } +} diff --git a/assets/less/nova/bem/header.less b/assets/less/nova/bem/header.less new file mode 100644 index 00000000..61d09c09 --- /dev/null +++ b/assets/less/nova/bem/header.less @@ -0,0 +1,47 @@ +.header { + width: 100%; + background: @grey-2; + box-shadow: 0 @global-shadow-distance @global-shadow-size fade(@grey-1, @global-shadow-opacity); + height: @header-height; + line-height: @header-height - 6px; + font-size: @header-font-size; + text-shadow: 0 @text-shadow-distance @text-shadow-size fade(@grey-0, @text-shadow-opacity); + padding: 2px; + + &__inner { + max-width: @container-max-width; + margin: 0 auto; + + display: flex; + justify-content: space-between; + } + + &__entry { + padding-left: 12px; + text-decoration: none; + color: inherit; + + &:before { + font-family: FontAwesome; + padding-right: 5px; + } + } + + &__user { + display: inline-flex; + text-decoration: none; + color: inherit; + } + + &__username { + padding: 0 15px; + } + + &__avatar { + height: 46px; + width: 46px; + background: no-repeat center center / cover @grey-f; + border-radius: 1px; + box-shadow: 0 @global-shadow-distance @global-shadow-size fade(@grey-1, @global-shadow-opacity); + } +} diff --git a/assets/less/nova/bem/landing.less b/assets/less/nova/bem/landing.less new file mode 100644 index 00000000..db00f7b6 --- /dev/null +++ b/assets/less/nova/bem/landing.less @@ -0,0 +1,44 @@ +.landing { + text-shadow: 0 @text-shadow-distance @text-shadow-size fade(@grey-0, @text-shadow-opacity); + + &__banner, + &__inner { + display: flex; + flex-flow: row-reverse; + } + + &__text { + max-width: 300px; + } + + &__buttons { + max-width: 200px; + display: inline-flex; + flex-flow: column; + justify-content: center; + } + + &__inner, + &__buttons { + background: fade(@grey-0, 80%); + align-items: center; + height: 100%; + } + + &__text, + &__button { + padding: 0 (@general-spacing * 4); + } + + &__button { + color: inherit; + text-decoration: none; + cursor: pointer; + flex-grow: 1; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 2em; + width: 100%; + } +} diff --git a/assets/less/nova/bem/platform.less b/assets/less/nova/bem/platform.less new file mode 100644 index 00000000..3c0a4d7e --- /dev/null +++ b/assets/less/nova/bem/platform.less @@ -0,0 +1,11 @@ +.platform { + margin: @platform-margin; + background: no-repeat center center / cover @grey-2; + box-shadow: 0 @global-shadow-distance @global-shadow-size fade(@grey-1, @global-shadow-opacity); + padding: @general-spacing; + + &--thin { + margin: @platform-thin-margin; + display: inline-block; + } +} diff --git a/assets/less/nova/bem/profile.less b/assets/less/nova/bem/profile.less new file mode 100644 index 00000000..47f1cac5 --- /dev/null +++ b/assets/less/nova/bem/profile.less @@ -0,0 +1,130 @@ +.profile { + text-shadow: 0 @text-shadow-distance @text-shadow-size fade(@grey-0, @text-shadow-opacity); + + &__header { + padding-left: @avatar-big + (@general-spacing * 4); + padding-right: @general-spacing * 2; + } + + &__names { + flex-grow: 1; + text-align: left; + font-weight: 200; + } + + &__username { + font-size: @font-size--profile-username; + } + + &__title { + font-size: @font-size--profile-title; + } + + &__dates { + font-weight: 300; + text-align: right; + font-size: @font-size--profile-dates; + line-height: 1.3em; + } + + &__content { + display: flex; + flex-flow: row; + margin: 0 (@general-spacing * 2); + } + + &__container { + flex-grow: 1; + + &--left { + max-width: @avatar-big; + margin-right: @general-spacing; + top: -(@avatar-big - (@general-spacing * 2)); + } + } + + &__platform { + text-align: left; + margin: @general-spacing auto 0; + + &:empty { + display: none; + } + } + + &__avatar { + height: @avatar-big; + width: @avatar-big; + background: no-repeat center center / cover @grey-f; + border-radius: 1px; + box-shadow: 0 @global-shadow-distance @global-shadow-size fade(@grey-1, @global-shadow-opacity); + } + + &__hierarchies { + font-size: 1.8em; + font-style: italic; + font-weight: 200; + } + + &__hierarchy { + display: inline-flex; + align-items: center; + + &-icon { + font-family: FontAwesome; + font-style: normal; + padding-right: 5px; + color: @grey-f; + text-align: center; + width: 1.2em; + } + + &--founder { + color: #6c3082; + } + + &--staff { + color: #fa3703; + } + + &--developer { + color: #6eac0a; + } + + &--contributor { + color: #ff69b4; + } + + &--premium { + color: #ee9400; + } + + &--banned { + color: #888; + } + } + + &__accounts { + font-size: .9em; + } + + &__account { + display: flex; + line-height: 1.3em; + color: inherit; + text-decoration: none; + + &-text { + text-align: right; + flex-grow: 1; + font-style: italic; + font-weight: 200; + color: inherit; + } + + &-icon { + text-align: center; + font-family: FontAwesome; + } + } +} diff --git a/assets/less/nova/bem/status.less b/assets/less/nova/bem/status.less new file mode 100644 index 00000000..c808a50b --- /dev/null +++ b/assets/less/nova/bem/status.less @@ -0,0 +1,140 @@ +.status { + &__overall { + font-size: @font-size--status-overall; + font-weight: 100; + flex-grow: 1; + flex-shrink: 0; + text-align: left; + margin-left: @general-spacing * 4; + + &-icon { + font-family: FontAwesome; + } + + &-text { + font-style: italic; + } + + &--good { + .status__overall-icon:before { + content: "\f05d"; + } + } + } + + &__last-update { + align-self: flex-end; + margin: @general-spacing * 2; + font-size: @font-size--status-last-update; + } + + &__response { + display: flex; + } + + &__services { + display: flex; + flex-flow: column; + border-right: 1px solid @grey-1; + } + + &__service { + display: inline-flex; + padding: @general-spacing; + align-items: center; + line-height: 1; + + &-icon { + width: 40px; + height: 20px; + border-radius: 4px; + transform: skewX(-10deg); + background: #333; + margin-left: @general-spacing / 2; + box-shadow: 0 @global-shadow-distance @global-shadow-size fade(@grey-1, @global-shadow-opacity); + } + + &-name { + font-size: 24px; + text-align: right; + flex-grow: 1; + padding-left: @general-spacing * 10; + } + + &--selected { + background: @grey-1; + } + + &--good { + .status__service-icon { + background: @green; + } + } + + &--bad { + .status__service-icon { + background: @red; + } + } + } + + &__incident { + display: flex; + + &:not(:last-child) { + border-bottom: 1px solid @grey-1; + margin-bottom: @general-spacing; + padding-bottom: @general-spacing; + } + + &-date { + border-right: 1px solid @grey-1; + margin-right: @general-spacing; + padding: @general-spacing; + padding-left: 0; + font-size: @font-size--status-incident-date; + font-style: italic; + font-weight: 300; + min-width: 150px; + } + } + + &__update { + display: flex; + + &:not(:last-child) { + margin-bottom: @general-spacing; + } + + &-meta { + text-align: left; + font-style: italic; + border-right: 1px solid @grey-1; + padding: @general-spacing; + margin-right: @general-spacing; + min-width: 150px; + } + + &-text { + padding: @general-spacing; + } + + &--good { + .status__update-meta { + border-color: @green; + } + } + + &--busy { + .status__update-meta { + border-color: @orange; + } + } + + &--bad { + .status__update-meta { + border-color: @red; + } + } + } +} diff --git a/assets/less/nova/colours.less b/assets/less/nova/colours.less new file mode 100644 index 00000000..cd05f69a --- /dev/null +++ b/assets/less/nova/colours.less @@ -0,0 +1,24 @@ +@purple: #5e3e71; + +@red: #b01116; + +@green: #007c36; + +@orange: #cf7618; + +@grey-0: #000; +@grey-1: #111; +@grey-2: #222; +@grey-3: #333; +@grey-4: #444; +@grey-5: #555; +@grey-6: #666; +@grey-7: #777; +@grey-8: #888; +@grey-9: #999; +@grey-a: #aaa; +@grey-b: #bbb; +@grey-c: #ccc; +@grey-d: #ddd; +@grey-e: #eee; +@grey-f: #fff; diff --git a/assets/less/nova/main.less b/assets/less/nova/main.less new file mode 100644 index 00000000..1fc2f66b --- /dev/null +++ b/assets/less/nova/main.less @@ -0,0 +1,15 @@ +@import "base"; + +@import "bem/auth"; +@import "bem/banner"; +@import "bem/button"; +@import "bem/container"; +@import "bem/form"; +@import "bem/header"; +@import "bem/landing"; +@import "bem/platform"; +@import "bem/profile"; +@import "bem/status"; + +@import "colours"; +@import "variables"; diff --git a/assets/less/nova/variables.less b/assets/less/nova/variables.less new file mode 100644 index 00000000..a37b5679 --- /dev/null +++ b/assets/less/nova/variables.less @@ -0,0 +1,30 @@ +@grid: "https://static.flash.moe/images/grid.png"; + +@container-max-width: 1366px; +@general-spacing: 4px; +@platform-margin: @general-spacing (@general-spacing * 2) 0; +@platform-thin-margin: @general-spacing auto 0; + +@avatar-big: 200px; + +@global-shadow-opacity: 80%; +@global-shadow-size: 5px; +@global-inner-shadow-size: 2px; +@global-shadow-distance: 1px; + +@text-shadow-opacity: 80%; +@text-shadow-size: 1px; +@text-shadow-distance: 1px; + +@base-font-size: 16px; + +@header-font-size: 1.5em; +@header-height: 50px; + +@font-size--status-overall: 36px; +@font-size--status-last-update: 12px; +@font-size--status-incident-date: 24px; + +@font-size--profile-username: 24px; +@font-size--profile-title: 14px; +@font-size--profile-dates: 12px; diff --git a/assets/typescript/.gitkeep b/assets/typescript/.gitkeep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/assets/typescript/.gitkeep @@ -0,0 +1 @@ + diff --git a/build.sh b/build.sh new file mode 100644 index 00000000..9dc7c991 --- /dev/null +++ b/build.sh @@ -0,0 +1,83 @@ +#!/bin/sh + +ASSETS_PATH='./assets' +ASSETS_LESS="$ASSETS_PATH/less" +ASSETS_TS="$ASSETS_PATH/typescript" + +LESS_ENTRY_FILE='main.less' + +PUBLIC_DIR='./public' +PUBLIC_CSS="$PUBLIC_DIR/css" +PUBLIC_JS="$PUBLIC_DIR/js" + +NODE_PATH='./node_modules' + +NODE_DEST_JS="$PUBLIC_JS/libs.js" +NODE_IMPORT_JS=( + #'turbolinks/dist/turbolinks.js' + #'highlightjs/highlight.pack.min.js' +) + +NODE_DEST_CSS="$PUBLIC_CSS/libs.css" +NODE_IMPORT_CSS=( + #'highlightjs/styles/default.css' +) + +# delete old files, using find to avoid errors +echo "=> Cleanup" +find $ASSETS_TS -type f -name "*.d.ts" -delete -print +find $PUBLIC_CSS -type f -name "*.css" -delete -print +find $PUBLIC_JS -type f -name "*.js" -delete -print +echo + +# styles +echo +echo "=> LESS" +for STYLE_DIR in $ASSETS_LESS/*/; do +STYLE_NAME=`basename $STYLE_DIR | tr '[A-Z]' '[a-z]'` +echo "==> $STYLE_NAME" +lessc --verbose $STYLE_DIR/$LESS_ENTRY_FILE $PUBLIC_CSS/$STYLE_NAME.css +echo +done + +# scripts +echo +echo "=> TypeScript" +for SCRIPT_DIR in $ASSETS_TS/*/; do +SCRIPT_NAME=`basename $SCRIPT_DIR` +SCRIPT_NAME_LOWER=`echo $SCRIPT_NAME | tr '[A-Z]' '[a-z]'` +echo "==> $SCRIPT_NAME" +find $SCRIPT_DIR -name "*.ts" | xargs tsc \ + -d \ + -t es5 \ + --listFiles \ + --listEmittedFiles \ + --noImplicitAny \ + --removeComments \ + --outFile $PUBLIC_JS/$SCRIPT_NAME_LOWER.js +mv -v $PUBLIC_JS/$SCRIPT_NAME_LOWER.d.ts $ASSETS_TS/$SCRIPT_NAME.d.ts +echo +done + +# node imports +echo +echo "=> NPM imports" + +echo "==> JavaScript" +echo "Creating $NODE_DEST_JS" +touch $NODE_DEST_JS +for FILE in "${NODE_IMPORT_JS[@]}"; do +echo "===> $FILE" +cat "$NODE_PATH/$FILE" >> $NODE_DEST_JS +done +echo + +echo "==> CSS" +echo "Creating $NODE_DEST_CSS" +touch $NODE_DEST_CSS +for FILE in "${NODE_IMPORT_CSS[@]}"; do +echo "===> $FILE" +cat "$NODE_PATH/$FILE" >> $NODE_DEST_CSS +done + + diff --git a/config/config.example.ini b/config/config.example.ini new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/config/config.example.ini @@ -0,0 +1 @@ + diff --git a/database/.gitkeep b/database/.gitkeep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/database/.gitkeep @@ -0,0 +1 @@ + diff --git a/src/Application.php b/src/Application.php index b64f72ed..0f6fab31 100644 --- a/src/Application.php +++ b/src/Application.php @@ -66,19 +66,19 @@ class Application $this->addModule('templating', new TemplateEngine); $this->addModule('config', new ConfigManager($config)); + $this->debug(true); + $this->templating->addFilter('json_decode'); $this->templating->addFilter('byte_symbol'); $this->templating->addFunction('byte_symbol'); $this->templating->addFunction('session_id'); $this->templating->addFunction('config', [$this->config, 'get']); $this->templating->addFunction('route', [$this->router, 'url']); + $this->templating->addFunction('git_hash', [Application::class, 'gitCommitHash']); + $this->templating->addFunction('git_branch', [Application::class, 'gitBranch']); + $this->templating->addPath('nova', __DIR__ . '/../views/nova'); - echo sprintf( - 'Running on commit %s on branch %3$s!', - self::gitCommitHash(true), - self::gitCommitHash(), - self::gitBranch() - ); + echo $this->templating->render('home.landing'); } public function __destruct() diff --git a/src/TemplateEngine.php b/src/TemplateEngine.php index 7300ec6c..d025f9a5 100644 --- a/src/TemplateEngine.php +++ b/src/TemplateEngine.php @@ -122,7 +122,7 @@ class TemplateEngine private function fixPath(string $path): string { // if the .twig extension if already present just assume that the path is already correct - if (ends_width($path, self::FILE_EXTENSION)) { + if (ends_with($path, self::FILE_EXTENSION)) { return $path; } diff --git a/store/.gitkeep b/store/.gitkeep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/store/.gitkeep @@ -0,0 +1 @@ + diff --git a/views/nova/home/landing.twig b/views/nova/home/landing.twig new file mode 100644 index 00000000..b9d26fd2 --- /dev/null +++ b/views/nova/home/landing.twig @@ -0,0 +1,5 @@ +{% extends '@nova/master.twig' %} + +{% block content %} + test +{% endblock %} diff --git a/views/nova/master.twig b/views/nova/master.twig new file mode 100644 index 00000000..285e6f15 --- /dev/null +++ b/views/nova/master.twig @@ -0,0 +1,45 @@ + + +
+ + +