Merge remote-tracking branch 'boilerplate/master' into develop

This commit is contained in:
Alice Gaudon 2021-03-06 18:05:36 +01:00
commit 7870e4aa3c
10 changed files with 271 additions and 137 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@ node_modules
public
dist
yarn-error.log
src/package.json

View File

@ -6,9 +6,10 @@ $secondaryForeground: $primaryForeground;
$backgroundColor: darken($primary, 4%);
$defaultTextColor: #ffffff;
$headerBackground: darken($primary, 7.5%);
$footerBackground: lighten($headerBackground, 1%);
$panelBackground: lighten($headerBackground, 1%);
$headerBackground: transparent;
$headerContainer: true;
$footerBackground: transparent;
$panelBackground: darken($backgroundColor, 3.2%);
$inputBackground: darken($panelBackground, 4%);
$info: #4499ff;
@ -29,3 +30,4 @@ $errorColor: desaturate($errorText, 50%);
// Responsivity
$mobileThreshold: 632px;
$desktopThreshold: 940px;

View File

@ -1,5 +1,6 @@
@import "vars";
@import 'fonts';
@import "responsivity_tools";
* {
box-sizing: border-box;
@ -69,21 +70,31 @@ body {
body > header {
z-index: 50;
display: flex;
flex-direction: row;
flex-direction: row-reverse;
justify-content: space-between;
align-items: center;
$headerHeight: 64px;
height: $headerHeight;
line-height: $headerHeight;
background-color: $headerBackground;
background: $headerBackground;
@if $headerContainer {
@include container;
}
@media (max-width: $mobileThreshold) {
padding: 0;
}
.logo {
display: flex;
flex-direction: row;
align-items: center;
padding: 0 24px 0 16px;
font-size: 32px;
padding: 0 16px 0 8px;
font-size: 24px;
color: $defaultTextColor;
&:hover {
@ -91,34 +102,48 @@ body > header {
}
img {
width: $headerHeight;
height: $headerHeight;
margin-right: 16px;
width: initial;
height: calc(#{$headerHeight} - 16px);
margin-right: 8px;
flex-shrink: 0;
}
}
nav {
ul {
> ul {
position: fixed;
z-index: -1;
top: 0;
left: 0;
height: 100%;
transform: translateX(-100%);
transition: transform ease-out 150ms;
display: flex;
flex-direction: row;
flex-direction: column;
margin: 0;
padding: 0;
padding: $headerHeight 8px 8px;
font-size: 20px;
background: $panelBackground;
li {
position: relative;
list-style: none;
margin-top: 8px;
a, button {
position: relative;
height: 64px;
margin: 0;
padding: 0 24px;
display: flex;
flex-direction: row;
align-items: center;
height: auto;
padding: 8px;
border-radius: 3px;
&:hover, &:active {
&:not(button) {
@ -127,13 +152,40 @@ body > header {
}
.feather {
--icon-size: 24px;
--icon-size: 16px;
}
.tip {
position: static;
visibility: visible;
opacity: 1;
display: block;
height: auto;
margin-left: 8px;
padding: 0 0 0 4px;
transform: none;
font-size: 16px;
line-height: 16px;
color: inherit;
text-transform: uppercase;
font-weight: inherit;
background: transparent;
}
&:hover {
.tip {
visibility: visible;
opacity: 1;
transition: opacity ease-out 100ms;
transition-delay: 150ms;
}
}
}
button {
margin: 8px;
padding: 24px;
margin: 0;
height: 32px;
.feather {
@ -158,114 +210,117 @@ body > header {
}
.dropdown {
position: absolute;
z-index: -1;
top: 100%;
right: 0;
white-space: nowrap;
background: $headerBackground;
border-radius: 0 0 3px 3px;
a {
padding: 0 8px;
}
}
&:hover .dropdown {
position: initial;
display: block;
padding-left: 0;
}
}
> li:not(:first-child) {
border-top: 1px solid transparentize($defaultTextColor, 0.8);
padding-top: 8px;
}
&.open {
transform: translateX(0%);
box-shadow: 0 0 5px darken($panelBackground, 20%);
}
}
#menu-button {
display: none;
}
}
position: fixed;
top: 0;
left: 0;
display: block;
margin: 0;
padding: 0 16px;
line-height: $headerHeight;
@media (max-width: $mobileThreshold) {
flex-direction: row-reverse;
cursor: pointer;
background: transparent;
border-radius: 0;
.logo {
padding: 0 16px 0 8px;
font-size: 24px;
img {
margin-right: 8px;
.feather {
--icon-size: 28px;
margin: 0 8px;
}
}
nav {
#menu-button {
display: block;
margin: 0;
padding: 0 16px;
line-height: $headerHeight;
cursor: pointer;
background: transparent;
border-radius: 0;
.feather {
--icon-size: 28px;
margin: 0 8px;
}
}
> ul {
flex-direction: column;
position: absolute;
z-index: 10;
left: 0;
transform: translateX(-100%);
transition: transform ease-out 150ms;
background-color: $headerBackground;
&.open {
transform: translateX(0%);
}
li {
a, button {
.tip {
display: block;
margin-left: 8px;
text-transform: inherit;
font-weight: inherit;
}
}
.dropdown {
position: initial;
display: block;
padding-left: 32px;
}
}
}
hr {
border: 0;
border-bottom: 1px solid $defaultTextColor;
opacity: 0.2;
}
}
@media (min-width: $mobileThreshold) {
nav ul li {
a, button, .button {
@include tip;
flex-direction: row;
nav {
#menu-button {
display: none;
}
&:last-child {
a, button, .button {
.tip {
left: unset;
right: 4px;
transform: none;
ul {
position: static;
flex-direction: row;
transform: none;
padding: 0;
background: transparent;
li {
margin-top: 0;
margin-left: 8px;
&:last-child {
a, button, .button {
.tip {
left: unset;
right: 4px;
transform: none;
}
}
}
.dropdown {
position: absolute;
z-index: -1;
top: 100%;
right: 0;
display: none;
padding: 8px;
white-space: nowrap;
background: $panelBackground;
border-radius: 0 0 3px 3px;
box-shadow: 0 2px 2px transparentize(darken($panelBackground, 20%), 0.75);
border-top: 4px solid lighten($panelBackground, 5%);
li {
margin-left: 0;
&:not(:first-child) {
margin-top: 8px;
}
}
}
&:hover .dropdown {
display: block;
}
}
> li:not(:first-child) {
border-top: 0;
padding-top: 0;
}
}
}
}
}
footer {
body > footer {
padding: 8px;
margin-top: 8px;
text-align: center;
@ -338,7 +393,7 @@ a {
text-decoration: none;
&:hover {
color: lighten($secondary, 10%);
color: lighten($secondary, 30%);
}
.feather.feather-external-link {
@ -584,6 +639,10 @@ button, .button {
&.warning {
background-color: $warningColor;
&:hover {
background-color: lighten($warningColor, 10%);
}
}
&.error, &.danger {
@ -603,6 +662,35 @@ button, .button {
}
}
// ---
// --- Tables
// ---
td.actions {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
form {
padding: 0;
display: inline;
}
button, .button {
margin: 0;
padding: 8px;
.feather {
margin-right: 0;
}
}
> *:not(:first-child) {
margin-left: 8px;
}
}
.data-table {
width: 100%;
text-align: left;
@ -629,6 +717,10 @@ button, .button {
}
}
// ---
// --- Breadcrumb widget
// ---
.breadcrumb {
list-style: none;
display: flex;
@ -642,6 +734,7 @@ button, .button {
}
}
// ---
// --- Layout helpers
// ---
@ -649,24 +742,6 @@ button, .button {
text-align: center;
}
@mixin container {
width: $mobileThreshold;
padding: 0 16px;
@media (min-width: $mobileThreshold) {
margin: 0 auto;
}
@media (max-width: $mobileThreshold) {
width: 100%;
padding: 0 8px;
}
}
.container {
@include container;
}
.panel {
position: relative;
margin: 16px 0 48px;
@ -688,10 +763,14 @@ button, .button {
}
.sub-panel {
margin: 32px -18px;
margin: 32px 0;
padding: 1px 16px;
border: 2px solid lighten($panelBackground, 4%);
border-radius: 5px;
form > & {
margin: 32px -18px;
}
}
@ -715,6 +794,10 @@ button, .button {
stroke-linejoin: miter;
fill: none;
vertical-align: middle;
h1 > &, h2 > &, h3 > & {
--icon-size: 24px;
}
}
// ---

View File

@ -0,0 +1,19 @@
@import "vars";
@mixin container {
width: 100%;
padding: 0 8px;
@media (min-width: $mobileThreshold) {
margin: 0 auto;
padding: 0 16px;
}
@media (min-width: $desktopThreshold) {
width: $desktopThreshold;
}
}
.container {
@include container;
}

View File

@ -4,23 +4,23 @@
"description": "A simple redirection to serve a gitea instance's repositories' latest release files as an http file server. (302 redirections)",
"repository": "https://eternae.ink/arisu/update.eternae.ink",
"author": "Alice Gaudon <alice@gaudon.pro>",
"main": "dist/src/main.js",
"main": "dist/main.js",
"license": "MIT",
"scripts": {
"dist-webpack": "webpack --mode production",
"test": "jest --verbose --runInBand",
"clean": "(test ! -d dist || rm -r dist)",
"prepareSources": "cp package.json src/",
"compile": "yarn clean && tsc",
"build": "yarn compile && yarn dist-webpack",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"dev": "concurrently -k -n \"Typescript,Node,Webpack,Maildev\" -p \"[{name}]\" -c \"blue,green,red,yellow\" \"tsc --watch\" \"nodemon\" \"webpack --watch --mode development\" \"maildev\"",
"start": "yarn build && node dist/src/main.js",
"test": "jest --verbose --runInBand"
"build": "yarn prepareSources && yarn compile && webpack --mode production",
"dev": "yarn prepareSources && concurrently -k -n \"Typescript,Node,Webpack,Maildev\" -p \"[{name}]\" -c \"blue,green,red,yellow\" \"tsc --watch\" \"nodemon\" \"webpack --watch --mode development\" \"maildev\"",
"start": "yarn build && node",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"@fortawesome/fontawesome-free": "^5.14.0",
"@types/config": "^0.0.36",
"@types/config": "^0.0.38",
"@types/express": "^4.17.6",
"@types/express-session": "^1.17.0",
"@types/feather-icons": "^4.7.0",
@ -47,6 +47,7 @@
"imagemin-svgo": "^8.0.0",
"img-loader": "^3.0.1",
"jest": "^26.1.0",
"maildev": "^1.1.0",
"mini-css-extract-plugin": "^1.2.1",
"node-sass": "^5.0.0",
"nodemon": "^2.0.3",
@ -63,6 +64,6 @@
"express": "^4.17.1",
"mime": "^2.4.6",
"send-ranges": "^4.0.0",
"swaf": "^0.22.5"
"swaf": "^0.23.0"
}
}

View File

@ -4,7 +4,7 @@ import ExpressAppComponent from "swaf/components/ExpressAppComponent";
import LogRequestsComponent from "swaf/components/LogRequestsComponent";
import GiteaRepoLatestReleaseController from "./controllers/GiteaRepoLatestReleaseController";
import NunjucksComponent from "swaf/components/NunjucksComponent";
import packageJson = require('../package.json');
import packageJson = require('./package.json');
export default class App extends Application {
public constructor(

View File

@ -0,0 +1,25 @@
import Controller from "swaf/Controller";
import {Request, Response} from "express";
export default class HomeController extends Controller {
public routes(): void {
this.get('/', this.getHome, 'home');
this.get('/about', this.getAbout, 'about');
this.get('/back', this.goBack, 'about');
}
protected async getHome(req: Request, res: Response): Promise<void> {
res.render('home');
}
protected async getAbout(req: Request, res: Response): Promise<void> {
res.render('about');
}
/**
* This is to test and assert that swaf extended types are available
*/
protected async goBack(req: Request, res: Response): Promise<void> {
res.redirect(req.getPreviousUrl() || Controller.route('home'));
}
}

View File

@ -2,19 +2,19 @@ import {delimiter} from "path";
// Load config from specified path or default + swaf/config (default defaults)
process.env['NODE_CONFIG_DIR'] =
__dirname + '/../../node_modules/swaf/config/'
__dirname + '/../node_modules/swaf/config/'
+ delimiter
+ (process.env['NODE_CONFIG_DIR'] || __dirname + '/../../config/');
+ (process.env['NODE_CONFIG_DIR'] || __dirname + '/../config/');
import {log} from "swaf/Logger";
import {logger} from "swaf/Logger";
import App from "./App";
import config from "config";
(async () => {
log.debug('Config path:', process.env['NODE_CONFIG_DIR']);
logger.debug('Config path:', process.env['NODE_CONFIG_DIR']);
const app = new App(config.get<string>('listen_addr'), config.get<number>('port'));
await app.start();
})().catch(err => {
log.error(err);
logger.error(err);
});

View File

@ -2,6 +2,7 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "public/js",
"rootDir": "./assets",
"target": "ES6",
"strict": true,
"lib": [

View File

@ -3,6 +3,7 @@
"module": "CommonJS",
"esModuleInterop": true,
"outDir": "dist",
"rootDir": "./src",
"target": "ES6",
"strict": true,
"lib": [