add gui
This commit is contained in:
parent
928ebc7e3c
commit
5eed3bed89
13
ffplayout/frontend/.editorconfig
Normal file
13
ffplayout/frontend/.editorconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
23
ffplayout/frontend/.eslintrc.js
Normal file
23
ffplayout/frontend/.eslintrc.js
Normal file
@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true
|
||||
},
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
},
|
||||
extends: [
|
||||
'@nuxtjs',
|
||||
'plugin:nuxt/recommended'
|
||||
],
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
'vue/html-indent': ['error', 4],
|
||||
'vue/html-closing-bracket-newline': 'off',
|
||||
'indent': [2, 4],
|
||||
'no-tabs': 'off',
|
||||
"no-console": 0,
|
||||
"camelcase": ["error", {properties: "never"}]
|
||||
}
|
||||
}
|
90
ffplayout/frontend/.gitignore
vendored
Normal file
90
ffplayout/frontend/.gitignore
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Node template
|
||||
# Logs
|
||||
/logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# Nuxt generate
|
||||
dist
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
# IDE / Editor
|
||||
.idea
|
||||
|
||||
# Service worker
|
||||
sw.*
|
||||
|
||||
# Mac OSX
|
||||
.DS_Store
|
||||
|
||||
# Vim swap files
|
||||
*.swp
|
22
ffplayout/frontend/README.md
Normal file
22
ffplayout/frontend/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# ffplayout
|
||||
|
||||
> web GUI for ffplayout engine
|
||||
|
||||
## Build Setup
|
||||
|
||||
``` bash
|
||||
# install dependencies
|
||||
$ npm run install
|
||||
|
||||
# serve with hot reload at localhost:3000
|
||||
$ npm run dev
|
||||
|
||||
# build for production and launch server
|
||||
$ npm run build
|
||||
$ npm run start
|
||||
|
||||
# generate static project
|
||||
$ npm run generate
|
||||
```
|
||||
|
||||
For detailed explanation on how things work, check out [Nuxt.js docs](https://nuxtjs.org).
|
7
ffplayout/frontend/assets/README.md
Normal file
7
ffplayout/frontend/assets/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# ASSETS
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
This directory contains your un-compiled assets such as LESS, SASS, or JavaScript.
|
||||
|
||||
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked).
|
497
ffplayout/frontend/assets/css/_bootswatch.scss
Normal file
497
ffplayout/frontend/assets/css/_bootswatch.scss
Normal file
@ -0,0 +1,497 @@
|
||||
// Slate 4.3.1
|
||||
// Bootswatch
|
||||
|
||||
|
||||
// Variables ===================================================================
|
||||
|
||||
@mixin btn-shadow($color){
|
||||
@include gradient-y-three-colors(lighten($color, 6%), $color, 60%, darken($color, 4%));
|
||||
filter: none;
|
||||
}
|
||||
|
||||
@mixin btn-shadow-inverse($color){
|
||||
@include gradient-y-three-colors(darken($color, 18%), darken($color, 15%), 40%, darken($color, 13%));
|
||||
filter: none;
|
||||
}
|
||||
|
||||
// Navbar ======================================================================
|
||||
|
||||
.navbar {
|
||||
border: 1px solid rgba(0, 0, 0, 0.6);
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
|
||||
|
||||
.container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
border-color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
&-fixed-top {
|
||||
border-width: 0 0 1px 0;
|
||||
}
|
||||
|
||||
&-fixed-bottom {
|
||||
border-width: 1px 0 0 0;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
padding: 1rem;
|
||||
border-left: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.2);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
@include btn-shadow-inverse($gray-800);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&-brand {
|
||||
padding: 0.75rem 1rem calc(54px - 0.75rem - 30px);
|
||||
margin-right: 0;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.nav-item.active .nav-link {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
&-nav .nav-item + .nav-item {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&.bg-light {
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.nav-link {
|
||||
&:hover,
|
||||
&:focus {
|
||||
@include btn-shadow-inverse($gray-600);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.navbar-expand-sm {
|
||||
.navbar-brand,
|
||||
.nav-link {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.navbar-expand-md {
|
||||
.navbar-brand,
|
||||
.nav-link {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.navbar-expand-lg {
|
||||
.navbar-brand,
|
||||
.nav-link {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Buttons =====================================================================
|
||||
|
||||
.btn {
|
||||
border-color: rgba(0, 0, 0, 0.6);
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
|
||||
|
||||
&:not([disabled]):not(.disabled).active,
|
||||
&.disabled {
|
||||
border-color: rgba(0, 0, 0, 0.6);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:not([disabled]):not(.disabled):active,
|
||||
&:not([disabled]):not(.disabled):active:hover,
|
||||
&:not([disabled]):not(.disabled).active:hover {
|
||||
border-color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@include btn-shadow($primary);
|
||||
|
||||
&:not([disabled]):not(.disabled):hover,
|
||||
&:not([disabled]):not(.disabled):focus,
|
||||
&:not([disabled]):not(.disabled):active:hover,
|
||||
&:not([disabled]):not(.disabled).active:hover {
|
||||
@include btn-shadow-inverse($primary);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@include btn-shadow($secondary);
|
||||
|
||||
&:not([disabled]):not(.disabled):hover,
|
||||
&:not([disabled]):not(.disabled):focus,
|
||||
&:not([disabled]):not(.disabled):active,
|
||||
&:not([disabled]):not(.disabled).active {
|
||||
@include btn-shadow-inverse($secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
@include btn-shadow($success);
|
||||
color: $white;
|
||||
|
||||
&:not([disabled]):not(.disabled):hover,
|
||||
&:not([disabled]):not(.disabled):focus,
|
||||
&:not([disabled]):not(.disabled):active,
|
||||
&:not([disabled]):not(.disabled).active {
|
||||
@include btn-shadow-inverse($success);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
@include btn-shadow($info);
|
||||
color: $white;
|
||||
|
||||
&:not([disabled]):not(.disabled):hover,
|
||||
&:not([disabled]):not(.disabled):focus,
|
||||
&:not([disabled]):not(.disabled):active,
|
||||
&:not([disabled]):not(.disabled).active {
|
||||
@include btn-shadow-inverse($info);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
@include btn-shadow($warning);
|
||||
color: $white;
|
||||
|
||||
&:not([disabled]):not(.disabled):hover,
|
||||
&:not([disabled]):not(.disabled):focus,
|
||||
&:not([disabled]):not(.disabled):active,
|
||||
&:not([disabled]):not(.disabled).active {
|
||||
@include btn-shadow-inverse($warning);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
@include btn-shadow($danger);
|
||||
|
||||
&:not([disabled]):not(.disabled):hover,
|
||||
&:not([disabled]):not(.disabled):focus,
|
||||
&:not([disabled]):not(.disabled):active,
|
||||
&:not([disabled]):not(.disabled).active {
|
||||
@include btn-shadow-inverse($danger);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-link,
|
||||
.btn-link:hover {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.btn-group,
|
||||
.btn-group-vertical {
|
||||
|
||||
.btn.active {
|
||||
border-color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
// Typography ==================================================================
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
text-shadow: -1px -1px 0 rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
// Tables ======================================================================
|
||||
|
||||
.table {
|
||||
|
||||
&-primary,
|
||||
&-secondary,
|
||||
&-success,
|
||||
&-info,
|
||||
&-warning,
|
||||
&-danger {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&-primary {
|
||||
&, > th, > td {
|
||||
background-color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
&-secondary {
|
||||
&, > th, > td {
|
||||
background-color: $secondary;
|
||||
}
|
||||
}
|
||||
|
||||
&-light {
|
||||
&, > th, > td {
|
||||
background-color: $light;
|
||||
}
|
||||
}
|
||||
|
||||
&-dark {
|
||||
&, > th, > td {
|
||||
background-color: $dark;
|
||||
}
|
||||
}
|
||||
|
||||
&-success {
|
||||
&, > th, > td {
|
||||
background-color: $success;
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
&, > th, > td {
|
||||
background-color: $info;
|
||||
}
|
||||
}
|
||||
|
||||
&-danger {
|
||||
&, > th, > td {
|
||||
background-color: $danger;
|
||||
}
|
||||
}
|
||||
|
||||
&-warning {
|
||||
&, > th, > td {
|
||||
background-color: $warning;
|
||||
}
|
||||
}
|
||||
|
||||
&-active {
|
||||
&, > th, > td {
|
||||
background-color: $table-active-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&-hover {
|
||||
|
||||
.table-primary:hover {
|
||||
&, > th, > td {
|
||||
background-color: darken($primary, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.table-secondary:hover {
|
||||
&, > th, > td {
|
||||
background-color: darken($secondary, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.table-light:hover {
|
||||
&, > th, > td {
|
||||
background-color: darken($light, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.table-dark:hover {
|
||||
&, > th, > td {
|
||||
background-color: darken($dark, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.table-success:hover {
|
||||
&, > th, > td {
|
||||
background-color: darken($success, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.table-info:hover {
|
||||
&, > th, > td {
|
||||
background-color: darken($info, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.table-danger:hover {
|
||||
&, > th, > td {
|
||||
background-color: darken($danger, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.table-warning:hover {
|
||||
&, > th, > td {
|
||||
background-color: darken($warning, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.table-active:hover {
|
||||
&, > th, > td {
|
||||
background-color: $table-active-bg;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Forms =======================================================================
|
||||
|
||||
legend {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
@include btn-shadow($secondary);
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
|
||||
color: $white;
|
||||
}
|
||||
|
||||
// Navs ========================================================================
|
||||
|
||||
.nav-tabs {
|
||||
|
||||
.nav-link {
|
||||
@include btn-shadow-inverse($gray-800);
|
||||
border: 1px solid rgba(0, 0, 0, 0.6);
|
||||
|
||||
&:not([disabled]):not(.disabled):hover,
|
||||
&:not([disabled]):not(.disabled):focus,
|
||||
&:not([disabled]):not(.disabled):active,
|
||||
&:not([disabled]):not(.disabled).active {
|
||||
@include btn-shadow($gray-800);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
border: 1px solid rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.nav-link,
|
||||
.nav-link:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-pills {
|
||||
|
||||
.nav-link {
|
||||
@include btn-shadow($gray-800);
|
||||
border: 1px solid rgba(0, 0, 0, 0.6);
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
@include btn-shadow-inverse($gray-800);
|
||||
border: 1px solid rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.nav-link.active,
|
||||
.nav-link:hover {
|
||||
background-color: transparent;
|
||||
@include btn-shadow-inverse($gray-800);
|
||||
border: 1px solid rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.nav-link.disabled,
|
||||
.nav-link.disabled:hover {
|
||||
@include btn-shadow($gray-800);
|
||||
color: $nav-link-disabled-color;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
|
||||
.page-link {
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
|
||||
@include btn-shadow($gray-800);
|
||||
|
||||
&:hover {
|
||||
@include btn-shadow-inverse($gray-800);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.page-item.active .page-link {
|
||||
@include btn-shadow-inverse($gray-800);
|
||||
}
|
||||
|
||||
.page-item.disabled .page-link {
|
||||
@include btn-shadow($gray-800);
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
border: 1px solid rgba(0, 0, 0, 0.6);
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
|
||||
background-color: transparent;
|
||||
@include btn-shadow($gray-800);
|
||||
|
||||
a,
|
||||
a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
// Indicators ==================================================================
|
||||
|
||||
.alert {
|
||||
|
||||
.close {
|
||||
color: $close-color;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.alert {
|
||||
border: none;
|
||||
color: $white;
|
||||
|
||||
a,
|
||||
.alert-link {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@each $color, $value in $theme-colors {
|
||||
&-#{$color} {
|
||||
background-color: $value;
|
||||
}
|
||||
}
|
||||
|
||||
&-light {
|
||||
&,
|
||||
& a:not(.btn),
|
||||
& .alert-link {
|
||||
color: $body-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
|
||||
&-success,
|
||||
&-warning,
|
||||
&-info {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
// Progress bars ===============================================================
|
||||
|
||||
// Containers ==================================================================
|
||||
|
||||
.jumbotron {
|
||||
border: 1px solid rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.list-group {
|
||||
|
||||
&-item:hover {
|
||||
background-color: darken($gray-900, 5%);
|
||||
}
|
||||
}
|
164
ffplayout/frontend/assets/css/_variables.scss
Executable file
164
ffplayout/frontend/assets/css/_variables.scss
Executable file
@ -0,0 +1,164 @@
|
||||
// Slate 4.3.1
|
||||
// Bootswatch
|
||||
|
||||
//
|
||||
// Color system
|
||||
//
|
||||
|
||||
$white: #fff !default;
|
||||
$gray-100: #f8f9fa !default;
|
||||
$gray-200: #e9ecef !default;
|
||||
$gray-300: #dee2e6 !default;
|
||||
$gray-400: #ced4da !default;
|
||||
$gray-500: #999 !default;
|
||||
$gray-600: #7A8288 !default;
|
||||
$gray-700: #52575C !default;
|
||||
$gray-800: #3A3F44 !default;
|
||||
$gray-900: #272B30 !default;
|
||||
$black: #000 !default;
|
||||
|
||||
$blue: #007bff !default;
|
||||
$indigo: #6610f2 !default;
|
||||
$purple: #6f42c1 !default;
|
||||
$pink: #e83e8c !default;
|
||||
$red: #ee5f5b !default;
|
||||
$orange: #fd7e14 !default;
|
||||
$yellow: #f89406 !default;
|
||||
$green: #62c462 !default;
|
||||
$teal: #20c997 !default;
|
||||
$cyan: #5bc0de !default;
|
||||
|
||||
$primary: $gray-800 !default;
|
||||
$secondary: $gray-600 !default;
|
||||
$success: $green !default;
|
||||
$info: $cyan !default;
|
||||
$warning: $yellow !default;
|
||||
$danger: $red !default;
|
||||
$light: $gray-200 !default;
|
||||
$dark: $gray-900 !default;
|
||||
|
||||
$yiq-contrasted-threshold: 170 !default;
|
||||
|
||||
// Body
|
||||
|
||||
$body-bg: $gray-900 !default;
|
||||
$body-color: #aaa !default;
|
||||
|
||||
// Links
|
||||
|
||||
$link-color: $white !default;
|
||||
|
||||
// Fonts
|
||||
|
||||
$font-size-base: 0.9375rem !default;
|
||||
|
||||
// Tables
|
||||
|
||||
$table-color: $white !default;
|
||||
$table-accent-bg: rgba($white,.05) !default;
|
||||
$table-hover-bg: rgba($white,.075) !default;
|
||||
|
||||
$table-border-color: rgba($black,.6) !default;
|
||||
|
||||
$table-dark-border-color: $table-border-color !default;
|
||||
$table-dark-color: $white !default;
|
||||
|
||||
// Buttons
|
||||
|
||||
$input-btn-padding-y: .75rem !default;
|
||||
$input-btn-padding-x: 1rem !default;
|
||||
|
||||
// Forms
|
||||
|
||||
$input-disabled-bg: #ccc !default;
|
||||
|
||||
// Dropdowns
|
||||
|
||||
$dropdown-bg: $gray-800 !default;
|
||||
$dropdown-border-color: rgba($black, .6) !default;
|
||||
$dropdown-divider-bg: rgba($black,.15) !default;
|
||||
|
||||
$dropdown-link-color: $body-color !default;
|
||||
$dropdown-link-hover-color: $white !default;
|
||||
$dropdown-link-hover-bg: $body-bg !default;
|
||||
|
||||
// Navs
|
||||
|
||||
$nav-tabs-border-color: rgba($black, 0.6) !default;
|
||||
$nav-tabs-link-hover-border-color: $nav-tabs-border-color !default;
|
||||
$nav-tabs-link-active-color: $white !default;
|
||||
$nav-tabs-link-active-border-color: $nav-tabs-border-color !default;
|
||||
|
||||
// Navbar
|
||||
|
||||
$navbar-padding-y: 0 !default;
|
||||
|
||||
$navbar-dark-hover-color: $white !default;
|
||||
|
||||
$navbar-light-hover-color: $gray-800 !default;
|
||||
$navbar-light-active-color: $gray-800 !default;
|
||||
|
||||
|
||||
// Pagination
|
||||
|
||||
$pagination-color: $white !default;
|
||||
$pagination-bg: transparent !default;
|
||||
$pagination-border-color: rgba($black, 0.6) !default;
|
||||
|
||||
$pagination-hover-color: $white !default;
|
||||
$pagination-hover-bg: transparent !default;
|
||||
$pagination-hover-border-color: rgba($black, 0.6) !default;
|
||||
|
||||
$pagination-active-bg: transparent !default;
|
||||
$pagination-active-border-color: rgba($black, 0.6) !default;
|
||||
|
||||
$pagination-disabled-bg: transparent !default;
|
||||
$pagination-disabled-border-color: rgba($black, 0.6) !default;
|
||||
|
||||
|
||||
// Jumbotron
|
||||
|
||||
$jumbotron-bg: darken($gray-900, 5%) !default;
|
||||
|
||||
// Cards
|
||||
|
||||
$card-border-color: rgba($black, 0.6) !default;
|
||||
$card-cap-bg: lighten($gray-800, 10%) !default;
|
||||
$card-bg: lighten($body-bg, 5%) !default;
|
||||
|
||||
// Popovers
|
||||
|
||||
$popover-bg: lighten($body-bg, 5%) !default;
|
||||
|
||||
// Modals
|
||||
|
||||
$modal-content-bg: lighten($body-bg, 5%) !default;
|
||||
|
||||
$modal-header-border-color: rgba(0,0,0,.2) !default;
|
||||
|
||||
// Progress bars
|
||||
|
||||
$progress-bg: darken($gray-900, 5%) !default;
|
||||
$progress-bar-color: $gray-600 !default;
|
||||
|
||||
// List group
|
||||
|
||||
$list-group-bg: lighten($body-bg, 5%) !default;
|
||||
$list-group-border-color: rgba($black, 0.6) !default;
|
||||
|
||||
$list-group-hover-bg: lighten($body-bg, 10%) !default;
|
||||
$list-group-active-color: $white !default;
|
||||
$list-group-active-bg: $list-group-hover-bg !default;
|
||||
$list-group-active-border-color: $list-group-border-color !default;
|
||||
|
||||
$list-group-disabled-color: $gray-700 !default;
|
||||
|
||||
$list-group-action-color: $white !default;
|
||||
|
||||
// Breadcrumbs
|
||||
|
||||
$breadcrumb-active-color: $gray-500 !default;
|
||||
|
||||
// Code
|
||||
|
||||
$pre-color: inherit !default;
|
12
ffplayout/frontend/assets/css/bootstrap.min.css
vendored
Normal file
12
ffplayout/frontend/assets/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
ffplayout/frontend/components/README.md
Normal file
7
ffplayout/frontend/components/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# COMPONENTS
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
The components directory contains your Vue.js Components.
|
||||
|
||||
_Nuxt.js doesn't supercharge these components._
|
7
ffplayout/frontend/layouts/README.md
Normal file
7
ffplayout/frontend/layouts/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# LAYOUTS
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
This directory contains your Application Layouts.
|
||||
|
||||
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts).
|
22
ffplayout/frontend/layouts/default.vue
Normal file
22
ffplayout/frontend/layouts/default.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div>
|
||||
<nuxt />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
font-family: 'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||||
Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
word-spacing: 1px;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
8
ffplayout/frontend/middleware/README.md
Normal file
8
ffplayout/frontend/middleware/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# MIDDLEWARE
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
This directory contains your application middleware.
|
||||
Middleware let you define custom functions that can be run before rendering either a page or a group of pages.
|
||||
|
||||
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware).
|
83
ffplayout/frontend/nuxt.config.js
Normal file
83
ffplayout/frontend/nuxt.config.js
Normal file
@ -0,0 +1,83 @@
|
||||
require('dotenv').config()
|
||||
|
||||
export default {
|
||||
mode: 'spa',
|
||||
/*
|
||||
** Headers of the page
|
||||
*/
|
||||
head: {
|
||||
title: process.env.npm_package_name || '',
|
||||
meta: [{
|
||||
charset: 'utf-8'
|
||||
},
|
||||
{
|
||||
name: 'viewport',
|
||||
content: 'width=device-width, initial-scale=1'
|
||||
},
|
||||
{
|
||||
hid: 'description',
|
||||
name: 'description',
|
||||
content: process.env.npm_package_description || ''
|
||||
}
|
||||
],
|
||||
link: [{
|
||||
rel: 'icon',
|
||||
type: 'image/x-icon',
|
||||
href: '/favicon.ico'
|
||||
}]
|
||||
},
|
||||
/*
|
||||
** Customize the progress-bar color
|
||||
*/
|
||||
loading: {
|
||||
color: '#ff9c36'
|
||||
},
|
||||
/*
|
||||
** Global CSS
|
||||
*/
|
||||
css: [
|
||||
'@/assets/css/bootstrap.min.css'
|
||||
],
|
||||
/*
|
||||
** Plugins to load before mounting the App
|
||||
*/
|
||||
plugins: [],
|
||||
/*
|
||||
** Nuxt.js dev-modules
|
||||
*/
|
||||
buildModules: [
|
||||
// Doc: https://github.com/nuxt-community/eslint-module
|
||||
'@nuxtjs/eslint-module'
|
||||
],
|
||||
/*
|
||||
** Nuxt.js modules
|
||||
*/
|
||||
modules: [
|
||||
// Doc: https://bootstrap-vue.js.org
|
||||
'bootstrap-vue/nuxt',
|
||||
// Doc: https://axios.nuxtjs.org/usage
|
||||
'@nuxtjs/axios',
|
||||
// Doc: https://github.com/nuxt-community/dotenv-module
|
||||
'@nuxtjs/dotenv'
|
||||
],
|
||||
/*
|
||||
** Axios module configuration
|
||||
** See https://axios.nuxtjs.org/options
|
||||
*/
|
||||
axios: {
|
||||
baseURL: process.env.API_URL
|
||||
},
|
||||
|
||||
bootstrapVue: {
|
||||
bootstrapCSS: false,
|
||||
},
|
||||
/*
|
||||
** Build configuration
|
||||
*/
|
||||
build: {
|
||||
/*
|
||||
** You can extend webpack config here
|
||||
*/
|
||||
extend(config, ctx) {}
|
||||
}
|
||||
}
|
10885
ffplayout/frontend/package-lock.json
generated
Normal file
10885
ffplayout/frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
ffplayout/frontend/package.json
Normal file
29
ffplayout/frontend/package.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "ffplayout",
|
||||
"version": "2.0.0",
|
||||
"description": "web GUI for ffplayout engine",
|
||||
"author": "Jonathan Baecker",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nuxt",
|
||||
"build": "nuxt build",
|
||||
"start": "nuxt start",
|
||||
"generate": "nuxt generate",
|
||||
"lint": "eslint --ext .js,.vue --ignore-path .gitignore ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxtjs/axios": "^5.3.6",
|
||||
"@nuxtjs/dotenv": "^1.4.0",
|
||||
"bootstrap": "^4.1.3",
|
||||
"bootstrap-vue": "^2.0.0",
|
||||
"jwt-decode": "^2.2.0",
|
||||
"nuxt": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxtjs/eslint-config": "^1.0.1",
|
||||
"@nuxtjs/eslint-module": "^1.0.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"eslint": "^6.1.0",
|
||||
"eslint-plugin-nuxt": ">=0.4.2"
|
||||
}
|
||||
}
|
6
ffplayout/frontend/pages/README.md
Normal file
6
ffplayout/frontend/pages/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
# PAGES
|
||||
|
||||
This directory contains your Application Views and Routes.
|
||||
The framework reads all the `*.vue` files inside this directory and creates the router of your application.
|
||||
|
||||
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing).
|
100
ffplayout/frontend/pages/index.vue
Normal file
100
ffplayout/frontend/pages/index.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<b-container class="login-container">
|
||||
<div>
|
||||
<div class="header">
|
||||
<h1>ffplayout</h1>
|
||||
</div>
|
||||
|
||||
<div v-if="!$store.state.auth.isLogin">
|
||||
<b-form @submit.prevent="login" class="login-form">
|
||||
<p v-if="formError" class="error">
|
||||
{{ formError }}
|
||||
</p>
|
||||
<b-form-group id="input-group-1" label="User:" label-for="input-user">
|
||||
<b-form-input id="input-user" v-model="formUsername" type="text" required placeholder="Username" />
|
||||
</b-form-group>
|
||||
<b-form-group id="input-group-1" label="Password:" label-for="input-pass">
|
||||
<b-form-input id="input-pass" v-model="formPassword" type="password" required placeholder="Password" />
|
||||
</b-form-group>
|
||||
<b-button type="submit" variant="primary">
|
||||
Login
|
||||
</b-button>
|
||||
</b-form>
|
||||
</div>
|
||||
<div v-else>
|
||||
<br>
|
||||
<br>
|
||||
<h3>Wellcome to ffplayout manager!</h3>
|
||||
</div>
|
||||
</div>
|
||||
</b-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
|
||||
data () {
|
||||
return {
|
||||
formError: null,
|
||||
formUsername: '',
|
||||
formPassword: ''
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
async init () {
|
||||
await this.$store.dispatch('auth/inspectToken')
|
||||
this.checkLogin()
|
||||
},
|
||||
async login () {
|
||||
try {
|
||||
await this.$store.dispatch('auth/obtainToken', {
|
||||
username: this.formUsername,
|
||||
password: this.formPassword
|
||||
})
|
||||
this.formUsername = ''
|
||||
this.formPassword = ''
|
||||
this.formError = null
|
||||
|
||||
this.checkLogin()
|
||||
} catch (e) {
|
||||
this.formError = e.message
|
||||
}
|
||||
},
|
||||
async logout () {
|
||||
try {
|
||||
await this.$store.commit('auth/REMOVE_TOKEN')
|
||||
await this.$store.commit('auth/UPDATE_IS_LOGIN', false)
|
||||
} catch (e) {
|
||||
this.formError = e.message
|
||||
}
|
||||
},
|
||||
checkLogin () {
|
||||
if (this.$store.state.auth.isLogin) {
|
||||
// this.$router.push('/player')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.login-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 3em;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
min-width: 300px;
|
||||
}
|
||||
</style>
|
7
ffplayout/frontend/plugins/README.md
Normal file
7
ffplayout/frontend/plugins/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# PLUGINS
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
This directory contains Javascript plugins that you want to run before mounting the root Vue.js application.
|
||||
|
||||
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins).
|
11
ffplayout/frontend/static/README.md
Normal file
11
ffplayout/frontend/static/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# STATIC
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
This directory contains your static files.
|
||||
Each file inside this directory is mapped to `/`.
|
||||
Thus you'd want to delete this README.md before deploying to production.
|
||||
|
||||
Example: `/static/robots.txt` is mapped as `/robots.txt`.
|
||||
|
||||
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static).
|
BIN
ffplayout/frontend/static/favicon.ico
Normal file
BIN
ffplayout/frontend/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
10
ffplayout/frontend/store/README.md
Normal file
10
ffplayout/frontend/store/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# STORE
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
This directory contains your Vuex Store files.
|
||||
Vuex Store option is implemented in the Nuxt.js framework.
|
||||
|
||||
Creating a file in this directory automatically activates the option in the framework.
|
||||
|
||||
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store).
|
85
ffplayout/frontend/store/auth.js
Normal file
85
ffplayout/frontend/store/auth.js
Normal file
@ -0,0 +1,85 @@
|
||||
/* eslint-disable camelcase */
|
||||
import jwt_decode from 'jwt-decode'
|
||||
|
||||
export const state = () => ({
|
||||
jwtToken: localStorage.getItem('token'),
|
||||
jwtRefresh: localStorage.getItem('refresh'),
|
||||
isLogin: false
|
||||
})
|
||||
|
||||
// mutate values in state
|
||||
export const mutations = {
|
||||
UPADTE_TOKEN (state, obj) {
|
||||
localStorage.setItem('token', obj.token)
|
||||
state.jwtToken = obj.token
|
||||
|
||||
if (obj.refresh) {
|
||||
localStorage.setItem('refresh', obj.refresh)
|
||||
state.jwtRefresh = obj.refresh
|
||||
}
|
||||
},
|
||||
REMOVE_TOKEN (state) {
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('refresh')
|
||||
state.jwtToken = null
|
||||
state.jwtRefresh = null
|
||||
},
|
||||
UPDATE_IS_LOGIN (state, bool) {
|
||||
state.isLogin = bool
|
||||
}
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
async obtainToken ({ commit, state }, { username, password }) {
|
||||
const payload = {
|
||||
username,
|
||||
password
|
||||
}
|
||||
await this.$axios.post('auth/token/', payload)
|
||||
.then((response) => {
|
||||
console.log('obtainToken: ', response)
|
||||
commit('UPADTE_TOKEN', { token: response.data.access, refresh: response.data.refresh })
|
||||
commit('UPDATE_IS_LOGIN', true)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
async refreshToken ({ commit, state }) {
|
||||
const payload = {
|
||||
refresh: state.jwtRefresh
|
||||
}
|
||||
const response = await this.$axios.post('auth/token/refresh/', payload)
|
||||
|
||||
console.log('refreshToken: ', response)
|
||||
commit('UPADTE_TOKEN', { token: response.data.access })
|
||||
commit('UPDATE_IS_LOGIN', true)
|
||||
},
|
||||
|
||||
async inspectToken ({ commit, dispatch, state }) {
|
||||
const token = state.jwtToken
|
||||
const refresh = state.jwtRefresh
|
||||
if (token && refresh) {
|
||||
const decoded_token = jwt_decode(token)
|
||||
const decoded_refresh = jwt_decode(refresh)
|
||||
const timestamp = Date.now() / 1000
|
||||
const expire_token = decoded_token.exp
|
||||
const expire_refresh = decoded_refresh.exp
|
||||
if (expire_token - timestamp > 0) {
|
||||
// DO NOTHING, DO NOT REFRESH
|
||||
commit('UPDATE_IS_LOGIN', true)
|
||||
console.log('token is valid, for: ' + Math.floor(expire_token - timestamp) + ' seconds')
|
||||
} else if (expire_refresh - timestamp > 0) {
|
||||
await dispatch('refreshToken')
|
||||
console.log('update token')
|
||||
} else {
|
||||
// PROMPT USER TO RE-LOGIN, THIS ELSE CLAUSE COVERS THE CONDITION WHERE A TOKEN IS EXPIRED AS WELL
|
||||
commit('UPDATE_IS_LOGIN', false)
|
||||
console.log('new login')
|
||||
}
|
||||
} else {
|
||||
commit('UPDATE_IS_LOGIN', false)
|
||||
console.log('new login')
|
||||
}
|
||||
}
|
||||
}
|
1
ffplayout/frontend/store/index.js
Normal file
1
ffplayout/frontend/store/index.js
Normal file
@ -0,0 +1 @@
|
||||
export const strict = false
|
Loading…
x
Reference in New Issue
Block a user