Change lint rules to AirBnB

This commit is contained in:
Alicia Sykes 2019-09-01 13:38:13 +01:00
parent 7ffc35afb6
commit 335c8eec53
18 changed files with 704 additions and 663 deletions

View File

@ -1,5 +1,5 @@
module.exports = { module.exports = {
presets: [ presets: [
'@vue/app' '@vue/app',
] ],
} };

40
package-lock.json generated
View File

@ -3521,6 +3521,12 @@
"typedarray": "^0.0.6" "typedarray": "^0.0.6"
} }
}, },
"confusing-browser-globals": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.8.tgz",
"integrity": "sha512-lI7asCibVJ6Qd3FGU7mu4sfG4try4LX3+GVS+Gv8UlrEf2AeW57piecapnog2UHZSbcX/P/1UDWVaTsblowlZg==",
"dev": true
},
"connect": { "connect": {
"version": "3.7.0", "version": "3.7.0",
"resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
@ -4700,6 +4706,28 @@
} }
} }
}, },
"eslint-config-airbnb": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.0.1.tgz",
"integrity": "sha512-hLb/ccvW4grVhvd6CT83bECacc+s4Z3/AEyWQdIT2KeTsG9dR7nx1gs7Iw4tDmGKozCNHFn4yZmRm3Tgy+XxyQ==",
"dev": true,
"requires": {
"eslint-config-airbnb-base": "^14.0.0",
"object.assign": "^4.1.0",
"object.entries": "^1.1.0"
}
},
"eslint-config-airbnb-base": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz",
"integrity": "sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA==",
"dev": true,
"requires": {
"confusing-browser-globals": "^1.0.7",
"object.assign": "^4.1.0",
"object.entries": "^1.1.0"
}
},
"eslint-config-standard": { "eslint-config-standard": {
"version": "12.0.0", "version": "12.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz",
@ -8231,6 +8259,18 @@
"object-keys": "^1.0.11" "object-keys": "^1.0.11"
} }
}, },
"object.entries": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz",
"integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.12.0",
"function-bind": "^1.1.1",
"has": "^1.0.3"
}
},
"object.getownpropertydescriptors": { "object.getownpropertydescriptors": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",

View File

@ -25,6 +25,7 @@
"@vue/eslint-config-standard": "^4.0.0", "@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.0.1", "babel-eslint": "^10.0.1",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-config-airbnb": "^18.0.1",
"eslint-plugin-vue": "^5.0.0", "eslint-plugin-vue": "^5.0.0",
"sass": "^1.18.0", "sass": "^1.18.0",
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
@ -37,9 +38,12 @@
}, },
"extends": [ "extends": [
"plugin:vue/essential", "plugin:vue/essential",
"@vue/standard" "@vue/standard",
"airbnb-base"
], ],
"rules": {}, "rules": {
"import/no-unresolved": "off"
},
"parserOptions": { "parserOptions": {
"parser": "babel-eslint" "parser": "babel-eslint"
} }

View File

@ -1,14 +1,13 @@
var connect = require('connect') const connect = require('connect');
var serveStatic = require('serve-static') const serveStatic = require('serve-static');
const port = process.env.PORT || 3002 const port = process.env.PORT || 3002;
try { /* eslint no-console: 0 */
connect() try {
.use(serveStatic(__dirname + '/dist')) connect()
.listen(port, () => .use(serveStatic(`${__dirname}/dist`))
console.log(`Boom, app is running on port ${port}`) .listen(port, () => console.log(`Boom, app is running on port ${port}`));
) } catch (error) {
} catch (error) { console.log('Something fucked up', error);
console.log('Something fucked up', error)
} }

View File

@ -7,14 +7,14 @@
</template> </template>
<script> <script>
import Footer from '@/components/Footer.vue' import Footer from '@/components/Footer.vue';
export default { export default {
name: 'app', name: 'app',
components: { components: {
Footer Footer,
} },
} };
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -1,108 +1,108 @@
<template> <template>
<div class="collapsable"> <div class="collapsable">
<input :id="`collapsible-${uniqueKey}`" class="toggle" type="checkbox" checked> <input :id="`collapsible-${uniqueKey}`" class="toggle" type="checkbox" checked>
<label :for="`collapsible-${uniqueKey}`" class="lbl-toggle" tabindex="0"> <label :for="`collapsible-${uniqueKey}`" class="lbl-toggle" tabindex="0">
<h2>{{ title }}</h2> <h2>{{ title }}</h2>
</label> </label>
<div class="collapsible-content"> <div class="collapsible-content">
<div class="content-inner"> <div class="content-inner">
<slot></slot> <slot></slot>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'CollapsableContainer', name: 'CollapsableContainer',
props: { props: {
uniqueKey: String, uniqueKey: String,
title: String title: String,
} },
} };
</script> </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss"> <style scoped lang="scss">
.collapsable { .collapsable {
width: 310px; width: 310px;
padding: 5px; padding: 5px;
margin: 10px; margin: 10px;
border-radius: 10px; border-radius: 10px;
background: #1CA8DD; background: #1CA8DD;
background: -webkit-linear-gradient(to left top, #9F86FF, #1CA8DD, #007AE1); background: -webkit-linear-gradient(to left top, #9F86FF, #1CA8DD, #007AE1);
background: linear-gradient(to left top, #9F86FF, #1CA8DD, #007AE1); background: linear-gradient(to left top, #9F86FF, #1CA8DD, #007AE1);
box-shadow: 1px 1px 2px #130f23; box-shadow: 1px 1px 2px #130f23;
.wrap-collabsible { .wrap-collabsible {
margin-bottom: 1.2rem 0; margin-bottom: 1.2rem 0;
} }
input[type='checkbox'] { input[type='checkbox'] {
display: none; display: none;
} }
label { label {
outline: none; outline: none;
} }
.lbl-toggle { .lbl-toggle {
display: block; display: block;
padding: 1rem; padding: 1rem;
cursor: pointer; cursor: pointer;
border-radius: 7px; border-radius: 7px;
transition: all 0.25s ease-out; transition: all 0.25s ease-out;
text-align: left; text-align: left;
color: #2f323ae6; color: #2f323ae6;
h2 { h2 {
margin: 0; margin: 0;
padding: 0; padding: 0;
display: inline; display: inline;
} }
} }
.lbl-toggle:hover { .lbl-toggle:hover {
color: #2f323a; color: #2f323a;
} }
.lbl-toggle::before { .lbl-toggle::before {
content: ' '; content: ' ';
display: inline-block; display: inline-block;
border-top: 5px solid transparent; border-top: 5px solid transparent;
border-bottom: 5px solid transparent; border-bottom: 5px solid transparent;
border-left: 5px solid currentColor; border-left: 5px solid currentColor;
vertical-align: middle; vertical-align: middle;
margin-right: .7rem; margin-right: .7rem;
transform: translateY(-2px); transform: translateY(-2px);
transition: transform .2s ease-out; transition: transform .2s ease-out;
} }
.toggle:checked + .lbl-toggle::before { .toggle:checked + .lbl-toggle::before {
transform: rotate(90deg) translateX(-3px); transform: rotate(90deg) translateX(-3px);
} }
.collapsible-content { .collapsible-content {
max-height: 0px; max-height: 0px;
overflow: hidden; overflow: hidden;
transition: max-height .25s ease-in-out; transition: max-height .25s ease-in-out;
background: #2f323ae6; background: #2f323ae6;
border-radius: 0 0 10px 10px; border-radius: 0 0 10px 10px;
} }
.toggle:checked + .lbl-toggle + .collapsible-content { .toggle:checked + .lbl-toggle + .collapsible-content {
max-height: 1000px; max-height: 1000px;
} }
.toggle:checked + .lbl-toggle { .toggle:checked + .lbl-toggle {
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
} }
.collapsible-content .content-inner { .collapsible-content .content-inner {
padding: 0.5rem; padding: 0.5rem;
} }
} }
</style> </style>

View File

@ -1,118 +1,119 @@
<template> <template>
<section> <section>
<form> <form>
<label for="filter-tiles">Search</label> <label for="filter-tiles">Search</label>
<input <input
id="filter-tiles" id="filter-tiles"
v-model="input" v-model="input"
ref="filter" ref="filter"
placeholder="Start typing to filter tiles..." placeholder="Start typing to filter tiles..."
v-on:input="userIsTypingSomething" v-on:input="userIsTypingSomething"
@keydown.esc="clearFilterInput" /> @keydown.esc="clearFilterInput" />
<i v-if="input.length > 0" <i v-if="input.length > 0"
class="el-icon-circle-close clear-search" class="el-icon-circle-close clear-search"
title="Clear search" title="Clear search"
@click="clearFilterInput"></i> @click="clearFilterInput"></i>
</form> </form>
<div class="space-filler"></div> <div class="space-filler"></div>
</section> </section>
</template> </template>
<script> <script>
export default { export default {
name: 'FilterTile', name: 'FilterTile',
data () { data() {
return { return {
input: '' input: '',
} };
}, },
methods: { methods: {
userIsTypingSomething () { userIsTypingSomething() {
this.$emit('user-is-searchin', this.input) this.$emit('user-is-searchin', this.input);
}, },
clearFilterInput () { clearFilterInput() {
this.input = '' this.input = '';
this.userIsTypingSomething() this.userIsTypingSomething();
document.activeElement.blur() document.activeElement.blur();
}, },
}, },
mounted: function() { mounted() {
window.addEventListener('keyup', (event) => { window.addEventListener('keyup', (event) => {
const key = event.key const { key } = event;
if(/^[a-zA-Z]$/.test(key) && !document.activeElement.id) { if (/^[a-zA-Z]$/.test(key) && !document.activeElement.id) {
this.input += key this.input += key;
this.$refs.filter.focus() this.$refs.filter.focus();
this.userIsTypingSomething() this.userIsTypingSomething();
} }
}); });
} },
} };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
section { section {
display: flex; display: flex;
align-items: center; align-items: center;
align-items: stretch; align-items: stretch;
background: linear-gradient(0deg, rgba(47,50,58,1) 0%, rgba(40,42,50,1) 100%); background: linear-gradient(0deg, rgba(47,50,58,1) 0%, rgba(40,42,50,1) 100%);
} }
form { form {
border-radius: 0 0 20px 0; border-radius: 0 0 20px 0;
padding: 0 0.2rem 0.2rem 0; padding: 0 0.2rem 0.2rem 0;
background: #282a32; background: #282a32;
label { label {
display: inline; display: inline;
background: -webkit-gradient(linear, right bottom, left top, from(#9F86FF), color-stop(#1CA8DD), to(#007AE1)); background: -webkit-gradient(
background: linear-gradient(to left top, #9F86FF, #1CA8DD, #007AE1); linear, right bottom, left top, from(#9F86FF), color-stop(#1CA8DD), to(#007AE1));
-webkit-background-clip: text; background: linear-gradient(to left top, #9F86FF, #1CA8DD, #007AE1);
-webkit-text-fill-color: transparent; -webkit-background-clip: text;
margin: 0.5rem; -webkit-text-fill-color: transparent;
display: inline; margin: 0.5rem;
} display: inline;
input { }
display: inline-block; input {
width: 200px; display: inline-block;
padding: 0.5rem; width: 200px;
margin: 0.5rem; padding: 0.5rem;
outline: none; margin: 0.5rem;
border: none; outline: none;
border-radius: 12px; border: none;
background: #607d8b33; border-radius: 12px;
box-shadow: 1px 1px 2px #232323; background: #607d8b33;
color: #1CA8DD; box-shadow: 1px 1px 2px #232323;
font-family: 'Comfortaa', cursive; color: #1CA8DD;
&:focus { font-family: 'Comfortaa', cursive;
background: #607d8b4a; &:focus {
} background: #607d8b4a;
} }
.clear-search { }
position: absolute; .clear-search {
margin: 1em 0 0 -2em; position: absolute;
color: #1CA8DD; margin: 1em 0 0 -2em;
opacity: 0.5; color: #1CA8DD;
border-radius: 50px; opacity: 0.5;
cursor: pointer; border-radius: 50px;
&:hover { cursor: pointer;
opacity: 1; &:hover {
background: #282a32; opacity: 1;
} background: #282a32;
} }
} }
.space-filler { }
flex: 1; .space-filler {
border-radius: 20px 0 0; flex: 1;
background: #2f323a; border-radius: 20px 0 0;
} background: #2f323a;
@media screen and (max-width: 600px) { }
form { @media screen and (max-width: 600px) {
flex: 1; form {
border-radius: 0; flex: 1;
text-align: center; border-radius: 0;
padding: 0.25rem 0; text-align: center;
} padding: 0.25rem 0;
.space-filler { }
display: none; .space-filler {
} display: none;
} }
</style> }
</style>

View File

@ -1,41 +1,41 @@
<template> <template>
<footer> <footer>
Developed by <a :href="authorUrl">{{authorName}}</a>. Developed by <a :href="authorUrl">{{authorName}}</a>.
Licensed under <a :href="licenseUrl">{{license}}</a> Licensed under <a :href="licenseUrl">{{license}}</a>
{{ showCopyright? '©': '' }} {{date}}. {{ showCopyright? '©': '' }} {{date}}.
Get the <a :href="repoUrl">Source Code</a>. Get the <a :href="repoUrl">Source Code</a>.
</footer> </footer>
</template> </template>
<script> <script>
export default { export default {
name: 'Footer', name: 'Footer',
props: { props: {
authorName: { type: String, default: 'Alicia Sykes' }, authorName: { type: String, default: 'Alicia Sykes' },
authorUrl: { type: String, default: 'https://aliciasykes.com' }, authorUrl: { type: String, default: 'https://aliciasykes.com' },
license: { type: String, default: 'MIT' }, license: { type: String, default: 'MIT' },
licenseUrl: { type: String, default: 'https://gist.github.com/Lissy93/143d2ee01ccc5c052a17' }, licenseUrl: { type: String, default: 'https://gist.github.com/Lissy93/143d2ee01ccc5c052a17' },
date: { type: String, default: `${new Date().getFullYear()}` }, date: { type: String, default: `${new Date().getFullYear()}` },
showCopyright: { type: Boolean, default: true }, showCopyright: { type: Boolean, default: true },
repoUrl: { type: String, default: 'https://github.com/lissy93/panel' } repoUrl: { type: String, default: 'https://github.com/lissy93/panel' },
} },
} };
</script> </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss"> <style scoped lang="scss">
footer { footer {
padding: 0.5rem; padding: 0.5rem;
text-align: center; text-align: center;
color: #5e6474; color: #5e6474;
} }
footer a{ footer a{
color: #5e6474; color: #5e6474;
&:hover { &:hover {
color: #9F86FF; color: #9F86FF;
} }
} }
</style> </style>

View File

@ -1,33 +1,34 @@
<template> <template>
<header> <header>
<PageTitle /> <PageTitle />
<Nav class="nav"/> <Nav class="nav"/>
</header> </header>
</template> </template>
<script> <script>
import PageTitle from '@/components/PageTitle.vue' import PageTitle from '@/components/PageTitle.vue';
import Nav from '@/components/Nav.vue' import Nav from '@/components/Nav.vue';
export default {
name: 'Header', export default {
components: { name: 'Header',
PageTitle, components: {
Nav PageTitle,
} Nav,
} },
</script> };
</script>
<style scoped lang="scss">
header { <style scoped lang="scss">
margin: 0; header {
padding: 0.5rem; margin: 0;
display: flex; padding: 0.5rem;
justify-content: space-between; display: flex;
background: #282a32; justify-content: space-between;
align-items: center; background: #282a32;
align-content: flex-start; align-items: center;
@media screen and (max-width: 600px) { align-content: flex-start;
flex-direction: column-reverse; @media screen and (max-width: 600px) {
} flex-direction: column-reverse;
} }
</style> }
</style>

View File

@ -9,9 +9,9 @@
export default { export default {
name: 'HelloWorld', name: 'HelloWorld',
props: { props: {
msg: String msg: String,
} },
} };
</script> </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <!-- Add "scoped" attribute to limit CSS to this component only -->

View File

@ -1,136 +1,134 @@
<template> <template>
<el-tooltip placement="bottom" effect="dark" :content="description" :disabled="!description"> <el-tooltip placement="bottom" effect="dark" :content="description" :disabled="!description">
<div class="item" tabindex="0"> <div class="item" tabindex="0">
<div class="tile-title" :id="`tile-${id}`"> <div class="tile-title" :id="`tile-${id}`">
<span class="text">{{ title }}</span> <span class="text">{{ title }}</span>
<div class="overflow-dots">...</div> <div class="overflow-dots">...</div>
</div> </div>
<img <img
v-if="icon" v-if="icon"
:src="`/img/tile-icons/${icon}.png`" :src="`/img/tile-icons/${icon}.png`"
class="tile-icon" class="tile-icon"
/> />
</div> </div>
</el-tooltip> </el-tooltip>
</template> </template>
<script> <script>
export default { export default {
name: 'Item', name: 'Item',
props: { props: {
id: String, // The unique ID of a tile (e.g. 001) id: String, // The unique ID of a tile (e.g. 001)
title: String, // The main text of tile, required title: String, // The main text of tile, required
subtitle: String, // Optional sub-text subtitle: String, // Optional sub-text
description: String, // Optional tooltip hover text description: String, // Optional tooltip hover text
icon: String, // Optional path to icon, within public/img/tile-icons icon: String, // Optional path to icon, within public/img/tile-icons
color: String, // Optional background color, specified in hex code color: String, // Optional background color, specified in hex code
url: String, // URL to the resource, optional but recommended url: String, // URL to the resource, optional but recommended
openingMethod: { // Where resource will open, either 'newtab', 'sametab' or 'iframe' openingMethod: { // Where resource will open, either 'newtab', 'sametab' or 'iframe'
type: String, type: String,
default: 'newtab', default: 'newtab',
validator: (value) => validator: (value) => ['newtab', 'sametab', 'iframe'].indexOf(value) !== -1,
['newtab', 'sametab', 'iframe'].indexOf(value) !== -1 },
} },
}, data() {
data () { return { getId: this.id };
return { getId: this.id } },
}, mounted() {
mounted () { // Detects overflowing text, and allows is to marguee on hover
// Detects overflowing text, and allows is to marguee on hover // The below code is horifically bad, it is embarassing that I wrote it...
// The below code is horifically bad, it is embarassing that I wrote it... const tileElem = document.getElementById(`tile-${this.getId}`);
const tileElem = document.getElementById(`tile-${this.getId}`) if (tileElem) {
if (tileElem) { const isOverflowing = tileElem.scrollHeight > tileElem.clientHeight
const isOverflowing = || tileElem.scrollWidth > tileElem.clientWidth;
tileElem.scrollHeight > tileElem.clientHeight || if (isOverflowing) {
tileElem.scrollWidth > tileElem.clientWidth tileElem.className += ' is-overflowing';
if (isOverflowing) { }
tileElem.className += ' is-overflowing' }
} },
} };
} </script>
}
</script> <!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss"> .item {
width: 120px;
.item { height: 100px;
width: 120px; color: #1CA8DD;
height: 100px; display: inline-block;
color: #1CA8DD; vertical-align: middle;
display: inline-block; margin: 8px;
vertical-align: middle; background: #607d8b33;
margin: 8px; text-align: center;
background: #607d8b33; padding: 2px;
text-align: center; border: 2px solid transparent;
padding: 2px; border-radius: 10px;
border: 2px solid transparent; box-shadow: 1px 1px 2px #373737;
border-radius: 10px; cursor: pointer;
box-shadow: 1px 1px 2px #373737; &:hover {
cursor: pointer; box-shadow: 1px 2px 4px #373737;
&:hover { background: #607d8b4d;
box-shadow: 1px 2px 4px #373737; }
background: #607d8b4d; &:focus {
} border: 2px solid #1CA8DD;
&:focus { outline: none;
border: 2px solid #1CA8DD; }
outline: none; }
} .tile-title {
} white-space: nowrap;
.tile-title { overflow: hidden;
white-space: nowrap; text-overflow: ellipsis;
overflow: hidden; width: 120px;
text-overflow: ellipsis; height: 30px;
width: 120px; overflow: hidden;
height: 30px; position: relative;
overflow: hidden; padding: 0;
position: relative;
padding: 0; span.text {
position: absolute;
span.text { white-space: nowrap;
position: absolute; transition: 1s;
white-space: nowrap; float: left;
transition: 1s; left: 0;
float: left; }
left: 0; &:not(.is-overflowing) span.text{
} width: 100%;
&:not(.is-overflowing) span.text{ }
width: 100%; .overflow-dots {
} // display: none;
.overflow-dots { opacity: 0;
// display: none; }
opacity: 0; }
}
} .tile-title.is-overflowing {
span.text {
.tile-title.is-overflowing { overflow: hidden;
span.text { }
overflow: hidden; .overflow-dots {
} display: block;
.overflow-dots { opacity: 1;
display: block; background: #354857;
opacity: 1; position: absolute;
background: #354857; z-index: 5;
position: absolute; right: 0;
z-index: 5; transition: opacity 0.1s ease-in;
right: 0; }
transition: opacity 0.1s ease-in; }
}
} .item:hover .tile-title{
.overflow-dots {
.item:hover .tile-title{ // display: none;
.overflow-dots { opacity: 0;
// display: none; }
opacity: 0; span.text {
} transform: translateX(calc(120px - 100%));
span.text { }
transform: translateX(calc(120px - 100%)); }
}
} .tile-icon {
width: 60px;
.tile-icon { }
width: 60px;
} </style>
</style>

View File

@ -1,55 +1,55 @@
<template> <template>
<Collapsable :title="title" :uniqueKey="groupId"> <Collapsable :title="title" :uniqueKey="groupId">
<div v-if="!items || items.length < 1" class="no-items"> <div v-if="!items || items.length < 1" class="no-items">
No Items to Show Yet No Items to Show Yet
</div> </div>
<div v-else class="there-are-items"> <div v-else class="there-are-items">
<Item <Item
v-for="item in items" v-for="item in items"
:key="`${groupId}-${item.id}`" :key="`${groupId}-${item.id}`"
:id="`${groupId}-${item.id}`" :id="`${groupId}-${item.id}`"
:title="item.title" :title="item.title"
:description="item.description" :description="item.description"
:icon="item.icon" :icon="item.icon"
/> />
</div> </div>
</Collapsable> </Collapsable>
</template> </template>
<script> <script>
import Item from '@/components/Item.vue' import Item from '@/components/Item.vue';
import Collapsable from '@/components/Collapsable.vue' import Collapsable from '@/components/Collapsable.vue';
export default { export default {
name: 'ItemGroup', name: 'ItemGroup',
props: { props: {
groupId: String, groupId: String,
title: String, title: String,
items: Array items: Array,
}, },
components: { components: {
Collapsable, Collapsable,
Item Item,
} },
} };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.no-items { .no-items {
width: 100px; width: 100px;
margin: 0 auto; margin: 0 auto;
padding: 0.8rem; padding: 0.8rem;
text-align: center; text-align: center;
cursor: default; cursor: default;
border-radius: 10px; border-radius: 10px;
background: #607d8b33; background: #607d8b33;
color: #1CA8DD; color: #1CA8DD;
box-shadow: 1px 1px 2px #373737; box-shadow: 1px 1px 2px #373737;
} }
.there-are-items { .there-are-items {
height: 100%; height: 100%;
} }
</style> </style>

View File

@ -1,41 +1,41 @@
<template> <template>
<nav id="nav"> <nav id="nav">
<router-link to="/" class="nav-item">Home</router-link> <router-link to="/" class="nav-item">Home</router-link>
<router-link to="/about" class="nav-item">About</router-link> <router-link to="/about" class="nav-item">About</router-link>
</nav> </nav>
</template> </template>
<script> <script>
export default { export default {
name: 'Nav' name: 'Nav',
} };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
nav { nav {
display: flex; display: flex;
align-items: center; align-items: center;
.nav-item { .nav-item {
display: inline-block; display: inline-block;
padding: 0.75rem 0.5rem; padding: 0.75rem 0.5rem;
margin: 0.5rem; margin: 0.5rem;
outline: none; outline: none;
border: none; border: none;
border-radius: 5px; border-radius: 5px;
background: #607d8b33; background: #607d8b33;
-webkit-box-shadow: 1px 1px 2px #232323; -webkit-box-shadow: 1px 1px 2px #232323;
box-shadow: 1px 1px 2px #232323; box-shadow: 1px 1px 2px #232323;
color: #1CA8DD; color: #1CA8DD;
font-family: "Comfortaa", cursive; font-family: "Comfortaa", cursive;
text-decoration: none; text-decoration: none;
&:hover { &:hover {
background: #607d8b1c; background: #607d8b1c;
box-shadow: 1px 4px 3px #232323; box-shadow: 1px 4px 3px #232323;
} }
} }
.router-link-active { .router-link-active {
border: 1px solid #1CA8DD; border: 1px solid #1CA8DD;
} }
} }
</style> </style>

View File

@ -1,36 +1,36 @@
<template> <template>
<div class="page-titles"> <div class="page-titles">
<h1>Pannel</h1> <h1>Pannel</h1>
<span class="subtitle">Awesome subtitle</span> <span class="subtitle">Awesome subtitle</span>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'PageTitle' name: 'PageTitle',
} };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.page-titles { .page-titles {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
h1 { h1 {
background: -webkit-linear-gradient(to left top, #9F86FF, #1CA8DD, #007AE1); background: -webkit-linear-gradient(to left top, #9F86FF, #1CA8DD, #007AE1);
background: linear-gradient(to left top, #9F86FF, #1CA8DD, #007AE1); background: linear-gradient(to left top, #9F86FF, #1CA8DD, #007AE1);
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
font-size: 3rem; font-size: 3rem;
margin: 0; margin: 0;
} }
span.subtitle { span.subtitle {
color: #9F86FF; color: #9F86FF;
font-style: italic; font-style: italic;
text-shadow: 1px 1px 2px #130f23; text-shadow: 1px 1px 2px #130f23;
} }
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
text-align: center; text-align: center;
padding: 0.25rem 0; padding: 0.25rem 0;
} }
} }
</style> </style>

View File

@ -1,14 +1,14 @@
import Vue from 'vue' import Vue from 'vue';
import Element from 'element-ui' import Element from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'; import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue' import App from './App.vue';
import router from './router' import router from './router';
import './registerServiceWorker' import './registerServiceWorker';
Vue.use(Element) Vue.use(Element);
Vue.config.productionTip = false Vue.config.productionTip = false;
new Vue({ new Vue({
router, router,
render: h => h(App) render: (h) => h(App),
}).$mount('#app') }).$mount('#app');

View File

@ -1,32 +1,32 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import { register } from 'register-service-worker' import { register } from 'register-service-worker';
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, { register(`${process.env.BASE_URL}service-worker.js`, {
ready () { ready() {
console.log( console.log(
'App is being served from cache by a service worker.\n' + 'App is being served from cache by a service worker.\n'
'For more details, visit https://goo.gl/AFskqB' + 'For more details, visit https://goo.gl/AFskqB',
) );
}, },
registered () { registered() {
console.log('Service worker has been registered.') console.log('Service worker has been registered.');
}, },
cached () { cached() {
console.log('Content has been cached for offline use.') console.log('Content has been cached for offline use.');
}, },
updatefound () { updatefound() {
console.log('New content is downloading.') console.log('New content is downloading.');
}, },
updated () { updated() {
console.log('New content is available; please refresh.') console.log('New content is available; please refresh.');
}, },
offline () { offline() {
console.log('No internet connection found. App is running in offline mode.') console.log('No internet connection found. App is running in offline mode.');
}, },
error (error) { error(error) {
console.error('Error during service worker registration:', error) console.error('Error during service worker registration:', error);
} },
}) });
} }

View File

@ -1,15 +1,15 @@
import Vue from 'vue' import Vue from 'vue';
import Router from 'vue-router' import Router from 'vue-router';
import Home from './views/Home.vue' import Home from './views/Home.vue';
Vue.use(Router) Vue.use(Router);
export default new Router({ export default new Router({
routes: [ routes: [
{ {
path: '/', path: '/',
name: 'home', name: 'home',
component: Home component: Home,
}, },
{ {
path: '/about', path: '/about',
@ -17,7 +17,7 @@ export default new Router({
// route level code-splitting // route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route // this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited. // which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ './views/About.vue') component: () => import(/* webpackChunkName: "about" */ './views/About.vue'),
} },
] ],
}) });

View File

@ -17,47 +17,45 @@
<script> <script>
import Header from '@/components/Header.vue' import Header from '@/components/Header.vue';
import FilterTile from '@/components/FilterTile.vue' import FilterTile from '@/components/FilterTile.vue';
import ItemGroup from '@/components/ItemGroup.vue' import ItemGroup from '@/components/ItemGroup.vue';
import * as linkData from './../data/item-data.json' import * as linkData from '../data/item-data.json';
export default { export default {
name: 'home', name: 'home',
props: { props: {
title: { default: 'Panel', type: String }, title: { default: 'Panel', type: String },
subtitle: { default: 'All your server management tools in one place', type: String } subtitle: { default: 'All your server management tools in one place', type: String },
}, },
components: { components: {
Header, Header,
FilterTile, FilterTile,
ItemGroup ItemGroup,
},
data: () => {
return {
items: linkData.default,
searchTile: ''
}
}, },
data: () => ({
items: linkData.default,
searchTile: '',
}),
methods: { methods: {
searching (searchTile) { searching(searchTile) {
this.searchTile = searchTile this.searchTile = searchTile;
}, },
getDomainFromUrl (url) { getDomainFromUrl(url) {
var urlPattern = /^(?:https?:\/\/)?(?:w{3}\.)?([a-z\d\.-]+)\.(?:[a-z\.]{2,10})(?:[/\w\.-]*)*/; const urlPattern = /^(?:https?:\/\/)?(?:w{3}\.)?([a-z\d.-]+)\.(?:[a-z.]{2,10})(?:[/\w.-]*)*/;
var domainPattern = url.match(urlPattern); const domainPattern = url.match(urlPattern);
return domainPattern? domainPattern[1] : '' return domainPattern ? domainPattern[1] : '';
}, },
filterTiles (allTiles) { filterTiles(allTiles) {
return allTiles.filter(tile => { return allTiles.filter((tile) => {
const searchTerm = this.searchTile.toLowerCase() const searchTerm = this.searchTile.toLowerCase();
return tile.title.toLowerCase().includes(searchTerm) || return tile.title.toLowerCase().includes(searchTerm)
tile.provider.toLowerCase().includes(searchTerm) || || tile.provider.toLowerCase().includes(searchTerm)
this.getDomainFromUrl(tile.url).includes(searchTerm) || this.getDomainFromUrl(tile.url).includes(searchTerm);
}) });
} },
} },
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>