diff --git a/package.json b/package.json index b74ecdc..b83dc74 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "devDependencies": { "@babel/core": "^7.9.0", "@babel/preset-env": "^7.9.5", - "@fortawesome/fontawesome-free": "^5.14.0", "@tsconfig/svelte": "^2.0.1", "@types/config": "^0.0.40", "@types/express": "^4.17.6", diff --git a/src/assets/sass/.gitkeep b/src/assets/sass/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assets/sass/_fonts.scss b/src/assets/sass/_fonts.scss deleted file mode 100644 index 6c26b55..0000000 --- a/src/assets/sass/_fonts.scss +++ /dev/null @@ -1,81 +0,0 @@ -/* vietnamese */ -@font-face { - font-family: 'Nunito Sans'; - font-style: normal; - font-weight: 300; - font-display: swap; - src: local('Nunito Sans Light'), local('NunitoSans-Light'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8WAc5iU1EQVg.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Nunito Sans'; - font-style: normal; - font-weight: 300; - font-display: swap; - src: local('Nunito Sans Light'), local('NunitoSans-Light'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8WAc5jU1EQVg.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Nunito Sans'; - font-style: normal; - font-weight: 300; - font-display: swap; - src: local('Nunito Sans Light'), local('NunitoSans-Light'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8WAc5tU1E.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* vietnamese */ -@font-face { - font-family: 'Nunito Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Nunito Sans Regular'), local('NunitoSans-Regular'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe0qMImSLYBIv1o4X1M8cceyI9tScg.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Nunito Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Nunito Sans Regular'), local('NunitoSans-Regular'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe0qMImSLYBIv1o4X1M8ccezI9tScg.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Nunito Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Nunito Sans Regular'), local('NunitoSans-Regular'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe0qMImSLYBIv1o4X1M8cce9I9s.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* vietnamese */ -@font-face { - font-family: 'Nunito Sans'; - font-style: normal; - font-weight: 700; - font-display: swap; - src: local('Nunito Sans Bold'), local('NunitoSans-Bold'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8GBs5iU1EQVg.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Nunito Sans'; - font-style: normal; - font-weight: 700; - font-display: swap; - src: local('Nunito Sans Bold'), local('NunitoSans-Bold'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8GBs5jU1EQVg.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Nunito Sans'; - font-style: normal; - font-weight: 700; - font-display: swap; - src: local('Nunito Sans Bold'), local('NunitoSans-Bold'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8GBs5tU1E.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} diff --git a/src/assets/sass/_vars.scss b/src/assets/sass/_vars.scss deleted file mode 100644 index 478fca3..0000000 --- a/src/assets/sass/_vars.scss +++ /dev/null @@ -1,33 +0,0 @@ -$primary: darken(#242b33, 2%); -$primaryForeground: #f0f0f0; -$secondary: lighten(#00766c, 10%); -$secondaryForeground: $primaryForeground; - -$backgroundColor: darken($primary, 4%); -$defaultTextColor: #ffffff; - -$headerBackground: transparent; -$headerContainer: true; -$footerBackground: transparent; -$panelBackground: darken($backgroundColor, 3.2%); -$inputBackground: darken($panelBackground, 4%); - -$info: #4499ff; -$infoText: darken($info, 42%); -$infoColor: desaturate($infoText, 50%); - -$success: #55ff55; -$successText: darken($success, 45%); -$successColor: desaturate($successText, 50%); - -$warning: #ffcc00; -$warningText: darken($warning, 30%); -$warningColor: desaturate($warningText, 50%); - -$error: #ff0000; -$errorText: darken($error, 30%); -$errorColor: desaturate($errorText, 50%); - -// Responsivity -$mobileThreshold: 632px; -$desktopThreshold: 940px; diff --git a/src/assets/sass/app.scss b/src/assets/sass/app.scss deleted file mode 100644 index 933fea1..0000000 --- a/src/assets/sass/app.scss +++ /dev/null @@ -1 +0,0 @@ -@import "layout"; \ No newline at end of file diff --git a/src/assets/sass/error.scss b/src/assets/sass/error.scss deleted file mode 100644 index d36ad0b..0000000 --- a/src/assets/sass/error.scss +++ /dev/null @@ -1,90 +0,0 @@ -@import "layout"; - -header, footer { - margin: 0; - padding: 0; - height: 0; -} - -main { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - .messages { - margin-bottom: 32px; - } - - .error-code { - font-size: 36px; - } - - .error-message { - font-size: 32px; - } - - .error-instructions { - margin-top: 32px; - font-size: 20px; - } - - nav { - margin-top: 32px; - } - - &::before { - content: "Oops"; - position: absolute; - z-index: -1; - - font-size: #{'min(50vh, 40vw)'}; - opacity: 0.025; - } -} - -.contact { - text-align: center; - padding: 8px; -} - -.logo { - position: absolute; - top: 0; - left: 0; - width: 100%; - margin-top: 24px; - text-align: center; - - a { - position: relative; - padding: 16px; - - color: $defaultTextColor; - - &:hover { - color: #fff; - - &::before { - opacity: 0.2; - } - } - - &::before { - content: ""; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - - background-image: url(../img/logo.svg); - background-repeat: no-repeat; - background-position: center; - background-size: 64px; - - opacity: 0.075; - filter: contrast(0); - } - } -} \ No newline at end of file diff --git a/src/assets/sass/layout.scss b/src/assets/sass/layout.scss deleted file mode 100644 index cf1f7c1..0000000 --- a/src/assets/sass/layout.scss +++ /dev/null @@ -1,843 +0,0 @@ -@import "vars"; -@import 'fonts'; -@import "responsivity_tools"; - -* { - box-sizing: border-box; -} - -html, body { - height: 100%; -} - -body { - display: flex; - flex-direction: column; - - margin: 0; - font-family: "Nunito Sans", sans-serif; - font-size: 16px; - - color: $defaultTextColor; - background-color: $backgroundColor; -} - -@mixin tip { - position: relative; - - .tip { - visibility: hidden; - position: absolute; - z-index: 10000; - pointer-events: none; - display: block; - width: max-content; - height: 30px; - padding: 4px 8px; - line-height: 22px; - top: calc(100% + 8px); - left: 50%; - transform: translateX(-50%); - - text-align: center; - font-size: 18px; - color: $defaultTextColor; - opacity: 0; - transition: opacity ease-out 100ms, visibility step-end 150ms; - transition-delay: 0ms; - background-color: #000; - border-radius: 5px; - - text-transform: initial; - font-weight: initial; - - &.top { - top: auto; - bottom: calc(100% + 8px); - } - } - - &:hover, &:active { - .tip { - visibility: visible; - opacity: 1; - transition: opacity ease-out 100ms; - transition-delay: 150ms; - } - } -} - -body > header { - z-index: 50; - display: flex; - flex-direction: row-reverse; - justify-content: space-between; - align-items: center; - - $headerHeight: 64px; - height: $headerHeight; - line-height: $headerHeight; - - background: $headerBackground; - - @if $headerContainer { - @include container; - } - - @media (max-width: $mobileThreshold) { - padding: 0; - } - - .logo { - display: flex; - flex-direction: row; - align-items: center; - - padding: 0 16px 0 8px; - font-size: 24px; - color: $defaultTextColor; - - &:hover { - color: lighten($defaultTextColor, 10%); - } - - img { - width: initial; - height: calc(#{$headerHeight} - 16px); - margin-right: 8px; - flex-shrink: 0; - } - } - - nav { - > ul { - position: fixed; - z-index: -1; - top: 0; - left: 0; - height: 100%; - transform: translateX(-100%); - transition: transform ease-out 150ms; - - display: flex; - flex-direction: column; - margin: 0; - padding: $headerHeight 8px 8px; - - font-size: 20px; - - background: $panelBackground; - - li { - position: relative; - list-style: none; - margin-top: 8px; - - a, button { - position: relative; - margin: 0; - - display: flex; - flex-direction: row; - align-items: center; - height: auto; - padding: 8px; - - border-radius: 3px; - - &:hover, &:active { - &:not(button) { - background-color: rgba(255, 255, 255, 0.07); - } - } - - .feather { - --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; - } - } - - button { - margin: 0; - height: 32px; - - .feather { - margin-right: 0; - } - } - - form { - display: flex; - justify-content: center; - align-items: center; - padding: 0; - } - - &.auth-user { - img { - width: 48px; - height: 48px; - border-radius: 3px; - margin-right: 8px; - } - } - - .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 { - position: fixed; - top: 0; - left: 0; - display: block; - margin: 0; - padding: 0 16px; - line-height: $headerHeight; - - cursor: pointer; - background: transparent; - border-radius: 0; - - .feather { - --icon-size: 28px; - margin: 0 8px; - } - } - - hr { - border: 0; - border-bottom: 1px solid $defaultTextColor; - opacity: 0.2; - } - } - - @media (min-width: $mobileThreshold) { - flex-direction: row; - - nav { - #menu-button { - display: 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; - } - } - } - } -} - -body > footer { - padding: 8px; - margin-top: 8px; - text-align: center; - background-color: $footerBackground; -} - -main { - flex: 1; - padding: 8px 0; - - button, .button { - @include tip; - } -} - -h1 { - text-align: center; - font-size: 32px; - - & + p { - text-align: center; - font-size: 20px; - } -} - -h1, h2 { - font-weight: 100; -} - -h3, h4 { - font-weight: 300; -} - -section > h2, .panel > h2 { - display: flex; - flex-direction: row; - align-items: center; - position: relative; - text-align: center; - margin-top: 4px; - - font-size: 24px; - line-height: 1; - - .feather { - margin: 0 16px 0 0; - opacity: 0.1; - } - - &::after { - content: ""; - flex: 1; - margin: 0 16px; - height: 0; - border-bottom: 1px solid $defaultTextColor; - opacity: 0.1; - } -} - -section > hr, .panel > hr { - border: 0; - border-bottom: 1px solid $defaultTextColor; - opacity: 0.2; - - margin: 8px 32px; -} - -a { - color: $secondary; - text-decoration: none; - - &:hover { - color: lighten($secondary, 30%); - } - - .feather.feather-external-link { - --icon-size: 16px; - margin-left: 4px; - margin-top: -3px; - } -} - -form { - padding: 8px 16px; - text-align: center; - - .form-field:not(.hidden) { - display: flex; - flex-direction: column; - margin: 16px auto; - - .control { - position: relative; - background: $inputBackground; - border-radius: 5px; - } - - .feather.icon { - position: absolute; - top: 50%; - right: 8px; - transform: translateY(-50%); - z-index: 0; - - --icon-size: 24px; - opacity: 0.75; - } - - label { - position: absolute; - left: 8px; - top: 20px; - user-select: none; - font-size: 16px; - opacity: 0.75; - - transition-property: top, font-size; - transition-duration: 150ms; - transition-timing-function: ease-out; - - cursor: text; - } - - [disabled] { - opacity: 0.5; - - & ~ label { - opacity: 0.5; - cursor: default; - } - } - - input, select, textarea, .input-group { - z-index: 1; - border: 0; - color: $defaultTextColor; - background: transparent; - font-size: 16px; - - &:focus, &:not([value=""]), &[type="file"] { - ~ label { - top: 8px; - font-size: 14px; - } - } - } - - input, select, textarea, .form-display { - display: block; - padding: 32px 8px 8px 8px; - width: 100%; - height: 60px; - } - - select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - - &::-ms-expand { - display: none; - } - - & + .feather { - position: absolute; - pointer-events: none; - right: 8px; - top: 30px; - - transition: transform 150ms ease-out; - } - - // Temporary - &:focus + .feather { - transform: rotateX(180deg); - } - } - - textarea { - resize: vertical; - min-height: 100px; - font-family: inherit; - } - - input[type=color] { - height: calc(32px + 8px + 32px); - } - - &.inline { - display: flex; - flex-direction: row; - - .control { - display: flex; - flex-direction: row; - align-items: center; - flex-grow: 1; - - input[type=checkbox] { - width: min-content; - height: min-content; - margin: 8px; - text-align: left; - - & ~ label { - position: static; - flex-grow: 1; - display: inline; - padding: 8px; - - font-size: 16px; - text-align: left; - } - } - } - } - - .input-group { - display: flex; - flex-grow: 1; - flex-direction: row; - - div { - position: relative; - flex: 1; - - input { - width: 100%; - border: 0; - background: transparent; - } - } - } - } - - .inline-fields { - display: flex; - flex-direction: row; - align-items: start; - margin: 16px auto; - - .form-field { - flex: 1; - margin: 0; - } - - > :not(.form-field) { - padding: 32px 8px 8px 8px; - } - - + { - .error, .hint { - margin-top: -16px; - margin-bottom: 16px; - } - } - } - - .form-field, .inline-fields + { - .error, .hint { - padding: 2px; - text-align: left; - font-size: 14px; - - .feather { - --icon-size: 14px; - } - } - - .error { - color: $error; - } - } -} - -button, .button { - display: inline-flex; - margin: 8px; - padding: 12px 16px; - border: 0; - border-radius: 5px; - cursor: pointer; - - text-transform: uppercase; - font-size: 16px; - font-weight: bolder; - - line-height: 16px; - - .feather { - --icon-size: 16px; - margin-right: 8px; - } - - .feather.last { - margin-right: 0; - margin-left: 8px; - } - - &, &.primary { - color: $primaryForeground; - background-color: darken($secondary, 10%); - - &:hover { - background-color: $secondary; - } - } - - &.info { - background-color: $infoColor; - } - - &.success { - background-color: $successColor; - } - - &.warning { - background-color: $warningColor; - - &:hover { - background-color: lighten($warningColor, 10%); - } - } - - &.error, &.danger { - background-color: $errorColor; - - &:hover { - background-color: lighten($errorColor, 10%); - } - } - - &.transparent { - background-color: transparent; - } - - &:hover { - color: $primaryForeground; - } -} - - -// --- -// --- 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; - } -} - - -// --- -// --- Breadcrumb widget -// --- -.breadcrumb { - list-style: none; - display: flex; - flex-direction: row; - margin: 0; - padding: 8px; - - > *:not(:first-child)::before { - content: '›'; - padding: 0 8px; - } -} - - -// --- -// --- Layout helpers -// --- -.center { - text-align: center; -} - -.panel { - position: relative; - margin: 16px 0 48px; - padding: 8px; - background-color: $panelBackground; - border-radius: 5px; - - p { - margin: 16px 8px; - } - - > .feather:first-child { - position: absolute; - --icon-size: 24px; - opacity: 0.1; - top: 8px; - left: 8px; - } -} - -.sub-panel { - margin: 32px 0; - padding: 1px 16px; - border: 2px solid lighten($panelBackground, 4%); - border-radius: 5px; - - form > & { - margin: 32px -18px; - } -} - - -// --- -// --- Helper classes -// --- -.container > .messages:first-child { - margin-top: 16px; -} - -.copyable-text { - display: flex; - flex-direction: row; - margin: 8px; - - background-color: darken($backgroundColor, 2%); - border-radius: 5px; - overflow: hidden; - - .title { - padding: 8px; - } - - .content { - width: 0; - flex-grow: 1; - overflow: hidden; - white-space: nowrap; - padding: 8px; - } - - .copy-button { - margin: 0; - padding: 0; - border-radius: 0; - - .feather { - --icon-size: 20px; - margin: 8px; - } - } -} - -.hidden { - display: none; -} - -.progress-bar { - position: relative; - display: block; - margin: 8px; - padding: 4px; - background: #fff1; - border-radius: 5px; - overflow: hidden; - text-align: center; - - .content { - position: relative; - } - - &::before { - content: ""; - display: block; - position: absolute; - left: 0; - top: 0; - width: var(--progress); - height: 100%; - transition: width ease-out 150ms; - - background: $secondary; - } -} - -.table-col-grow { - width: 100%; -} - -.pagination { - ul { - display: flex; - flex-direction: row; - list-style: none; - padding: 8px; - - justify-content: center; - - li { - a, &.active, &.ellipsis { - display: block; - min-width: 40px; - height: 40px; - padding: 4px; - - line-height: 32px; - text-align:center; - - &:hover:not(.active):not(.ellipsis) { - background-color: #fff5; - } - } - } - } -} diff --git a/src/assets/sass/responsivity_tools.scss b/src/assets/sass/responsivity_tools.scss deleted file mode 100644 index 0e3d232..0000000 --- a/src/assets/sass/responsivity_tools.scss +++ /dev/null @@ -1,19 +0,0 @@ -@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; -} diff --git a/src/assets/ts/PersistentWebSocket.ts b/src/assets/ts/PersistentWebSocket.ts deleted file mode 100644 index 98e474f..0000000 --- a/src/assets/ts/PersistentWebSocket.ts +++ /dev/null @@ -1,39 +0,0 @@ -export default class PersistentWebsocket { - private webSocket?: WebSocket; - - public constructor( - protected readonly url: string, - private readonly handler: MessageHandler, - protected readonly reconnectOnClose: boolean = true, - ) { - } - - public run(): void { - const _webSocket = this.webSocket = new WebSocket(this.url); - this.webSocket.addEventListener('open', () => { - console.debug('Websocket connected'); - }); - this.webSocket.addEventListener('message', (e) => { - this.handler(_webSocket, e); - }); - this.webSocket.addEventListener('error', (e) => { - console.error('Websocket error', e); - }); - this.webSocket.addEventListener('close', (e) => { - this.webSocket = undefined; - console.debug('Websocket closed', e.code, e.reason); - - if (this.reconnectOnClose) { - setTimeout(() => this.run(), 1000); - } - }); - } - - public send(data: string): void { - if (!this.webSocket) throw new Error('WebSocket not connected'); - - this.webSocket.send(data); - } -} - -export type MessageHandler = (webSocket: WebSocket, e: MessageEvent) => void; diff --git a/src/assets/ts/app.ts b/src/assets/ts/app.ts deleted file mode 100644 index 8594552..0000000 --- a/src/assets/ts/app.ts +++ /dev/null @@ -1,10 +0,0 @@ -import './external_links'; -import './message_icons'; -import './forms'; -import './copyable_text'; -import './tooltips-and-dropdowns'; -import './main_menu'; -import './font-awesome'; - -// css -import '../sass/app.scss'; diff --git a/src/assets/ts/copyable_text.ts b/src/assets/ts/copyable_text.ts deleted file mode 100644 index 60d58ab..0000000 --- a/src/assets/ts/copyable_text.ts +++ /dev/null @@ -1,15 +0,0 @@ -document.addEventListener('DOMContentLoaded', () => { - document.querySelectorAll('.copyable-text').forEach(el => { - const contentEl = el.querySelector('.content'); - const selection = window.getSelection(); - if (contentEl && selection) { - contentEl.addEventListener('click', () => { - selection.selectAllChildren(contentEl); - }); - el.querySelector('.copy-button')?.addEventListener('click', () => { - selection.selectAllChildren(contentEl); - document.execCommand('copy'); - }); - } - }); -}); diff --git a/src/assets/ts/external_links.ts b/src/assets/ts/external_links.ts deleted file mode 100644 index bc9ba26..0000000 --- a/src/assets/ts/external_links.ts +++ /dev/null @@ -1,11 +0,0 @@ -import feather from "feather-icons"; - -document.addEventListener('DOMContentLoaded', () => { - document.querySelectorAll('a[target="_blank"]').forEach(el => { - if (!el.classList.contains('no-icon')) { - el.innerHTML += ``; - } - }); - - feather.replace(); -}); diff --git a/src/assets/ts/font-awesome.ts b/src/assets/ts/font-awesome.ts deleted file mode 100644 index 0409cfe..0000000 --- a/src/assets/ts/font-awesome.ts +++ /dev/null @@ -1,4 +0,0 @@ -import '@fortawesome/fontawesome-free/scss/fontawesome.scss'; -import '@fortawesome/fontawesome-free/scss/regular.scss'; -import '@fortawesome/fontawesome-free/scss/solid.scss'; -import '@fortawesome/fontawesome-free/scss/brands.scss'; diff --git a/src/assets/ts/forms.ts b/src/assets/ts/forms.ts deleted file mode 100644 index ece465d..0000000 --- a/src/assets/ts/forms.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * For labels to update their state (css selectors based on the value attribute) - */ -import {ValidationError} from "swaf/db/Validator"; - -export function updateInputs(): void { - document.querySelectorAll('input, textarea').forEach(el => { - if (!el.dataset.inputSetup) { - el.dataset.inputSetup = 'true'; - if (el.type !== 'checkbox') { - el.setAttribute('value', el.value); - el.addEventListener('change', () => { - el.setAttribute('value', el.value); - }); - } - } - }); -} - -document.addEventListener('DOMContentLoaded', () => { - updateInputs(); -}); - -export function applyFormMessages( - formElement: HTMLFormElement, - messages: { [p: string]: ValidationError }, -): void { - for (const fieldName of Object.keys(messages)) { - const field = formElement.querySelector('#field-' + fieldName); - if (!field) continue; - - let parent = field.parentElement; - while (parent && !parent.classList.contains('form-field')) parent = parent.parentElement; - - let err = field.querySelector('.error'); - if (!err) { - err = document.createElement('div'); - err.classList.add('error'); - parent?.insertBefore(err, parent.querySelector('.hint') || parent); - } - err.innerHTML = ` ${messages[fieldName].message}`; - } -} diff --git a/src/assets/ts/main_menu.ts b/src/assets/ts/main_menu.ts deleted file mode 100644 index 4e19e40..0000000 --- a/src/assets/ts/main_menu.ts +++ /dev/null @@ -1,21 +0,0 @@ -document.addEventListener('DOMContentLoaded', () => { - const menuButton = document.getElementById('menu-button'); - const mainMenu = document.getElementById('main-menu'); - - if (menuButton) { - menuButton.addEventListener('click', (e) => { - e.stopPropagation(); - mainMenu?.classList.toggle('open'); - }); - } - - if (mainMenu) { - mainMenu.addEventListener('click', (e) => { - e.stopPropagation(); - }); - - document.addEventListener('click', () => { - mainMenu.classList.remove('open'); - }); - } -}); diff --git a/src/assets/ts/message_icons.ts b/src/assets/ts/message_icons.ts deleted file mode 100644 index b737de3..0000000 --- a/src/assets/ts/message_icons.ts +++ /dev/null @@ -1,26 +0,0 @@ -import feather from "feather-icons"; - -document.addEventListener('DOMContentLoaded', () => { - const messageTypeToIcon: { [p: string]: string } = { - info: 'info', - success: 'check', - warning: 'alert-triangle', - error: 'x-circle', - question: 'help-circle', - }; - - document.querySelectorAll('.message').forEach(el => { - const icon = el.querySelector('.icon'); - const type = el.dataset['type']; - if (!icon || !type) return; - if (!messageTypeToIcon[type]) throw new Error(`No icon for type ${type}`); - - const svgContainer = document.createElement('div'); - svgContainer.innerHTML = feather.icons[messageTypeToIcon[type]].toSvg(); - - if (svgContainer.firstChild) el.insertBefore(svgContainer.firstChild, icon); - icon.remove(); - }); - - feather.replace(); -}); diff --git a/src/assets/ts/tooltips-and-dropdowns.ts b/src/assets/ts/tooltips-and-dropdowns.ts deleted file mode 100644 index 069b405..0000000 --- a/src/assets/ts/tooltips-and-dropdowns.ts +++ /dev/null @@ -1,31 +0,0 @@ -export function updateTooltips(): void { - console.debug('Updating tooltips'); - const elements = document.querySelectorAll('.tip, .dropdown'); - - // Calculate max potential displacement - let max = 0; - elements.forEach(el => { - const box = el.getBoundingClientRect(); - if (max < box.height) max = box.height; - }); - - // Prevent displacement - elements.forEach(el => { - if (!el.dataset.tooltipSetup) { - el.dataset.tooltipSetup = 'true'; - const box = el.getBoundingClientRect(); - if (box.bottom >= document.body.clientHeight - (max + 32)) { - el.classList.add('top'); - } - } - }); -} - -document.addEventListener('DOMContentLoaded', () => { - window.addEventListener('popstate', () => { - updateTooltips(); - }); - window.requestAnimationFrame(() => { - updateTooltips(); - }); -}); diff --git a/src/assets/views/about.njk b/src/assets/views/about.njk deleted file mode 100644 index f1e7a0a..0000000 --- a/src/assets/views/about.njk +++ /dev/null @@ -1,14 +0,0 @@ -{% extends 'layouts/base.njk' %} - -{% set title = app.name + ' - About us' %} - -{% block body %} -

Very interesting

- -
-
-

This is us

-

And we like swaf!

-
-
-{% endblock %} diff --git a/src/assets/views/home.njk b/src/assets/views/home.njk deleted file mode 100644 index 09adf33..0000000 --- a/src/assets/views/home.njk +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'layouts/base.njk' %} - -{% set title = app.name + ' - Hello world!' %} - -{% block body %} -

Hello world!

-{% endblock %} \ No newline at end of file diff --git a/src/assets/views/layouts/base.njk b/src/assets/views/layouts/base.njk deleted file mode 100644 index f350e8e..0000000 --- a/src/assets/views/layouts/base.njk +++ /dev/null @@ -1,41 +0,0 @@ -{% extends 'layouts/barebone.njk' %} -{% import 'macros.njk' as macros %} - -{% block _stylesheets %} - {{ super() }} - - {% block stylesheets %}{% endblock %} -{% endblock %} -{% block _scripts %} - {{ super() }} - {% block scripts %}{% endblock %} -{% endblock %} - -{% block header %} - - -{% endblock %} - -{% block _body %} -
- {{ macros.messages(flash) }} -
- -
- {% if h1 %} -

{{ h1 }}

- {% endif %} - {% if subtitle %} -

{{ subtitle }}

- {% endif %} - - {% block body %}{% endblock %} -
-{% endblock %} - -{% block footer %}{{ app.name }} v{{ app_version }} - all rights reserved.{% endblock %} \ No newline at end of file