mirror of https://github.com/Lissy93/dashy.git
Merge pull request #38 from Lissy93/feature_workspace-view
Feature workspace view
This commit is contained in:
commit
b5f8c85522
|
@ -299,6 +299,13 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWAREOR THE
|
|||
OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
```
|
||||
|
||||
#### Author 🦄
|
||||
<p align="right"><img width="200" src="https://i.ibb.co/FnxqTfx/aht-bot-round.png" alt="Alicia Sykes"></p>
|
||||
Developed by [Alicia Sykes](https://aliciasykes.com) ([@Lissy93](https://github.com/lissy93)) in 2021.
|
||||
|
||||
- **PGP Key**: [`0688 F8D3 4587 D954 E9E5 1FB8 FEDB 68F5 5C02 83A7`](https://keybase.io/aliciasykes/pgp_keys.asc?fingerprint=0688f8d34587d954e9e51fb8fedb68f55c0283a7)
|
||||
- **BTC Address**: `3853bSxupMjvxEYfwGDGAaLZhTKxB2vEVC`
|
||||
|
||||
**[⬆️ Back to Top](#dashy)**
|
||||
|
||||
---
|
||||
|
|
|
@ -49,6 +49,20 @@ Maximum of 24mb of storage per user. Please do not repeatedly hit the endpoint,
|
|||
- Add your `zone_id` (found in the Overview tab of your desired domain on Cloudflare)
|
||||
- Add your `route`, which should be a domain or host, supporting a wildcard
|
||||
|
||||
```toml
|
||||
name = "dashy-worker"
|
||||
type = "javascript"
|
||||
|
||||
workers_dev = true
|
||||
route = "example.com/*"
|
||||
zone_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
account_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
kv_namespaces = [
|
||||
{ binding = "DASHY_CLOUD_BACKUP", id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
|
||||
]
|
||||
```
|
||||
|
||||
#### Complete `index.js`
|
||||
- Write code to handle your requests, and interact with any other data sources in this file
|
||||
- Generally, this is done within an event listener for 'fetch', and returns a promise
|
||||
|
@ -66,7 +80,7 @@ async function handleRequest(request) {
|
|||
}
|
||||
```
|
||||
|
||||
- For the code used for Dashy's cloud service, see [here](https://notes.aliciasykes.com/p/j2F1deljv1)
|
||||
- For the code used for Dashy's cloud service, see [here](https://gist.github.com/Lissy93/d19b43d50f30e02fa25f349cf5cb5ed8#file-index-js)
|
||||
|
||||
|
||||
#### Commands
|
||||
|
|
|
@ -50,6 +50,8 @@ All fields are optional, unless otherwise stated.
|
|||
**`backgroundImg`** | `string` | _Optional_ | Path to an optional full-screen app background image. This can be either remote (http) or local (/). Note that this will slow down initial load
|
||||
**`enableFontAwesome`** | `boolean` | _Optional_ | Where `true` is enabled, if left blank font-awesome will be enabled only if required by 1 or more icons
|
||||
**`fontAwesomeKey`** | `string` | _Optional_ | If you have a font-awesome key, then you can use it here and make use of premium icons. It is a 10-digit alpha-numeric string from you're FA kit URL (e.g. `13014ae648`)
|
||||
**`layout`** | `string` | _Optional_ | App layout, either `horizontal`, `vertical`, `auto` or `sidebar`. Defaults to `auto`. This specifies the layout and direction of how sections are positioned on the home screen. This can also be modified from the UI.
|
||||
**`iconSize`** | `string` | _Optional_ | The size of link items / icons. Can be either `small`, `medium,` or `large`. Defaults to `medium`. This can also be set directly from the UI.
|
||||
**`theme`** | `string` | _Optional_ | The default theme for first load (you can change this later from the UI)
|
||||
**`cssThemes`** | `string[]` | _Optional_ | An array of custom theme names which can be used in the theme switcher dropdown
|
||||
**`externalStyleSheet`** | `string` or `string[]` | _Optional_ | Either a URL to an external stylesheet or an array or URLs, which can be applied as themes within the UI
|
||||
|
@ -104,9 +106,9 @@ All fields are optional, unless otherwise stated.
|
|||
**`itemSize`** | `string` | _Optional_ | Specify the size for items within this group, either `small`, `medium` or `large`. Note that this will overide any settings specified through the UI
|
||||
**`rows`** | `number` | _Optional_ | Height of the section, specified as the number of rows it should span vertically, e.g. `2`. Defaults to `1`. Max is `5`.
|
||||
**`cols`** | `number` | _Optional_ | Width of the section, specified as the number of columns the section should span horizontally, e.g. `2`. Defaults to `1`. Max is `5`.
|
||||
**`layout`** | `string` | _Optional_ | Specify which CSS layout will be used to responsivley place items. Can be either `auto` (which uses flex layout), or `grid`. If `grid` is selected, then `itemCountX` and `itemCountY` may also be set. Defaults to `auto`
|
||||
**`itemCountX`** | `number` | _Optional_ | The number of items to display per row / horizontally. If not set, it will be calculated automatically based on available space. Can only be set if `layout` is set to `grid`. Must be a whole number between `1` and `12`
|
||||
**`itemCountY`** | `number` | _Optional_ | The number of items to display per column / vertically. If not set, it will be calculated automatically based on available space. If `itemCountX` is set, then `itemCountY` can be calculated automatically. Can only be set if `layout` is set to `grid`. Must be a whole number between `1` and `12`
|
||||
**`sectionLayout`** | `string` | _Optional_ | Specify which CSS layout will be used to responsivley place items. Can be either `auto` (which uses flex layout), or `grid`. If `grid` is selected, then `itemCountX` and `itemCountY` may also be set. Defaults to `auto`
|
||||
**`itemCountX`** | `number` | _Optional_ | The number of items to display per row / horizontally. If not set, it will be calculated automatically based on available space. Can only be set if `sectionLayout` is set to `grid`. Must be a whole number between `1` and `12`
|
||||
**`itemCountY`** | `number` | _Optional_ | The number of items to display per column / vertically. If not set, it will be calculated automatically based on available space. If `itemCountX` is set, then `itemCountY` can be calculated automatically. Can only be set if `sectionLayout` is set to `grid`. Must be a whole number between `1` and `12`
|
||||
|
||||
**[⬆️ Back to Top](#configuring)**
|
||||
|
||||
|
|
|
@ -128,7 +128,8 @@ Click one of the links below, to open an issue:
|
|||
|
||||
### Contributors
|
||||
|
||||
![Auto-generated contributors](https://raw.githubusercontent.com/Lissy93/dashy/03fbaf35ff4653d16a622cfce00a1347c13d0192/docs/assets/CONTRIBUTORS.svg)
|
||||
![Auto-generated contributors](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/assets/CONTRIBUTORS.svg)
|
||||
|
||||
|
||||
### Star-Gazers Over Time
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
- [Basic Commands](#basic-commands)
|
||||
- [Healthchecks](#healthchecks)
|
||||
- [Monitoring](#logs-and-performance)
|
||||
- [Auto Starting](#auto-starting-at-system-boot)
|
||||
- [Updating](#updating)
|
||||
- [Updating Docker Container](#updating-docker-container)
|
||||
- [Automating Docker Updates](#automatic-docker-updates)
|
||||
|
@ -49,6 +50,16 @@ You can also build and deploy the Docker container from source.
|
|||
- Edit the `./public/conf.yml` file and take a look at the `docker-compose.yml`
|
||||
- Start the container: `docker compose up`
|
||||
|
||||
### Other Container Engines
|
||||
|
||||
Docker isn't the only host application capable of running standard Linux containers - [Podman](http://podman.io) is another popular option. Unlike Docker, Podman does not rely on a daemon to be running on your host system. This means there is no single point of failure and it can also support rootless containers, which is perfect for Dashy as it does not require any sudo privileges. Podman was developed by RedHat, and it's source code is written in Go, and published on [GitHub](https://github.com/containers/podman).
|
||||
|
||||
Installation of the podman is really easy, as it's repository is available for most package managers (for example; Arch: `sudo pacman -S podman`, Debian/ Ubuntu: `sudo apt-get install podman`, Gentoo: `sudo emerge app-emulation/podman`, and MacOS: `brew install podman`). For more info, check out the [podman installation docs](https://podman.io/getting-started/installation). If you are using Windows, then take a look at Brent Baude's article on [Running Podman on WSL](https://www.redhat.com/sysadmin/podman-windows-wsl2). Since it's CLI is pretty much identical to that of Dockers, Podman's learning curve is very shallow.
|
||||
|
||||
To run Dashy with Podman, just replace `docker` with `podman` in the above instructions. E.g. `podman run -p 8080:80 lissy93/dashy`
|
||||
|
||||
It's worth noting that Podman isn't the only container running alternative, there's also [`rkt`](https://www.openshift.com/learn/topics/rkt), [`runc`](https://github.com/opencontainers/runc), [`containerd`](https://containerd.io/) and [`cri-o`](https://cri-o.io/). Dashy has not been tested with any of these engines, but it should work just fine.
|
||||
|
||||
|
||||
### Deploy from Source
|
||||
If you do not want to use Docker, you can run Dashy directly on your host system. For this, you will need both [git](https://git-scm.com/downloads) and the latest or LTS version of [Node.js](https://nodejs.org/) installed.
|
||||
|
@ -187,11 +198,25 @@ To restart unhealthy containers automatically, check out [Autoheal](https://hub.
|
|||
|
||||
### Logs and Performance
|
||||
|
||||
##### Container Logs
|
||||
You can view logs for a given Docker container with `docker logs [container-id]`, add the `--follow` flag to stream the logs. For more info, see the [Logging Documentation](https://docs.docker.com/config/containers/logging/). There's also [Dozzle](https://dozzle.dev/), a useful tool, that provides a web interface where you can stream and query logs from all your running containers from a single web app.
|
||||
|
||||
##### Container Performance
|
||||
You can check the resource usage for your running Docker containers with `docker stats` or `docker stats [container-id]`. For more info, see the [Stats Documentation](https://docs.docker.com/engine/reference/commandline/stats/). There's also [cAdvisor](https://github.com/google/cadvisor), a useful web app for viewing and analyzing resource usage and performance of all your running containers.
|
||||
|
||||
You can also view logs, resource usage and other info as well as manage your Docker workflow in third-party Docker management apps. For example [Portainer](https://github.com/portainer/portainer) an all-in-one management web UI for Docker and Kubernetes, or [LazyDocker](https://github.com/jesseduffield/lazydocker) a terminal UI for Docker container management and monitoring.
|
||||
##### Management Apps
|
||||
You can also view logs, resource usage and other info as well as manage your entire Docker workflow in third-party Docker management apps. For example [Portainer](https://github.com/portainer/portainer) an all-in-one open source management web UI for Docker and Kubernetes, or [LazyDocker](https://github.com/jesseduffield/lazydocker) a terminal UI for Docker container management and monitoring.
|
||||
|
||||
##### Advanced Logging and Monitoring
|
||||
Docker supports using [Prometheus](https://prometheus.io/) to collect logs, which can then be visualized using a platform like [Grafana](https://grafana.com/). For more info, see [this guide](https://docs.docker.com/config/daemon/prometheus/). If you need to route your logs to a remote syslog, then consider using [logspout](https://github.com/gliderlabs/logspout). For enterprise-grade instances, there are managed services, that make monitoring container logs and metrics very easy, such as [Sematext](https://sematext.com/blog/docker-container-monitoring-with-sematext/) with [Logagent](https://github.com/sematext/logagent-js).
|
||||
|
||||
### Auto-Starting at System Boot
|
||||
|
||||
You can use Docker's [restart policies](https://docs.docker.com/engine/reference/run/#restart-policies---restart) to instruct the container to start after a system reboot, or restart after a crash. Just add the `--restart=always` flag to your Docker compose script or Docker run command. For more information, see the docs on [Starting Containers Automatically](https://docs.docker.com/config/containers/start-containers-automatically/).
|
||||
|
||||
For Podman, you can use `systemd` to create a service that launches your container, [the docs](https://podman.io/blogs/2018/09/13/systemd.html) explains things further. A similar approach can be used with Docker, if you need to start containers after a reboot, but before any user interaction.
|
||||
|
||||
To restart the container after something within it has crashed, consider using [`docker-autoheal`](https://github.com/willfarrell/docker-autoheal) by @willfarrell, a service that monitors and restarts unhealthy containers. For more info, see the [Healthchecks](#healthchecks) section above.
|
||||
|
||||
**[⬆️ Back to Top](#deployment)**
|
||||
|
||||
|
|
|
@ -7,5 +7,6 @@
|
|||
- [User Guide](/docs/user-guide.md)
|
||||
- [Troubleshooting](/docs/troubleshooting.md)
|
||||
- [Backup & Restore](/docs/backup-restore.md)
|
||||
- [Status Indicators](/docs/status-indicators.md)
|
||||
- [Theming](/docs/theming.md)
|
||||
- [Authentication](/docs/authentication.md)
|
||||
|
|
|
@ -108,10 +108,14 @@ You can target specific elements on the UI with these variables. All are optiona
|
|||
- `--config-settings-background` - The text color for text within the settings container. Defaults to `--background-darker`
|
||||
- `--scroll-bar-color` - Color of the scroll bar thumb. Defaults to `--primary`
|
||||
- `--scroll-bar-background` Color of the scroll bar blank space. Defaults to `--background-darker`
|
||||
- `--highlight-background` Fill color for text highlighting. Defaults to `--primary`
|
||||
- `--highlight-color` Text color for selected/ highlighted text. Defaults to `--background`
|
||||
- `--toast-background` - Background color for the toast info popup. Defaults to `--primary`
|
||||
- `--toast-color` - Text, icon and border color in the toast info popup. Defaults to `--background`
|
||||
- `--welcome-popup-background` - Background for the info pop-up shown on first load. Defaults to `--background-darker`
|
||||
- `--welcome-popup-text-color` - Text color for the welcome pop-up. Defaults to `--primary`
|
||||
- `--side-bar-background` - Background color of the sidebar used in the workspace view. Defaults to `--background-darker`
|
||||
- `--side-bar-color` - Color of icons and text within the sidebar. Defaults to `--primary`
|
||||
|
||||
#### Non-Color Variables
|
||||
- `--outline-color` - Used to outline focused or selected elements
|
||||
|
|
|
@ -68,6 +68,7 @@ export default {
|
|||
<style lang="scss">
|
||||
@import '@/styles/global-styles.scss';
|
||||
@import '@/styles/color-palette.scss';
|
||||
@import '@/styles/dimensions.scss';
|
||||
@import '@/styles/color-themes.scss';
|
||||
@import '@/styles/typography.scss';
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ export default {
|
|||
return this.displayData.itemSize || this.itemSize;
|
||||
},
|
||||
isGridLayout() {
|
||||
return this.displayData.layout === 'grid'
|
||||
return this.displayData.sectionLayout === 'grid'
|
||||
|| !!(this.displayData.itemCountX || this.displayData.itemCountY);
|
||||
},
|
||||
gridStyle() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="item-icon">
|
||||
<i v-if="iconType === 'font-awesome'" :class="`${icon} ${size}`" ></i>
|
||||
<img v-else-if="icon" :src="iconPath" @error="imageNotFound"
|
||||
:class="`tile-icon ${size} ${broken ? 'broken' : ''}`"
|
||||
|
@ -98,9 +98,16 @@ export default {
|
|||
|
||||
<style lang="scss">
|
||||
.tile-icon {
|
||||
width: 60px;
|
||||
width: 2rem;
|
||||
// filter: var(--item-icon-transform);
|
||||
border-radius: var(--curve-factor);
|
||||
&.broken { display: none; }
|
||||
&.small {
|
||||
width: 1.5rem;
|
||||
}
|
||||
&.large {
|
||||
width: 3rem;
|
||||
}
|
||||
}
|
||||
i.fas, i.fab, i.far, i.fal, i.fad {
|
||||
font-size: 2rem;
|
||||
|
|
|
@ -29,6 +29,9 @@ export default {
|
|||
<style scoped lang="scss">
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
padding: 0.25rem;
|
||||
text-align: center;
|
||||
color: var(--medium-grey);
|
||||
|
|
|
@ -54,6 +54,7 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
/* Sets the theme, by updating data-theme attribute on the html tag */
|
||||
setLocalTheme(newTheme) {
|
||||
const htmlTag = document.getElementsByTagName('html')[0];
|
||||
if (htmlTag.hasAttribute('data-theme')) htmlTag.removeAttribute('data-theme');
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<nav class="side-bar">
|
||||
<div v-for="(section, index) in sections" :key="index">
|
||||
<div @click="openSection(index)" class="side-bar-item-container">
|
||||
<SideBarItem
|
||||
class="item"
|
||||
:icon="section.icon"
|
||||
:title="section.name"
|
||||
/>
|
||||
</div>
|
||||
<transition name="slide">
|
||||
<SideBarSection
|
||||
v-if="isOpen[index]"
|
||||
:items="section.items"
|
||||
@launch-app="launchApp"
|
||||
/>
|
||||
</transition>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import SideBarItem from '@/components/Workspace/SideBarItem.vue';
|
||||
import SideBarSection from '@/components/Workspace/SideBarSection.vue';
|
||||
|
||||
export default {
|
||||
name: 'SideBar',
|
||||
inject: ['config'],
|
||||
props: {
|
||||
sections: Array,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOpen: new Array(this.sections.length).fill(false),
|
||||
};
|
||||
},
|
||||
components: {
|
||||
SideBarItem,
|
||||
SideBarSection,
|
||||
},
|
||||
methods: {
|
||||
/* Toggles the section clicked, and closes all other sections */
|
||||
openSection(index) {
|
||||
this.isOpen = this.isOpen.map((val, ind) => (ind !== index ? false : !val));
|
||||
},
|
||||
launchApp(url) {
|
||||
this.$emit('launch-app', url);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@import '@/styles/media-queries.scss';
|
||||
@import '@/styles/style-helpers.scss';
|
||||
|
||||
nav.side-bar {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--side-bar-background);
|
||||
color: var(--side-bar-color);
|
||||
height: 100%;
|
||||
width: var(--side-bar-width);
|
||||
text-align: center;
|
||||
overflow: auto;
|
||||
@extend .scroll-bar;
|
||||
.side-bar-item-container {
|
||||
z-index: 5;
|
||||
}
|
||||
.item:not(:last-child) {
|
||||
border-bottom: 1px dashed var(--side-bar-color);
|
||||
z-index: 5;
|
||||
}
|
||||
}
|
||||
|
||||
.slide-leave-active,
|
||||
.slide-enter-active {
|
||||
transition: all 0.1s ease-in-out;
|
||||
}
|
||||
.slide-enter {
|
||||
transform: translate(0, -80%);
|
||||
}
|
||||
.slide-leave-to {
|
||||
transform: translate(0, -80%);
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<div @click="itemClicked()"
|
||||
:class="`side-bar-item ${icon ? 'w-icon' : 'text-only'}`" v-tooltip="tooltip">
|
||||
<Icon v-if="icon" :icon="icon" size="small" :url="url" />
|
||||
<p class="small-title" v-else>{{ title }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import Icon from '@/components/LinkItems/ItemIcon.vue';
|
||||
|
||||
export default {
|
||||
name: 'SideBarItem',
|
||||
inject: ['config'],
|
||||
props: {
|
||||
icon: String,
|
||||
title: String,
|
||||
url: String,
|
||||
click: Function,
|
||||
},
|
||||
components: {
|
||||
Icon,
|
||||
},
|
||||
methods: {
|
||||
itemClicked() {
|
||||
if (this.url) this.$emit('launch-app', this.url);
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tooltip: {
|
||||
disabled: !this.title,
|
||||
content: this.title,
|
||||
trigger: 'hover focus',
|
||||
hideOnTargetClick: true,
|
||||
html: false,
|
||||
placement: 'right-start',
|
||||
delay: { show: 800, hide: 1000 },
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/media-queries.scss';
|
||||
@import '@/styles/style-helpers.scss';
|
||||
|
||||
div.side-bar-item {
|
||||
color: var(--side-bar-color);
|
||||
background: var(--side-bar-background);
|
||||
text-align: center;
|
||||
&.text-only {
|
||||
background: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
p.small-title {
|
||||
margin: 0.1rem auto;
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<div class="sub-side-bar">
|
||||
<div v-for="(item, index) in items" :key="index">
|
||||
<SideBarItem
|
||||
class="item"
|
||||
:icon="item.icon"
|
||||
:title="item.title"
|
||||
:url="item.url"
|
||||
@launch-app="launchApp"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import SideBarItem from '@/components/Workspace/SideBarItem.vue';
|
||||
|
||||
export default {
|
||||
name: 'SideBarSection',
|
||||
inject: ['config'],
|
||||
props: {
|
||||
items: Array,
|
||||
},
|
||||
components: {
|
||||
SideBarItem,
|
||||
},
|
||||
methods: {
|
||||
launchApp(url) {
|
||||
this.$emit('launch-app', url);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/media-queries.scss';
|
||||
@import '@/styles/style-helpers.scss';
|
||||
|
||||
div.sub-side-bar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--side-bar-background-lighter);
|
||||
border-radius: var(--curve-factor);
|
||||
margin: 0.2rem;
|
||||
color: var(--side-bar-color);
|
||||
text-align: center;
|
||||
z-index: 3;
|
||||
.item:not(:last-child) {
|
||||
border-bottom: 1px dashed var(--side-bar-color);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,30 @@
|
|||
<template>
|
||||
<div class="web-content">
|
||||
<iframe :src="url" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'WebContent',
|
||||
props: {
|
||||
url: String,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/media-queries.scss';
|
||||
@import '@/styles/style-helpers.scss';
|
||||
|
||||
iframe {
|
||||
position: absolute;
|
||||
left: var(--side-bar-width);
|
||||
height: calc(100% - var(--header-height));
|
||||
width: calc(100% - var(--side-bar-width));
|
||||
border: none;
|
||||
background: white;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -3,8 +3,10 @@ import Router from 'vue-router';
|
|||
|
||||
import Home from '@/views/Home.vue';
|
||||
import Login from '@/views/Login.vue';
|
||||
import Workspace from '@/views/Workspace.vue';
|
||||
import { isLoggedIn } from '@/utils/Auth';
|
||||
import { appConfig, pageInfo, sections } from '@/utils/ConfigAccumalator';
|
||||
import { metaTagData } from '@/utils/defaults';
|
||||
|
||||
Vue.use(Router);
|
||||
|
||||
|
@ -26,12 +28,17 @@ const router = new Router({
|
|||
},
|
||||
meta: {
|
||||
title: pageInfo.title || 'Home Page',
|
||||
metaTags: [
|
||||
{
|
||||
name: 'description',
|
||||
content: 'A simple static homepage for you\'re server',
|
||||
},
|
||||
],
|
||||
metaTags: metaTagData,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/workspace',
|
||||
name: 'workspace',
|
||||
component: Workspace,
|
||||
props: { appConfig, pageInfo, sections },
|
||||
meta: {
|
||||
title: pageInfo.title || 'Dashy Workspace',
|
||||
metaTags: metaTagData,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -31,22 +31,6 @@
|
|||
--transparent-white-50: #ffffff80;
|
||||
--transparent-white-30: #ffffff4d;
|
||||
|
||||
/* Other Variables */
|
||||
--outline-color: none;
|
||||
--curve-factor: 5px; // Border radius for most components
|
||||
--curve-factor-navbar: 16px; // Border radius for header
|
||||
--dimming-factor: 0.7; // Opacity for semi-transparent components
|
||||
|
||||
/* Settings for specific components */
|
||||
--scroll-bar-width: 8px;
|
||||
--item-group-padding: 5px; // Determines width of item-group outline
|
||||
--item-shadow: 1px 1px 2px #130f23;
|
||||
--item-hover-shadow: 1px 2px 4px #373737;
|
||||
--item-icon-transform: drop-shadow(2px 4px 6px var(--transparent-50)) saturate(0.65);
|
||||
--item-icon-transform-hover: drop-shadow(4px 8px 3px var(--transparent-50)) saturate(2);
|
||||
--item-group-shadow: var(--item-shadow);
|
||||
--settings-container-shadow: none;
|
||||
|
||||
/* Color variables for specific components
|
||||
* all variables are optional, since they inherit initial values from above*
|
||||
* Using specific variables makes overriding for custom themes really easy */
|
||||
|
@ -77,10 +61,17 @@
|
|||
--toast-color: var(--background);
|
||||
--scroll-bar-color: var(--primary);
|
||||
--scroll-bar-background: var(--background-darker);
|
||||
--highlight-color: var(--background);
|
||||
--highlight-background: var(--primary);
|
||||
--loading-screen-color: var(--primary);
|
||||
--loading-screen-background: var(--background);
|
||||
--login-form-color: var(--primary);
|
||||
--login-form-background: var(--background);
|
||||
--login-form-background-secondary: var(--background-darker);
|
||||
|
||||
--about-page-color: var(--white);
|
||||
--about-page-background: #0b1021;
|
||||
--about-page-accent: var(--primary);
|
||||
--side-bar-background: var(--background-darker);
|
||||
--side-bar-background-lighter: var(--background);
|
||||
--side-bar-color: var(--primary);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
:root {
|
||||
/* General Variables */
|
||||
--outline-color: none;
|
||||
--curve-factor: 5px; // Border radius for most components
|
||||
--curve-factor-navbar: 16px; // Border radius for header
|
||||
--dimming-factor: 0.7; // Opacity for semi-transparent components
|
||||
|
||||
/* Basic Page Components */
|
||||
--scroll-bar-width: 8px;
|
||||
--header-height: 6.3rem;
|
||||
|
||||
/* Section & Item dimensions */
|
||||
--item-group-padding: 5px; // Determines width of item-group outline
|
||||
--item-shadow: 1px 1px 2px #130f23;
|
||||
--item-hover-shadow: 1px 2px 4px #373737;
|
||||
--item-icon-transform: drop-shadow(2px 4px 6px var(--transparent-50)) saturate(0.65);
|
||||
--item-icon-transform-hover: drop-shadow(4px 8px 3px var(--transparent-50)) saturate(2);
|
||||
--item-group-shadow: var(--item-shadow);
|
||||
|
||||
/* Settings and config menu */
|
||||
--settings-container-shadow: none;
|
||||
|
||||
/* Workspace View */
|
||||
--side-bar-width: 3.5rem; // The width of the sidebar
|
||||
}
|
|
@ -7,6 +7,7 @@ html {
|
|||
transition: all 1s;
|
||||
margin-top: -3px;
|
||||
@extend .scroll-bar;
|
||||
@extend .highlight;
|
||||
box-sizing: border-box;
|
||||
input[type=button], button, a {
|
||||
cursor: pointer;
|
||||
|
|
|
@ -15,6 +15,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* Custom highlight color */
|
||||
.highlight {
|
||||
::selection {
|
||||
background-color: var(--highlight-background);
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
::-moz-selection, ::-o-selection, ::-ms-selection, ::-webkit-selection {
|
||||
background-color: var(--highlight-background);
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Single-style helpers */
|
||||
.bold { font-weight: bold; }
|
||||
.light { font-weight: lighter; }
|
||||
|
|
|
@ -8,13 +8,17 @@ import Defaults, { localStorageKeys } from '@/utils/defaults';
|
|||
import conf from '../../public/conf.yml';
|
||||
|
||||
export const appConfig = (() => {
|
||||
let usersAppConfig = Defaults.appConfig;
|
||||
if (localStorage[localStorageKeys.APP_CONFIG]) {
|
||||
return JSON.parse(localStorage[localStorageKeys.APP_CONFIG]);
|
||||
usersAppConfig = JSON.parse(localStorage[localStorageKeys.APP_CONFIG]);
|
||||
} else if (conf.appConfig) {
|
||||
return conf.appConfig;
|
||||
} else {
|
||||
return Defaults.appConfig;
|
||||
usersAppConfig = conf.appConfig;
|
||||
}
|
||||
usersAppConfig.layout = localStorage[localStorageKeys.LAYOUT_ORIENTATION]
|
||||
|| conf.appConfig.layout || Defaults.layout;
|
||||
usersAppConfig.iconSize = localStorage[localStorageKeys.ICON_SIZE]
|
||||
|| conf.appConfig.iconSize || Defaults.iconSize;
|
||||
return usersAppConfig;
|
||||
})();
|
||||
|
||||
export const pageInfo = (() => {
|
||||
|
|
|
@ -69,6 +69,25 @@
|
|||
"pattern": "^[a-z0-9]{10}$",
|
||||
"description": "API key for font-awesome"
|
||||
},
|
||||
"layout": {
|
||||
"enum": [
|
||||
"horizontal",
|
||||
"vertical",
|
||||
"auto",
|
||||
"sidebar"
|
||||
],
|
||||
"default": "auto",
|
||||
"description": "Specifies sections layout orientation on the home screen"
|
||||
},
|
||||
"iconSize": {
|
||||
"enum": [
|
||||
"small",
|
||||
"medium",
|
||||
"large"
|
||||
],
|
||||
"default": "medium",
|
||||
"description": "The size of each link item / icon"
|
||||
},
|
||||
"cssThemes": {
|
||||
"type": "array",
|
||||
"description": "Theme names to be added to the dropdown",
|
||||
|
@ -195,7 +214,7 @@
|
|||
"default": 1,
|
||||
"description": "The amount of space that the section spans horizontally"
|
||||
},
|
||||
"layout": {
|
||||
"sectionLayout": {
|
||||
"enum": [
|
||||
"grid",
|
||||
"auto"
|
||||
|
|
|
@ -77,4 +77,7 @@ module.exports = {
|
|||
},
|
||||
backupEndpoint: 'https://dashy-sync-service.as93.net',
|
||||
splashScreenTime: 1900,
|
||||
metaTagData: [
|
||||
{ name: 'description', content: 'A simple static homepage for you\'re server' },
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,5 +1,129 @@
|
|||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
</div>
|
||||
<article class="about">
|
||||
<h1>About Dashy</h1>
|
||||
<section>
|
||||
<h2>Project Overview</h2>
|
||||
<p>
|
||||
Dashy is a self-hosted startpage for keeping your running applications and
|
||||
services organised. The aim of Dashy is to provide an easy-to-deploy,
|
||||
highly customizable and functianl dashboard, in order to improvde productivity
|
||||
and enable easy organisation of running services or web links.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Source</h2>
|
||||
<p>
|
||||
Dashy's source is available through <a href="https://github.com/lissy93/dashy">GitHub</a>,
|
||||
and the Docker image is on <a href="https://hub.docker.com/r/lissy93/dashy">DockerHub</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Reporting a Bug</h2>
|
||||
<p>
|
||||
If you've come across an bug in Dashy, please <a href="https://git.io/JnqPR">open an issue</a>,
|
||||
so that it can be fixed.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Getting Support</h2>
|
||||
<p>
|
||||
If you need any help deploying, using, or developing Dashy, feel free to
|
||||
<a href="https://git.io/JnqiA">open a support ticket</a> or start a
|
||||
<a href="https://github.com/Lissy93/dashy/discussions">discussion</a> on GitHub.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>About the Author</h2>
|
||||
<a href="https://aliciasykes.com">
|
||||
<img class="aht-pic" src="https://i.ibb.co/FnxqTfx/aht-bot-round.png" alt="Alicia Sykes">
|
||||
</a>
|
||||
Dashy is developed an maintained by <a href="https://aliciasykes.com">Alicia Sykes</a>
|
||||
(<a href="https://github.com/lissy93">@Lissy93</a>), with support from the community.
|
||||
<ul>
|
||||
<li><b>PGP Key</b> - <a href="https://keybase.io/aliciasykes/pgp_keys.asc?fingerprint=0688f8d34587d954e9e51fb8fedb68f55c0283a7"><code>0688 F8D3 4587 D954 E9E5 1FB8 FEDB 68F5 5C02 83A7</code></a></li>
|
||||
<li><b>BTC Address</b> - <code>3853bSxupMjvxEYfwGDGAaLZhTKxB2vEVC</code></li>
|
||||
<li><b>Mail</b> - <code>alicia at omg dot lol</code></li>
|
||||
<li><b>Blog</b> - <a href="https://notes.aliciasykes.com">notes.aliciasykes.com</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="license">
|
||||
<h2>License</h2>
|
||||
<code>
|
||||
Copyright © 2021 Alicia Sykes (https://aliciasykes.com)
|
||||
</code>
|
||||
<br><br>
|
||||
<code>
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
software and associated documentation files (the “Software”), to deal in the Software
|
||||
without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
</code>
|
||||
<br><br>
|
||||
<code>
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
</code>
|
||||
<br><br>
|
||||
<code>
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWAREOR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</code>
|
||||
</section>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
document.getElementsByTagName('html')[0].setAttribute('data-theme', 'callisto');
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
article.about {
|
||||
background: var(--about-page-background);
|
||||
color: var(--about-page-color);
|
||||
width: 80%;
|
||||
max-width: 1000px;
|
||||
margin: 1rem auto 2.5rem auto;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--about-page-accent);
|
||||
border-radius: var(--curve-factor);
|
||||
h1, h2, h3, p, span, div, section {
|
||||
color: var(--about-page-color);
|
||||
}
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
a, code {
|
||||
color: var(--about-page-accent);
|
||||
}
|
||||
section {
|
||||
padding-bottom: 1rem;
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px dashed var(--about-page-accent);
|
||||
}
|
||||
}
|
||||
p {
|
||||
line-height: 1.5rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
img.aht-pic {
|
||||
width: 100px;
|
||||
float: right;
|
||||
}
|
||||
section.license code {
|
||||
color: var(--about-page-color);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -64,14 +64,14 @@ export default {
|
|||
}),
|
||||
computed: {
|
||||
layoutOrientation: {
|
||||
get: () => localStorage[localStorageKeys.LAYOUT_ORIENTATION] || Defaults.layout,
|
||||
get() { return this.appConfig.layout || Defaults.layout; },
|
||||
set: function setLayout(layout) {
|
||||
localStorage.setItem(localStorageKeys.LAYOUT_ORIENTATION, layout);
|
||||
this.layout = layout;
|
||||
},
|
||||
},
|
||||
iconSize: {
|
||||
get: () => localStorage[localStorageKeys.ICON_SIZE] || Defaults.iconSize,
|
||||
get() { return this.appConfig.iconSize || Defaults.iconSize; },
|
||||
set: function setIconSize(iconSize) {
|
||||
localStorage.setItem(localStorageKeys.ICON_SIZE, iconSize);
|
||||
this.itemSizeBound = iconSize;
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<div class="work-space">
|
||||
<SideBar :sections="sections" @launch-app="launchApp" />
|
||||
<WebContent :url="url" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import SideBar from '@/components/Workspace/SideBar';
|
||||
import WebContent from '@/components/Workspace/WebContent';
|
||||
import Defaults, { localStorageKeys } from '@/utils/defaults';
|
||||
|
||||
export default {
|
||||
name: 'Workspace',
|
||||
props: {
|
||||
sections: Array,
|
||||
appConfig: Object,
|
||||
},
|
||||
data: () => ({
|
||||
url: '',
|
||||
}),
|
||||
components: {
|
||||
SideBar,
|
||||
WebContent,
|
||||
},
|
||||
methods: {
|
||||
launchApp(url) {
|
||||
this.url = url;
|
||||
},
|
||||
setTheme() {
|
||||
const theme = localStorage[localStorageKeys.THEME] || this.confTheme || Defaults.theme;
|
||||
const htmlTag = document.getElementsByTagName('html')[0];
|
||||
if (htmlTag.hasAttribute('data-theme')) htmlTag.removeAttribute('data-theme');
|
||||
htmlTag.setAttribute('data-theme', theme);
|
||||
},
|
||||
initiateFontAwesome() {
|
||||
const fontAwesomeScript = document.createElement('script');
|
||||
const faKey = this.appConfig.fontAwesomeKey || Defaults.fontAwesomeKey;
|
||||
fontAwesomeScript.setAttribute('src', `https://kit.fontawesome.com/${faKey}.js`);
|
||||
document.head.appendChild(fontAwesomeScript);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setTheme();
|
||||
this.initiateFontAwesome();
|
||||
},
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
Loading…
Reference in New Issue