362 lines
8.7 KiB
Vue
362 lines
8.7 KiB
Vue
<template>
|
|
<v-app id="speckle">
|
|
<v-app-bar app color="background2" flat class="no-decor">
|
|
<v-container class="py-0 fill-height">
|
|
<v-btn text to="/" active-class="no-active">
|
|
<v-img
|
|
contain
|
|
max-height="30"
|
|
max-width="30"
|
|
src="./assets/logo.svg"
|
|
/>
|
|
<div class="mt-1">
|
|
<span class="primary--text"><b>SPECKLE</b></span>
|
|
<!--
|
|
<span class="font-weight-light">ADMIN</span> -->
|
|
</div>
|
|
</v-btn>
|
|
|
|
<v-btn
|
|
v-for="link in navLinks"
|
|
:key="link.name"
|
|
text
|
|
class="text-uppercase"
|
|
:to="link.link"
|
|
>
|
|
{{ link.name }}
|
|
</v-btn>
|
|
|
|
<v-spacer></v-spacer>
|
|
<v-responsive max-width="300">
|
|
<v-autocomplete
|
|
v-model="selectedSearchResult"
|
|
:loading="$apollo.loading"
|
|
:items="streams.items"
|
|
:search-input.sync="search"
|
|
no-filter
|
|
counter="3"
|
|
rounded
|
|
filled
|
|
dense
|
|
flat
|
|
hide-no-data
|
|
hide-details
|
|
placeholder="Search streams..."
|
|
item-text="name"
|
|
item-value="id"
|
|
return-object
|
|
clearable
|
|
append-icon=""
|
|
>
|
|
<template #item="{ item }" color="background">
|
|
<v-list-item-content>
|
|
<v-list-item-title>
|
|
<v-row class="pa-0 ma-0">
|
|
{{ item.name }}
|
|
<v-spacer></v-spacer>
|
|
<span class="streamid">{{ item.id }}</span>
|
|
</v-row>
|
|
</v-list-item-title>
|
|
<v-list-item-subtitle
|
|
v-text="item.description"
|
|
></v-list-item-subtitle>
|
|
<v-list-item-subtitle class="caption">
|
|
Updated
|
|
<timeago :datetime="item.updatedAt"></timeago>
|
|
</v-list-item-subtitle>
|
|
</v-list-item-content>
|
|
</template>
|
|
</v-autocomplete>
|
|
</v-responsive>
|
|
<v-menu v-if="user" bottom left offset-y class="userMenu">
|
|
<template #activator="{ on, attrs }">
|
|
<v-btn
|
|
icon
|
|
v-bind="attrs"
|
|
height="38"
|
|
width="38"
|
|
class="ml-3"
|
|
v-on="on"
|
|
>
|
|
<v-avatar color="background" size="38">
|
|
<v-img v-if="user.avatar" :src="user.avatar" />
|
|
<v-img
|
|
v-else
|
|
:src="`https://robohash.org/` + user.id + `.png?size=38x38`"
|
|
/>
|
|
</v-avatar>
|
|
</v-btn>
|
|
</template>
|
|
<v-list dense class="userMenu" color="background2">
|
|
<v-list-item>
|
|
<v-list-item-content class="caption">
|
|
Signed in as:
|
|
<strong>{{ user.name }}</strong>
|
|
</v-list-item-content>
|
|
</v-list-item>
|
|
<v-divider></v-divider>
|
|
<v-list-item
|
|
v-if="!this.$vuetify.theme.dark"
|
|
link
|
|
@click="switchTheme"
|
|
>
|
|
<v-list-item-content>Dark mode</v-list-item-content>
|
|
<v-list-item-icon>
|
|
<v-icon>mdi-weather-night</v-icon>
|
|
</v-list-item-icon>
|
|
</v-list-item>
|
|
<v-list-item v-else exact @click="switchTheme">
|
|
<v-list-item-content>Light mode</v-list-item-content>
|
|
<v-list-item-icon>
|
|
<v-icon>mdi-white-balance-sunny</v-icon>
|
|
</v-list-item-icon>
|
|
</v-list-item>
|
|
<!-- <v-list-item href="https://speckle.systems/" target="_blank">
|
|
<v-list-item-content>SpeckleSystems</v-list-item-content>
|
|
</v-list-item> -->
|
|
<v-list-item @click="signOut">
|
|
<v-list-item-content>Sign out</v-list-item-content>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-menu>
|
|
</v-container>
|
|
</v-app-bar>
|
|
|
|
<v-main :style="background">
|
|
<router-view></router-view>
|
|
</v-main>
|
|
</v-app>
|
|
</template>
|
|
<script>
|
|
import userQuery from "./graphql/user.gql"
|
|
import gql from "graphql-tag"
|
|
|
|
export default {
|
|
data: () => ({
|
|
search: "",
|
|
streams: { items: [] },
|
|
selectedSearchResult: null,
|
|
navLinks: [
|
|
{ link: "/streams", name: "streams" },
|
|
{ link: "/help", name: "help" }
|
|
]
|
|
}),
|
|
apollo: {
|
|
user: {
|
|
prefetch: true,
|
|
query: userQuery
|
|
},
|
|
streams: {
|
|
query: gql`
|
|
query Streams($query: String) {
|
|
streams(query: $query) {
|
|
totalCount
|
|
cursor
|
|
items {
|
|
id
|
|
name
|
|
description
|
|
updatedAt
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
variables() {
|
|
return {
|
|
query: this.search
|
|
}
|
|
},
|
|
skip() {
|
|
return !this.search || this.search.length < 3
|
|
},
|
|
debounce: 300
|
|
}
|
|
},
|
|
computed: {
|
|
background() {
|
|
let theme = this.$vuetify.theme.dark ? "dark" : "light"
|
|
return `background-color: ${this.$vuetify.theme.themes[theme].background};`
|
|
}
|
|
},
|
|
watch: {
|
|
selectedSearchResult(val) {
|
|
this.search = ""
|
|
this.streams.items = []
|
|
if (val)
|
|
this.$router.push({ name: "stream", params: { streamId: val.id } })
|
|
},
|
|
"streams.items"(val) {
|
|
console.log(val)
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
switchTheme() {
|
|
this.$vuetify.theme.dark = !this.$vuetify.theme.dark
|
|
localStorage.setItem(
|
|
"darkModeEnabled",
|
|
this.$vuetify.theme.dark ? "dark" : "light"
|
|
)
|
|
},
|
|
signOut() {
|
|
localStorage.clear()
|
|
location.reload()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style>
|
|
.v-card__text,
|
|
.v-card__title {
|
|
word-break: normal !important;
|
|
}
|
|
|
|
.streamid {
|
|
font-family: monospace !important;
|
|
}
|
|
|
|
a {
|
|
text-decoration: none;
|
|
}
|
|
|
|
a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.no-decor a:hover {
|
|
text-decoration: none;
|
|
}
|
|
|
|
.v-btn--active.no-active::before {
|
|
opacity: 0 !important;
|
|
}
|
|
|
|
/* .theme--dark {
|
|
/color: #cfcdcc !important;
|
|
} */
|
|
|
|
/* don't like fat text */
|
|
.v-list-item--dense .v-list-item__title,
|
|
.v-list-item--dense .v-list-item__subtitle,
|
|
.v-list--dense .v-list-item .v-list-item__title,
|
|
.v-list--dense .v-list-item .v-list-item__subtitle {
|
|
font-weight: 400 !important;
|
|
}
|
|
|
|
/* DARK MODE HARD FIXES */
|
|
|
|
.theme--dark.v-list {
|
|
background-color: #303132 !important;
|
|
}
|
|
|
|
/* TOOLTIPs */
|
|
|
|
.tooltip {
|
|
display: block !important;
|
|
z-index: 10000;
|
|
font-family: "Roboto", sans-serif !important;
|
|
font-size: 0.75rem !important;
|
|
}
|
|
|
|
.tooltip .tooltip-inner {
|
|
background: rgba(0, 0, 0, 0.5);
|
|
color: white;
|
|
border-radius: 16px;
|
|
padding: 5px 10px 4px;
|
|
}
|
|
|
|
.tooltip .tooltip-arrow {
|
|
width: 0;
|
|
height: 0;
|
|
border-style: solid;
|
|
position: absolute;
|
|
margin: 5px;
|
|
border-color: rgba(0, 0, 0, 0.5);
|
|
z-index: 1;
|
|
}
|
|
|
|
.tooltip[x-placement^="top"] {
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.tooltip[x-placement^="top"] .tooltip-arrow {
|
|
border-width: 5px 5px 0 5px;
|
|
border-left-color: transparent !important;
|
|
border-right-color: transparent !important;
|
|
border-bottom-color: transparent !important;
|
|
bottom: -5px;
|
|
left: calc(50% - 5px);
|
|
margin-top: 0;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.tooltip[x-placement^="bottom"] {
|
|
margin-top: 5px;
|
|
}
|
|
|
|
.tooltip[x-placement^="bottom"] .tooltip-arrow {
|
|
border-width: 0 5px 5px 5px;
|
|
border-left-color: transparent !important;
|
|
border-right-color: transparent !important;
|
|
border-top-color: transparent !important;
|
|
top: -5px;
|
|
left: calc(50% - 5px);
|
|
margin-top: 0;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.tooltip[x-placement^="right"] {
|
|
margin-left: 5px;
|
|
}
|
|
|
|
.tooltip[x-placement^="right"] .tooltip-arrow {
|
|
border-width: 5px 5px 5px 0;
|
|
border-left-color: transparent !important;
|
|
border-top-color: transparent !important;
|
|
border-bottom-color: transparent !important;
|
|
left: -5px;
|
|
top: calc(50% - 5px);
|
|
margin-left: 0;
|
|
margin-right: 0;
|
|
}
|
|
|
|
.tooltip[x-placement^="left"] {
|
|
margin-right: 5px;
|
|
}
|
|
|
|
.tooltip[x-placement^="left"] .tooltip-arrow {
|
|
border-width: 5px 0 5px 5px;
|
|
border-top-color: transparent !important;
|
|
border-right-color: transparent !important;
|
|
border-bottom-color: transparent !important;
|
|
right: -5px;
|
|
top: calc(50% - 5px);
|
|
margin-left: 0;
|
|
margin-right: 0;
|
|
}
|
|
|
|
.tooltip.popover .popover-inner {
|
|
background: #f9f9f9;
|
|
color: black;
|
|
padding: 24px;
|
|
border-radius: 5px;
|
|
box-shadow: 0 5px 30px rgba(black, 0.1);
|
|
}
|
|
|
|
.tooltip.popover .popover-arrow {
|
|
border-color: #f9f9f9;
|
|
}
|
|
|
|
.tooltip[aria-hidden="true"] {
|
|
visibility: hidden;
|
|
opacity: 0;
|
|
transition: opacity 0.15s, visibility 0.15s;
|
|
}
|
|
|
|
.tooltip[aria-hidden="false"] {
|
|
visibility: visible;
|
|
opacity: 1;
|
|
transition: opacity 0.15s;
|
|
}
|
|
</style>
|