mirror of
https://github.com/Lissy93/dashy.git
synced 2025-04-07 20:55:11 +02:00
🔀 Merge pull request #261 from Lissy93/IMPROVMENTS/user-requested-modifications
[IMPROVMENTS] User-Requested Modifications Fixes #255 Fixes #254
This commit is contained in:
commit
9b1c457ddd
.github
CHANGELOG.mdpr-branch-labeler.yml
workflows
assign-reviewer.ymlauto-rebase-pr.ymlauto-tag-pr.ymlcheck-duplicate-issues.ymlclose-stale-issues.ymldocs-link-checker.ymldomain-expirey-check.ymlgenerate-credits.ymlget-size.ymlissue-spam-control.ymllabel-sponsors.ymlpr-labler.ymlremove-stale-label.ymlrepo-visualization.ymlsave-repo-analytics.ymlunfurl-links.yml
docs
package.jsonsrc
components
Configuration
LinkItems
Workspace
styles
utils
views
10
.github/CHANGELOG.md
vendored
10
.github/CHANGELOG.md
vendored
@ -1,5 +1,15 @@
|
||||
# Changelog
|
||||
|
||||
## 💄 1.8.5 - Lots of Requested UI Improvements [PR #261](https://github.com/Lissy93/dashy/pull/261)
|
||||
- Adds an option for landing URL in workspace, Re: #255
|
||||
- Switches to a new API for generative icons, Re: #163
|
||||
- Adds new tab functionality to Workspace, Re: #254
|
||||
- Remove CSS validation in style editor, Re: #259
|
||||
- Cap item description at 2 lines, Re: #250
|
||||
- Adds native support for common homelab icons, using dashboard-icons
|
||||
- Improves general responsiveness of home page sections positioning
|
||||
- Updates, fixes and adds a bunch of actions for easier repo management
|
||||
|
||||
## ✨ 1.8.4 - Custom Error Pages [PR #257](https://github.com/Lissy93/dashy/pull/257)
|
||||
- Creates a 404 Not Found page
|
||||
- Routes any missing views to the 404 page
|
||||
|
10
.github/pr-branch-labeler.yml
vendored
Normal file
10
.github/pr-branch-labeler.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# PR labels and the branch patterns they should be auto-assigned to
|
||||
|
||||
🦋 Bug Fix: ['FIX/*', 'HOT-FIX/*', 'BUG-FIX/*']
|
||||
✨ New Feature: ['FEATURE/*']
|
||||
🚚 Refactor: ['IMPROVMENTS/*', 'REFACTOR/*']
|
||||
💯 Showcase: ['SHOWCASE/*']
|
||||
💄 Stylistic Changes: ['STYLES/*', 'THEME/*']
|
||||
🛠️ Build Changes: ['ARCH/*', 'ARCHITECTURE/*', 'DOCKER/*', 'BUILD/*']
|
||||
🤖 Auto: ['AUTO/*', 'BOT/*', 'snyk-upgrade-*', 'snyk-fix-*']
|
||||
⛔ Don't Merge: ['WEBSITE/*', 'EXPERIMENT/*', 'DEPLOY/*', 'deploy_*', 'gh-pages', 'dev-demo']
|
14
.github/workflows/assign-reviewer.yml
vendored
Normal file
14
.github/workflows/assign-reviewer.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# Automatically assigns the author as a reviewer to opened PRs and issues
|
||||
name: 💡 Auto-Assign Author to PR
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened]
|
||||
issues:
|
||||
types: [opened]
|
||||
jobs:
|
||||
assign-author:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Assign author
|
||||
uses: technote-space/assign-author@v1
|
||||
GITHUB_TOKEN: ${{secrets.BOT_GITHUB_TOKEN}}
|
23
.github/workflows/auto-rebase-pr.yml
vendored
Normal file
23
.github/workflows/auto-rebase-pr.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# When a '/rebase' comment is added to a PR, it will be rebased from the main branch
|
||||
name: 🏗️ Automatic PR Rebase
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
jobs:
|
||||
rebase:
|
||||
name: Rebase
|
||||
if: >
|
||||
github.event.issue.pull_request != ''
|
||||
&& contains(github.event.comment.body, '/rebase')
|
||||
&& github.event.comment.author_association == 'MEMBER'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
fetch-depth: 0
|
||||
- name: Rebase
|
||||
uses: cirrus-actions/rebase@1.4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
17
.github/workflows/auto-tag-pr.yml
vendored
17
.github/workflows/auto-tag-pr.yml
vendored
@ -1,16 +1,27 @@
|
||||
# Creates a new tag, whenever the app version (in package.json) is updated in master
|
||||
name: 🏗️ Create Tag on Version Change
|
||||
# And marks any relevant issues as fixed
|
||||
name: 🏗️ Release Tag new Versions
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
build:
|
||||
tag-pre-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: butlerlogic/action-autotag@stable
|
||||
with:
|
||||
GITHUB_TOKEN: '${{ secrets.BOT_GITHUB_TOKEN }}'
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
strategy: package
|
||||
commit_message_template: "🔖 {{number}} {{message}} (by {{author}})\nSHA: {{sha}}\n."
|
||||
mark-issue-fixed:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: butlerlogic/action-autotag@stable
|
||||
- name: Label Fixed Issues
|
||||
uses: gh-bot/fix-labeler@master
|
||||
with:
|
||||
token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
label: '✅ Fixed'
|
22
.github/workflows/check-duplicate-issues.yml
vendored
Normal file
22
.github/workflows/check-duplicate-issues.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
# Attempts to auto-detect weather an issue is a duplicate, and adds a comment
|
||||
name: 🎯 Issue Duplicate Check
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
jobs:
|
||||
check-duplicate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/potential-duplicates@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
filter: ''
|
||||
exclude: '[BUG] [QUESTION] [FEEDBACK] [SHOWCASE]'
|
||||
label: '🕸️ Potential Duplicate'
|
||||
state: all
|
||||
threshold: 0.6
|
||||
reactions: 'eyes'
|
||||
comment: >
|
||||
Potential duplicates: {{#issues}}
|
||||
- [#{{ number }}] {{ title }} ({{ accuracy }}%)
|
||||
{{/issues}}
|
28
.github/workflows/close-stale-issues.yml
vendored
28
.github/workflows/close-stale-issues.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
uses: actions/stale@v4
|
||||
with:
|
||||
repo-token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
days-before-stale: 42
|
||||
days-before-stale: 30
|
||||
days-before-close: 5
|
||||
operations-per-run: 30
|
||||
remove-stale-when-updated: true
|
||||
@ -41,9 +41,9 @@ jobs:
|
||||
uses: actions/stale@v4
|
||||
with:
|
||||
repo-token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
days-before-stale: 7
|
||||
days-before-stale: 5
|
||||
days-before-close: 3
|
||||
operations-per-run: 10
|
||||
operations-per-run: 30
|
||||
remove-stale-when-updated: true
|
||||
stale-issue-message: >
|
||||
Hello! Looks like additional info is required for this issue to be addressed.
|
||||
@ -55,3 +55,25 @@ jobs:
|
||||
close-issue-label: '🕸️ Inactive'
|
||||
exempt-issue-labels: '📌 Keep Open'
|
||||
exempt-pr-labels: '📌 Keep Open'
|
||||
|
||||
# Comment on issues that I should have replied to
|
||||
- name: Notify Repo Owner to Respond
|
||||
uses: actions/stale@v4
|
||||
with:
|
||||
repo-token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
days-before-stale: 7
|
||||
days-before-close: 365
|
||||
operations-per-run: 30
|
||||
remove-stale-when-updated: true
|
||||
stale-issue-message: Hey @Lissy93 - Don't forget to respond!
|
||||
stale-pr-message: Hey @Lissy93 - Don't forget to respond!
|
||||
only-labels: '👤 Awaiting Maintainer Response'
|
||||
labels-to-remove-when-unstale: '👤 Awaiting Maintainer Response'
|
||||
close-issue-message: 'Closed due to no response from repo author for over a year'
|
||||
close-pr-message: 'Closed due to no response from repo author for over a year'
|
||||
stale-issue-label: '👤 Awaiting Maintainer Response'
|
||||
stale-pr-label: '👤 Awaiting Maintainer Response'
|
||||
close-issue-label: '🕸️ Inactive'
|
||||
close-pr-label: '🕸️ Inactive'
|
||||
exempt-issue-labels: '📌 Keep Open'
|
||||
exempt-pr-labels: '📌 Keep Open'
|
27
.github/workflows/docs-link-checker.yml
vendored
Normal file
27
.github/workflows/docs-link-checker.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# Checks for any broken links in the docs, and raises an issue if found
|
||||
name: 🌈 Broken Link Checker
|
||||
on:
|
||||
repository_dispatch:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 1 * * 0' # At 01:00 on Sunday.
|
||||
jobs:
|
||||
link-checker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Check for Broken Links
|
||||
uses: lycheeverse/lychee-action@v1.0.8
|
||||
with:
|
||||
args: --verbose --no-progress **/*.md **/*.html
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.BOT_GITHUB_TOKEN}}
|
||||
LYCHEE_OUT: .github/broken-link-report.md
|
||||
|
||||
- name: Raise an Issue with Results
|
||||
uses: peter-evans/create-issue-from-file@v3
|
||||
with:
|
||||
title: '[DOCS] Broken Links found in Documentation'
|
||||
content-filepath: .github/broken-link-report.md
|
||||
labels: '📕 Docs, 👩💻 Good First Issue, 💤 Low Priority, 🤖 Auto'
|
43
.github/workflows/domain-expirey-check.yml
vendored
Normal file
43
.github/workflows/domain-expirey-check.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
name: 📕 Check Docs Domain Expiry
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 1 * * 0' # At 01:00 on Sunday.
|
||||
jobs:
|
||||
check-domain:
|
||||
runs-on: ubuntu-latest
|
||||
name: Check domain
|
||||
strategy:
|
||||
matrix:
|
||||
domain:
|
||||
- https://dashy.to
|
||||
steps:
|
||||
- name: Check domain SSL and registry expire date
|
||||
id: check-domain
|
||||
uses: codex-team/action-check-domain@v1
|
||||
with:
|
||||
url: ${{ matrix.domain }}
|
||||
- name: Raise issue if domain expiring soon
|
||||
if: ${{ steps.check-domain.outputs.paid-till-days-left && steps.check-domain.outputs.paid-till-days-left < 30 }}
|
||||
uses: rishabhgupta/git-action-issue@v2
|
||||
with:
|
||||
token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
assignees: Lissy93
|
||||
title: '[WEBSITE] Domain Expiring Soon'
|
||||
body: >
|
||||
**Priority Notice**
|
||||
Domain, ${{ matrix.domain }} will expire in ${{ steps.check-domain.outputs.paid-till-days-left }} days.
|
||||
@Lissy93 - Please take action immediately to prevent any downtime
|
||||
|
||||
- name: Raise issue if SSL Cert expiring soon
|
||||
if: ${{ steps.check-domain.outputs.ssl-expire-days-left && steps.check-domain.outputs.ssl-expire-days-left < 14 }}
|
||||
uses: rishabhgupta/git-action-issue@v2
|
||||
with:
|
||||
token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
assignees: Lissy93
|
||||
title: '[WEBSITE] SSL Cert Expiring Soon'
|
||||
body: >
|
||||
**Priority Notice**
|
||||
The SSL Certificate for ${{ matrix.domain }} will expire in ${{ ssl-expire-days-left }} days, on ${{ steps.check-domain.outputs.ssl-expire-date }}.
|
||||
@Lissy93 - Please take action immediately to prevent any downtime
|
||||
|
16
.github/workflows/generate-credits.yml
vendored
16
.github/workflows/generate-credits.yml
vendored
@ -65,4 +65,18 @@ jobs:
|
||||
committer_username: liss-bot
|
||||
committer_email: liss-bot@d0h.co
|
||||
|
||||
|
||||
make-author-list:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout 🛎️
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: wow-actions/update-authors@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
sort: commits
|
||||
bots: true
|
||||
path: .github/AUTHORS.txt
|
||||
commit: ':blue_heart: Makes author list'
|
||||
template: '{{name}} <{{email}}> - {{commits}} commits'
|
||||
|
34
.github/workflows/get-size.yml
vendored
34
.github/workflows/get-size.yml
vendored
@ -1,5 +1,5 @@
|
||||
# Adds a comment to new PRs, showing the compressed size and size difference of new code
|
||||
# And labels the PR based on the number of lines changes
|
||||
# And also labels the PR based on the number of lines changes
|
||||
name: 🌈 Check PR Size
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
@ -13,18 +13,26 @@ jobs:
|
||||
uses: preactjs/compressed-size-action@v2
|
||||
with:
|
||||
repo-token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
pattern: "./dist/**/**"
|
||||
pattern: './dist/**/*.{js,css,html}'
|
||||
strip-hash: '[-|.](\w{32}|\w{8}).'
|
||||
exclude: '{./dist/manifest.json,**/*.map,**/node_modules/**}'
|
||||
minimum-change-threshold: 100
|
||||
# Check number of lines of code added
|
||||
- name: Label based on Lines of Code
|
||||
uses: codelytv/pr-size-labeler@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
xs_max_size: '10'
|
||||
s_max_size: '100'
|
||||
m_max_size: '500'
|
||||
l_max_size: '1000'
|
||||
fail_if_xl: 'false'
|
||||
message_if_xl: >
|
||||
It looks like this PR is very large (over 1000 lines).
|
||||
Try to avoid addressing multiple issues in a single PR, and
|
||||
in the future consider breaking large tasks down into smaller steps.
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
xs_max_size: '10'
|
||||
s_max_size: '100'
|
||||
m_max_size: '500'
|
||||
l_max_size: '1000'
|
||||
s_label: '🟩 PR - Small'
|
||||
m_label: '🟨 PR - Medium'
|
||||
l_label: '🟧 PR - Large'
|
||||
xl_label: '🟥 PR - XL'
|
||||
fail_if_xl: 'false'
|
||||
message_if_xl: >
|
||||
It looks like this PR is very large (over 1000 lines).
|
||||
Try to avoid addressing multiple issues in a single PR, and
|
||||
in the future consider breaking large tasks down into smaller steps.
|
||||
This it to make reviewing, testing, reverting and general quality management easier.
|
||||
|
8
.github/workflows/issue-spam-control.yml
vendored
8
.github/workflows/issue-spam-control.yml
vendored
@ -1,12 +1,12 @@
|
||||
# Will add a comment and close new issues opened by users that may be spam, or have not starred
|
||||
# Is still a work in progress, will also detect if user has previous activity in repo and check when joined GH
|
||||
# Will add a comment and close any new issues opened by
|
||||
# users who have not yet committed to, or starred the repo
|
||||
name: 🎯 Issue Spam Control
|
||||
on:
|
||||
issues:
|
||||
types: [opened, reopened]
|
||||
jobs:
|
||||
check:
|
||||
if: ${{ ! contains( github.event.issue.labels.*.name, 'keep-open') }}
|
||||
check-user:
|
||||
if: ${{ ! contains( github.event.issue.labels.*.name, 'keep-open') && github.event.comment.author_association != 'CONTRIBUTOR' }}
|
||||
runs-on: ubuntu-latest
|
||||
name: Close issue opened by non-stargazer
|
||||
steps:
|
||||
|
2
.github/workflows/label-sponsors.yml
vendored
2
.github/workflows/label-sponsors.yml
vendored
@ -2,8 +2,6 @@
|
||||
# In order to allow their request can be prioritized
|
||||
name: 🎯 Label sponsors
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened]
|
||||
issues:
|
||||
types: [opened]
|
||||
jobs:
|
||||
|
12
.github/workflows/pr-labler.yml
vendored
Normal file
12
.github/workflows/pr-labler.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# Labels pull requests based on their branch name
|
||||
name: 💡 PR Branch Labeler
|
||||
on: pull_request
|
||||
jobs:
|
||||
label-pr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Label PR
|
||||
if: github.event.action == 'opened'
|
||||
uses: ffittschen/pr-branch-labeler@v1
|
||||
with:
|
||||
repo-token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
28
.github/workflows/remove-stale-label.yml
vendored
28
.github/workflows/remove-stale-label.yml
vendored
@ -1,13 +1,13 @@
|
||||
# When a new comment is added to an issue, if it had the Stale or Awaiting User Response labels,
|
||||
# then those labels will be removed, providing it was not user lissy93 who added the commend.
|
||||
name: 🎯 Remove Stale Label on Update
|
||||
name: 🎯 Add/ Remove Awaiting Response Labels
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
jobs:
|
||||
remove-stale:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.inputs.name != 'liss-bot' }}
|
||||
if: ${{ github.event.inputs.name != 'liss-bot' && github.event.inputs.name != 'lissy93' }}
|
||||
steps:
|
||||
- name: Remove Stale labels when Updated
|
||||
uses: actions-cool/issues-helper@v2
|
||||
@ -16,3 +16,27 @@ jobs:
|
||||
token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
labels: '🚏 Awaiting User Response,⚰️ Stale'
|
||||
|
||||
add-awaiting-author:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.inputs.name != 'liss-bot' && github.event.inputs.name != 'lissy93' }}
|
||||
steps:
|
||||
- name: Add Awaiting Author labels when Updated
|
||||
uses: actions-cool/issues-helper@v2
|
||||
with:
|
||||
actions: add-labels
|
||||
token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
labels: '👤 Awaiting Maintainer Response'
|
||||
|
||||
remove-awaiting-author:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.inputs.name == 'lissy93' }}
|
||||
steps:
|
||||
- name: Remove Awaiting Author labels when Updated
|
||||
uses: actions-cool/issues-helper@v2
|
||||
with:
|
||||
actions: remove-labels
|
||||
token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
labels: '👤 Awaiting Maintainer Response'
|
||||
|
37
.github/workflows/repo-visualization.yml
vendored
37
.github/workflows/repo-visualization.yml
vendored
@ -1,16 +1,17 @@
|
||||
# Generates diagram showing file breakdown
|
||||
name: 📊 Generate Repo Visualization
|
||||
# Generates series of diagrams and visualizations
|
||||
name: 📊 Generate Repo Stats
|
||||
on:
|
||||
workflow_dispatch: # Manual dispatch
|
||||
schedule:
|
||||
- cron: '0 1 * * 0' # At 01:00 on Sunday.
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# File structure chart
|
||||
file-structure:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: Generate File Structure Diagram
|
||||
uses: githubocto/repo-visualizer@0.7.1
|
||||
with:
|
||||
@ -19,7 +20,28 @@ jobs:
|
||||
excluded_paths: dist,node_modules
|
||||
commit_message: ':yellow_heart: Updates repo diagram'
|
||||
branch: master
|
||||
|
||||
|
||||
# Hercules git branching stats
|
||||
git-stats:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Hercules
|
||||
uses: src-d/hercules@master
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: hercules_charts
|
||||
path: hercules_charts.tar
|
||||
|
||||
# Lowlighter metrics community metrics
|
||||
community-stats:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@master
|
||||
- name: Generate Repo Metrics
|
||||
uses: lowlighter/metrics@latest
|
||||
with:
|
||||
@ -32,7 +54,7 @@ jobs:
|
||||
user: Lissy93
|
||||
repo: dashy
|
||||
delay: 5
|
||||
|
||||
|
||||
- name: Generate License Metrics
|
||||
uses: lowlighter/metrics@latest
|
||||
with:
|
||||
@ -67,5 +89,4 @@ jobs:
|
||||
plugin_contributors_ignored: bot
|
||||
plugin_contributors_contributions: yes
|
||||
plugin_contributors_sections: contributors
|
||||
|
||||
|
||||
|
15
.github/workflows/save-repo-analytics.yml
vendored
Normal file
15
.github/workflows/save-repo-analytics.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
name: 📊 Save Repo Analytics
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 1 * * 0' # At 01:00 on Sunday.
|
||||
jobs:
|
||||
gen-stats:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repo Analytics
|
||||
uses: jgehrcke/github-repo-stats@HEAD
|
||||
with:
|
||||
repository: lissy93/dashy
|
||||
databranch: DATA/repo-stats
|
||||
ghtoken: ${{ secrets.BOT_GITHUB_TOKEN }}
|
17
.github/workflows/unfurl-links.yml
vendored
Normal file
17
.github/workflows/unfurl-links.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# Expands any raw pasted link in comments. Useful so people know what they're clicking
|
||||
name: 🎯 Unfurl Links
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
issue_comment:
|
||||
types: [created, edited]
|
||||
pull_request:
|
||||
types: [opened, edited]
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/unfurl-links@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
raw: true
|
@ -14,7 +14,9 @@ This is the main page that you will land on when you first launch the applicatio
|
||||
### Workspace
|
||||
The workspace view displays your links in a sidebar on the left-hand side, and apps are launched within Dashy. This enables you to use all of your self-hosted apps from one place, and makes multi-tasking easy.
|
||||
|
||||
In the workspace view, you can keep previously opened websites/ apps open in the background, by setting `appConfig.enableMultiTasking: true`. This comes at the cost of performance, but does mean that your session with each app is preserved, enabling you to quickly switch between your apps.
|
||||
In the workspace view, you can opt to keep previously opened websites/ apps open in the background, by setting `appConfig.enableMultiTasking: true`. This comes at the cost of performance, but does mean that your session with each app is preserved, enabling you to quickly switch between your apps.
|
||||
|
||||
You can also specify a default app to be opened when you land on the workspace, by setting `appConfig.workspaceLandingUrl: https://app-to-open/`. If this app exists within your sections.items, then the corresponding section will also be expanded.
|
||||
|
||||
<p align="center">
|
||||
<b>Example of Workspace View</b><br>
|
||||
|
@ -82,8 +82,9 @@ Tips:
|
||||
**`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`)
|
||||
**`faviconApi`** | `enum` | _Optional_ | Only applicable if you are using favicons for item icons. Specifies which service to use to resolve favicons. Set to `local` to do this locally, without using an API. Services running locally will use this option always. Available options are: `local`, `faviconkit`, `google`, `clearbit`, `webmasterapi` and `allesedv`. Defaults to `faviconkit`. See [Icons](/docs/icons.md#favicons) for more info
|
||||
**`auth`** | `object` | _Optional_ | All settings relating to user authentication. See [`auth`](#appconfigauth-optional)
|
||||
**`layout`** | `enum` | _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.
|
||||
**`layout`** | `enum` | _Optional_ | Layout for homepage, either `horizontal`, `vertical` or `auto`. Defaults to `auto`. This specifies the layout and direction of how sections are positioned on the home screen. This can also be modified and overridden from the UI.
|
||||
**`iconSize`** | `enum` | _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.
|
||||
**`colCount`** | `number` | _Optional_ | The number of columns of sections displayed on the homepage, using the default view. Should be in integer between `1` and `8`. Note that by default this is applied responsively, based on current screen size, and specifying a value here will override this behavior, which may not be desirable.
|
||||
**`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
|
||||
**`customColors`** | `object`| _Optional_ | Enables you to apply a custom color palette to any given theme. Use the theme name (lowercase) as the key, for an object including key-value-pairs, with the color variable name as keys, and 6-digit hex code as value. See [Theming](/docs/theming.md#modifying-theme-colors) for more info
|
||||
@ -91,6 +92,7 @@ Tips:
|
||||
**`customCss`** | `string` | _Optional_ | Raw CSS that will be applied to the page. This can also be set from the UI. Please minify it first.
|
||||
**`hideComponents`** | `object` | _Optional_ | A list of key page components (header, footer, search, settings, etc) that are present by default, but can be removed using this option. See [`appConfig.hideComponents`](#appconfighideComponents-optional)
|
||||
**`enableMultiTasking`** | `boolean` | _Optional_ | If set to true, will keep apps open in the background when in the workspace view. Useful for quickly switching between multiple sites, and preserving their state, but comes at the cost of performance.
|
||||
**`workspaceLandingUrl`** | `string` | _Optional_ | The URL or an app, service or website to launch when the workspace view is opened, before another service has been launched
|
||||
**`allowConfigEdit`** | `boolean` | _Optional_ | Should prevent / allow the user to write configuration changes to the conf.yml from the UI. When set to `false`, the user can only apply changes locally using the config editor within the app, whereas if set to `true` then changes can be written to disk directly through the UI. Defaults to `true`. Note that if authentication is enabled, the user must be of type `admin` in order to apply changes globally.
|
||||
**`enableErrorReporting`** | `boolean` | _Optional_ | Enable reporting of unexpected errors and crashes. This is off by default, and **no data will ever be captured unless you explicitly enable it**. Turning on error reporting helps previously unknown bugs get discovered and fixed. Dashy uses [Sentry](https://github.com/getsentry/sentry) for error reporting. Defaults to `false`.
|
||||
**`sentryDsn`** | `boolean` | _Optional_ | If you need to monitor errors in your instance, then you can use Sentry to collect and process bug reports. Sentry can be self-hosted, or used as SaaS, once your instance is setup, then all you need to do is pass in the DSN here, and enable error reporting. You can learn more on the [Sentry DSN Docs](https://docs.sentry.io/product/sentry-basics/dsn-explainer/). Note that this will only ever be used if `enableErrorReporting` is explicitly enabled.
|
||||
|
@ -75,10 +75,10 @@ If for a given service none of the APIs work in your situation, and nor does loc
|
||||
---
|
||||
|
||||
## Generative Icons
|
||||
Uses a unique and programmatically generated icon for a given service. This is particularly useful when you have a lot of similar services with a different IP or port, and no specific icon. These icons are generated with [ipsicon.io](https://ipsicon.io/). To use this option, just set an item's to: `icon: generative`.
|
||||
Uses a unique and programmatically generated icon for a given service. This is particularly useful when you have a lot of similar services with a different IP or port, and no specific icon. These icons are generated with [DiceBear](https://avatars.dicebear.com/), and use a hash of the services domain/ ip for entropy, so each domain will always have the same icon. To use this option, just set an item's to: `icon: generative`.
|
||||
|
||||
<p align="center">
|
||||
<img width="400" src="https://i.ibb.co/qrNNNcm/generative-icons.png" />
|
||||
<img width="500" src="https://i.ibb.co/b2pC2CL/generative-icons-2.png" />
|
||||
</p>
|
||||
|
||||
---
|
||||
@ -94,6 +94,32 @@ For example, these will all render the same rocket (🚀) emoji: `icon: ':rocket
|
||||
|
||||
---
|
||||
|
||||
## Home-Lab Icons
|
||||
|
||||
The [dashboard-icons](https://github.com/WalkxCode/dashboard-icons) repo by [@WalkxCode](https://github.com/WalkxCode) provides a comprehensive collection of 360+ high-quality PNG icons for commonly self-hosted services. Dashy natively supports these icons, and you can use them just by specifying the icon name (without extension) preceded by `hl-`. You can see a full list of all available icons [here](https://github.com/WalkxCode/dashboard-icons/tree/master/png).
|
||||
|
||||
For example:
|
||||
```yaml
|
||||
sections:
|
||||
- name: Home Lab Icons Example
|
||||
items:
|
||||
- title: AdGuard Home
|
||||
icon: hl-adguardhome
|
||||
- title: Long Horn
|
||||
icon: hl-longhorn
|
||||
- title: Nagios
|
||||
icon: hl-nagios
|
||||
- title: Whoogle Search
|
||||
icon: hl-whooglesearch
|
||||
```
|
||||
|
||||
|
||||
<p align="center">
|
||||
<img width="580" src="https://i.ibb.co/PQzYHmD/homelab-icons-2.png" />
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## Icons by URL
|
||||
You can also set an icon by passing in a valid URL pointing to the icons location. For example `icon: https://i.ibb.co/710B3Yc/space-invader-x256.png`, this can be in .png, .jpg or .svg format, and hosted anywhere- so long as it's accessible from where you are hosting Dashy. The icon will be automatically scaled to fit, however loading in a lot of large icons may have a negative impact on performance, especially if you visit Dashy from new devices often.
|
||||
|
||||
@ -127,3 +153,20 @@ sections:
|
||||
|
||||
## No Icon
|
||||
If you don't wish for a given item or section to have an icon, just leave out the `icon` attribute.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Icon Collections and Resources
|
||||
|
||||
The following website provide good-quality, free icon sets. To use any of these icons, just copy the link to the raw icon (it should end in `.svg` or `.png`) and paste it as your `icon`, or download and save the icons in `/public/item-icons` or pass through with a Docker volume as described above.
|
||||
Full credit to the authors, please see the licenses for each service for usage and copyright information.
|
||||
|
||||
- [dashboard-icons](https://github.com/WalkxCode/dashboard-icons) - 350+ high-quality icons for commonly self-hosted services, maintained by [@WalkxCode](https://github.com/WalkxCode)
|
||||
- [SVG Box](https://svgbox.net/iconsets/) - Cryptocurrency, social media apps and flag icons
|
||||
- [Simple Icons](https://simpleicons.org/) - Free SVG brand icons, with easy API access
|
||||
- [Icons8](https://icons8.com/icons) - Thousands of icons, all with free 64x64 versions
|
||||
- [Flat Icon](https://www.flaticon.com/) - Wide variety of icon sets, almost all free to use
|
||||
|
||||
If you are a student, then you can get free access to premium icons on [Icon Scout](https://education.github.com/pack/redeem/iconscout-student) or [Icons8](https://icons8.com/github-students) using the GitHub Student Pack.
|
||||
|
||||
|
@ -18,6 +18,10 @@ If an item's icon is set to `favicon`, then it will be auto-fetched from the cor
|
||||
|
||||
The default favicon API is [Favicon Kit](https://faviconkit.com/), but this can be changed by setting `appConfig.faviconApi` to an alternate source (`google`, `clearbit`, `webmasterapi` and `allesedv` are supported). If you do not want to use any API, then you can set this property to `local`, and the favicon will be fetched from the default path. For hosted services, this will still incur an external request.
|
||||
|
||||
### Generative Icons
|
||||
If an item has the icon set to `generative`, then an external request it made to [Dice Bear](https://dicebear.com/) to fetch the uniquely generated icon. The URL of a given service is used as the key for generating the icon, but it is first hashed and encoded for basic privacy. For more info, please reference the [Dicebear Privacy Policy](https://avatars.dicebear.com/legal/privacy-policy)
|
||||
|
||||
|
||||
### Other Icons
|
||||
Section icons, item icons and app icons are able to accept a URL to a raw image, if the image is hosted online then an external request will be made. To avoid the need to make external requests for icon assets, you can either use a self-hosted CDN, or store your images within `./public/item-icons` (which can be mounted as a volume if you're using Docker).
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Dashy",
|
||||
"version": "1.8.4",
|
||||
"version": "1.8.5",
|
||||
"license": "MIT",
|
||||
"main": "server",
|
||||
"scripts": {
|
||||
|
@ -4,7 +4,7 @@
|
||||
<div class="css-wrapper">
|
||||
<h2 class="css-input-title">Custom CSS</h2>
|
||||
<textarea class="css-editor" v-model="customCss" />
|
||||
<button class="save-button" @click="save()">{{ $t('config.css-save-btn') }}</button>
|
||||
<Button class="save-button" :click="save">{{ $t('config.css-save-btn') }}</button>
|
||||
<p class="quick-note">
|
||||
<b>{{ $t('config.css-note-label') }}:</b>
|
||||
{{ $t('config.css-note-l1') }} {{ $t('config.css-note-l2') }} {{ $t('config.css-note-l3') }}
|
||||
@ -19,6 +19,7 @@
|
||||
<script>
|
||||
|
||||
import CustomThemeMaker from '@/components/Settings/CustomThemeMaker';
|
||||
import Button from '@/components/FormElements/Button';
|
||||
import { getTheme } from '@/utils/ConfigHelpers';
|
||||
import { localStorageKeys } from '@/utils/defaults';
|
||||
import { InfoHandler } from '@/utils/ErrorHandler';
|
||||
@ -29,6 +30,7 @@ export default {
|
||||
config: Object,
|
||||
},
|
||||
components: {
|
||||
Button,
|
||||
CustomThemeMaker,
|
||||
},
|
||||
data() {
|
||||
@ -38,26 +40,21 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/* A regex to validate the users CSS */
|
||||
validate(css) {
|
||||
return css === '' || css.match(/([#.@]?[\w.:> ]+)[\s]{[\r\n]?([A-Za-z\- \r\n\t]+[:][\s]*[\w ./()\-!]+;[\r\n]*(?:[A-Za-z\- \r\n\t]+[:][\s]*[\w ./()\-!]+;[\r\n]*(2)*)*)}/gmi);
|
||||
},
|
||||
/* Save custom CSS in browser, call inject, and show success message */
|
||||
save() {
|
||||
let msg = '';
|
||||
if (this.validate(this.customCss)) {
|
||||
const appConfig = { ...this.config.appConfig };
|
||||
appConfig.customCss = this.customCss;
|
||||
localStorage.setItem(localStorageKeys.APP_CONFIG, JSON.stringify(appConfig));
|
||||
msg = 'Changes saved successfully';
|
||||
InfoHandler('User syles has been saved', 'Custom CSS Update');
|
||||
this.inject(this.customCss);
|
||||
if (this.customCss === '') setTimeout(() => { location.reload(); }, 1500); // eslint-disable-line no-restricted-globals
|
||||
} else {
|
||||
msg = 'Error - Invalid CSS';
|
||||
InfoHandler(msg, 'Custom CSS Update');
|
||||
}
|
||||
this.$toasted.show(msg);
|
||||
// Get, and sanitize users CSS
|
||||
const css = this.customCss.replace(/<\/?[^>]+(>|$)/g, '');
|
||||
// Update app config, and apply settings locally
|
||||
const appConfig = { ...this.config.appConfig };
|
||||
appConfig.customCss = css;
|
||||
localStorage.setItem(localStorageKeys.APP_CONFIG, JSON.stringify(appConfig));
|
||||
// Immidiatley inject new CSS
|
||||
this.inject(css);
|
||||
// If reseting styles, then refresh the page
|
||||
if (css === '') setTimeout(() => { location.reload(); }, 1500); // eslint-disable-line no-restricted-globals
|
||||
// Show status message
|
||||
InfoHandler('User syles has been saved', 'Custom CSS Update');
|
||||
this.$toasted.show('Changes saved successfully');
|
||||
},
|
||||
/* Formats CSS, and applies it to page */
|
||||
inject(userStyles) {
|
||||
@ -72,6 +69,7 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
// Main layout
|
||||
div.css-editor-outer {
|
||||
text-align: center;
|
||||
padding-bottom: 1rem;
|
||||
@ -87,22 +85,19 @@ div.css-editor-outer {
|
||||
}
|
||||
}
|
||||
|
||||
button.save-button {
|
||||
padding: 0.5rem 1rem;
|
||||
margin: 0.25rem auto;
|
||||
font-size: 1.2rem;
|
||||
// Save button
|
||||
button.save-button{
|
||||
background: var(--config-settings-color);
|
||||
color: var(--config-settings-background);
|
||||
border: 1px solid var(--config-settings-background);
|
||||
border-radius: var(--curve-factor);
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
&:hover:not(:disabled) {
|
||||
background: var(--config-settings-background);
|
||||
color: var(--config-settings-color);
|
||||
border-color: var(--config-settings-color);
|
||||
}
|
||||
}
|
||||
|
||||
// CSS textarea input
|
||||
.css-editor {
|
||||
margin: 1rem auto;
|
||||
padding: 0.5rem;
|
||||
@ -121,6 +116,7 @@ button.save-button {
|
||||
}
|
||||
}
|
||||
|
||||
// Info note
|
||||
p.quick-note {
|
||||
text-align: left;
|
||||
width: 80%;
|
||||
@ -131,6 +127,7 @@ p.quick-note {
|
||||
border-radius: var(--curve-factor);
|
||||
}
|
||||
|
||||
// Theme editor
|
||||
.color-config.theme-configurator-wrapper {
|
||||
border: 1px solid var(--config-settings-color);
|
||||
background: var(--config-settings-background);
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template ref="container">
|
||||
<div class="item-wrapper">
|
||||
<div :class="`item-wrapper wrap-size-${itemSize}`">
|
||||
<a @click="itemOpened"
|
||||
@mouseup.right="openContextMenu"
|
||||
@contextmenu.prevent
|
||||
@ -144,7 +144,7 @@ export default {
|
||||
html: true,
|
||||
placement: this.statusResponse ? 'left' : 'auto',
|
||||
delay: { show: 600, hide: 200 },
|
||||
classes: 'item-description-tooltip',
|
||||
classes: `item-description-tooltip tooltip-is-${this.itemSize}`,
|
||||
};
|
||||
},
|
||||
/* Used by certain themes, which display an icon with animated CSS */
|
||||
@ -239,6 +239,10 @@ export default {
|
||||
|
||||
.item-wrapper {
|
||||
flex-grow: 1;
|
||||
flex-basis: 6rem;
|
||||
&.wrap-size-large {
|
||||
flex-basis: 12rem;
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
@ -392,11 +396,13 @@ export default {
|
||||
width: 100%;
|
||||
}
|
||||
p.description {
|
||||
display: block;
|
||||
margin: 0;
|
||||
display: block;
|
||||
white-space: pre-wrap;
|
||||
font-size: .9em;
|
||||
text-overflow: ellipsis;
|
||||
font-size: .9em;
|
||||
line-height: 1rem;
|
||||
height: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="item-icon">
|
||||
<div :class="`item-icon wrapper-${size}`">
|
||||
<!-- Font-Awesome Icon -->
|
||||
<i v-if="iconType === 'font-awesome'" :class="`${icon} ${size}`" ></i>
|
||||
<!-- Emoji Icon -->
|
||||
@ -23,9 +23,10 @@
|
||||
import simpleIcons from 'simple-icons';
|
||||
import BrokenImage from '@/assets/interface-icons/broken-icon.svg';
|
||||
import ErrorHandler from '@/utils/ErrorHandler';
|
||||
import { faviconApi as defaultFaviconApi, faviconApiEndpoints, iconCdns } from '@/utils/defaults';
|
||||
import EmojiUnicodeRegex from '@/utils/EmojiUnicodeRegex';
|
||||
import emojiLookup from '@/utils/emojis.json';
|
||||
import { faviconApi as defaultFaviconApi, faviconApiEndpoints, iconCdns } from '@/utils/defaults';
|
||||
import { asciiHash } from '@/utils/MiscHelpers';
|
||||
|
||||
export default {
|
||||
name: 'Icon',
|
||||
@ -127,7 +128,8 @@ export default {
|
||||
},
|
||||
/* Formats the URL for fetching the generative icons */
|
||||
getGenerativeIcon(url) {
|
||||
return `${iconCdns.generative}/${this.getHostName(url)}.svg`;
|
||||
const host = encodeURI(url) || Math.random().toString();
|
||||
return iconCdns.generative.replace('{icon}', asciiHash(host));
|
||||
},
|
||||
/* Returns the SVG path content */
|
||||
getSimpleIcon(img) {
|
||||
@ -135,6 +137,11 @@ export default {
|
||||
const icon = simpleIcons.Get(imageName);
|
||||
return icon.path;
|
||||
},
|
||||
/* Gets home-lab icon from GitHub */
|
||||
getHomeLabIcon(img) {
|
||||
const imageName = img.replace('hl-', '').toLocaleLowerCase();
|
||||
return iconCdns.homeLabIcons.replace('{icon}', imageName);
|
||||
},
|
||||
/* Checks if the icon is from a local image, remote URL, SVG or font-awesome */
|
||||
getIconPath(img, url) {
|
||||
switch (this.determineImageType(img)) {
|
||||
@ -145,6 +152,7 @@ export default {
|
||||
case 'generative': return this.getGenerativeIcon(url);
|
||||
case 'mdi': return img; // Material design icons
|
||||
case 'simple-icons': return this.getSimpleIcon(img);
|
||||
case 'home-lab-icons': return this.getHomeLabIcon(img);
|
||||
case 'svg': return img; // Local SVG icon
|
||||
case 'emoji': return img; // Emoji/ unicode
|
||||
default: return '';
|
||||
@ -159,6 +167,7 @@ export default {
|
||||
else if (img.includes('fa-')) imgType = 'font-awesome';
|
||||
else if (img.includes('mdi-')) imgType = 'mdi';
|
||||
else if (img.includes('si-')) imgType = 'si';
|
||||
else if (img.includes('hl-')) imgType = 'home-lab-icons';
|
||||
else if (img.includes('favicon-')) imgType = 'custom-favicon';
|
||||
else if (img === 'favicon') imgType = 'favicon';
|
||||
else if (img === 'generative') imgType = 'generative';
|
||||
@ -180,6 +189,18 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
/* Icon wraper */
|
||||
.item-icon {
|
||||
&.wrapper-medium {
|
||||
min-height: 2.5rem;
|
||||
}
|
||||
&.wrapper-large {
|
||||
min-width: 3.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* Default Image Icon */
|
||||
.tile-icon {
|
||||
min-width: 1rem;
|
||||
|
@ -178,9 +178,9 @@ export default {
|
||||
padding: 0.8rem;
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
border-radius: var(--curve-factor);
|
||||
background: #607d8b33;
|
||||
color: var(--primary);
|
||||
background: var(--item-background);
|
||||
border-radius: var(--curve-factor);
|
||||
box-shadow: var(--item-shadow);
|
||||
}
|
||||
|
||||
@ -192,12 +192,13 @@ export default {
|
||||
display: grid;
|
||||
overflow: auto;
|
||||
@extend .scroll-bar;
|
||||
@include phone { grid-template-columns: repeat(1, 1fr); }
|
||||
@include tablet { grid-template-columns: repeat(2, 1fr); }
|
||||
@include laptop { grid-template-columns: repeat(2, 1fr); }
|
||||
@include monitor { grid-template-columns: repeat(3, 1fr); }
|
||||
@include big-screen { grid-template-columns: repeat(4, 1fr); }
|
||||
@include big-screen-up { grid-template-columns: repeat(5, 1fr); }
|
||||
@include phone { --item-col-count: 1; }
|
||||
@include tablet { --item-col-count: 2; }
|
||||
@include laptop { --item-col-count: 2; }
|
||||
@include monitor { --item-col-count: 3; }
|
||||
@include big-screen { --item-col-count: 4; }
|
||||
@include big-screen-up { --item-col-count: 5; }
|
||||
grid-template-columns: repeat(var(--item-col-count, 2), minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
.orientation-horizontal {
|
||||
@ -205,13 +206,13 @@ export default {
|
||||
flex-direction: column;
|
||||
.there-are-items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
@include phone { grid-template-columns: repeat(2, 1fr); }
|
||||
@include tablet { grid-template-columns: repeat(4, 1fr); }
|
||||
@include laptop { grid-template-columns: repeat(6, 1fr); }
|
||||
@include monitor { grid-template-columns: repeat(8, 1fr); }
|
||||
@include big-screen { grid-template-columns: repeat(10, 1fr); }
|
||||
@include big-screen-up { grid-template-columns: repeat(12, 1fr); }
|
||||
@include phone { --item-col-count: 2; }
|
||||
@include tablet { --item-col-count: 4; }
|
||||
@include laptop { --item-col-count: 6; }
|
||||
@include monitor { --item-col-count: 8; }
|
||||
@include big-screen { --item-col-count: 10; }
|
||||
@include big-screen-up { --item-col-count: 12; }
|
||||
grid-template-columns: repeat(var(--item-col-count, 2), minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ export default {
|
||||
inject: ['config'],
|
||||
props: {
|
||||
sections: Array,
|
||||
initUrl: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -56,9 +57,22 @@ export default {
|
||||
openSection(index) {
|
||||
this.isOpen = this.isOpen.map((val, ind) => (ind !== index ? false : !val));
|
||||
},
|
||||
launchApp(url) {
|
||||
this.$emit('launch-app', url);
|
||||
/* When item clicked, emit a launch event */
|
||||
launchApp(options) {
|
||||
this.$emit('launch-app', options);
|
||||
},
|
||||
/* If an initial URL is specified, then open relevant section */
|
||||
openDefaultSection() {
|
||||
if (!this.initUrl) return;
|
||||
const process = (url) => url.replace(/[^\w\s]/gi, '').toLowerCase();
|
||||
const compare = (item) => (process(item.url) === process(this.initUrl));
|
||||
this.sections.forEach((section, sectionIndex) => {
|
||||
if (section.items.findIndex(compare) !== -1) this.openSection(sectionIndex);
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.openDefaultSection();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -17,6 +17,7 @@ export default {
|
||||
icon: String,
|
||||
title: String,
|
||||
url: String,
|
||||
target: String,
|
||||
click: Function,
|
||||
},
|
||||
components: {
|
||||
@ -24,7 +25,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
itemClicked() {
|
||||
if (this.url) this.$emit('launch-app', this.url);
|
||||
if (this.url) this.$emit('launch-app', { url: this.url, target: this.target });
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
@ -6,6 +6,7 @@
|
||||
:icon="item.icon"
|
||||
:title="item.title"
|
||||
:url="item.url"
|
||||
:target="item.target"
|
||||
@launch-app="launchApp"
|
||||
/>
|
||||
</div>
|
||||
@ -26,8 +27,8 @@ export default {
|
||||
SideBarItem,
|
||||
},
|
||||
methods: {
|
||||
launchApp(url) {
|
||||
this.$emit('launch-app', url);
|
||||
launchApp(options) {
|
||||
this.$emit('launch-app', options);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -406,7 +406,7 @@ html[data-theme='material'], html[data-theme='material-dark'] {
|
||||
}
|
||||
}
|
||||
}
|
||||
.tooltip.item-description-tooltip {
|
||||
.tooltip.item-description-tooltip:not(.tooltip-is-small) {
|
||||
display: none !important;
|
||||
}
|
||||
.orientation-horizontal {
|
||||
|
@ -145,6 +145,12 @@
|
||||
"default": "medium",
|
||||
"description": "The size of each link item / icon"
|
||||
},
|
||||
"colCount": {
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 8,
|
||||
"description": "Number of section columns for homepage. Leave blank for column count to be responsively calculated based on screen size"
|
||||
},
|
||||
"hideComponents": {
|
||||
"type": "object",
|
||||
"description": "Hide individual parts of the page. If not set, all components are visible by default",
|
||||
@ -385,6 +391,10 @@
|
||||
"sentryDsn": {
|
||||
"type": "string",
|
||||
"description": "The DSN to your self-hosted Sentry server, if you need to collect bug reports. Only used if enableErrorReporting is enabled"
|
||||
},
|
||||
"workspaceLandingUrl": {
|
||||
"type": "string",
|
||||
"description": "The URL of an app, service or website to render when the Workspace view is opened"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
@ -3,4 +3,11 @@ import { hideFurnitureOn } from '@/utils/defaults';
|
||||
/* Returns false if page furniture should be hidden on said route */
|
||||
export const shouldBeVisible = (routeName) => !hideFurnitureOn.includes(routeName);
|
||||
|
||||
export const x = () => null;
|
||||
/* Very rudimentary hash function for generative icons */
|
||||
export const asciiHash = (input) => {
|
||||
const str = (!input || input.length === 0) ? Math.random().toString() : input;
|
||||
const reducer = (previousHash, char) => (previousHash || 0) + char.charCodeAt(0);
|
||||
const asciiSum = str.split('').reduce(reducer).toString();
|
||||
const shortened = asciiSum.slice(0, 30) + asciiSum.slice(asciiSum.length - 30);
|
||||
return window.btoa(shortened);
|
||||
};
|
||||
|
@ -173,9 +173,10 @@ module.exports = {
|
||||
fa: 'https://kit.fontawesome.com',
|
||||
mdi: 'https://cdn.jsdelivr.net/npm/@mdi/font@5.9.55/css/materialdesignicons.min.css',
|
||||
si: 'https://unpkg.com/simple-icons@v5/icons',
|
||||
generative: 'https://ipsicon.io',
|
||||
generative: 'https://avatars.dicebear.com/api/identicon/{icon}.svg',
|
||||
localPath: '/item-icons',
|
||||
faviconName: 'favicon.ico',
|
||||
homeLabIcons: 'https://raw.githubusercontent.com/WalkxCode/dashboard-icons/master/png/{icon}.png',
|
||||
},
|
||||
/* URLs for web search engines */
|
||||
searchEngineUrls: {
|
||||
|
@ -18,7 +18,11 @@
|
||||
/>
|
||||
<!-- Main content, section for each group of items -->
|
||||
<div v-if="checkTheresData(sections)"
|
||||
:class="`item-group-container orientation-${layout} item-size-${itemSizeBound}`">
|
||||
:class="`item-group-container `
|
||||
+ `orientation-${layout} `
|
||||
+ `item-size-${itemSizeBound} `
|
||||
+ (this.colCount ? `col-count-${this.colCount} ` : '')"
|
||||
>
|
||||
<Section
|
||||
v-for="(section, index) in filteredTiles"
|
||||
:key="index"
|
||||
@ -67,6 +71,14 @@ export default {
|
||||
modalOpen: false, // When true, keybindings are disabled
|
||||
}),
|
||||
computed: {
|
||||
/* Get class for num columns, if specified by user */
|
||||
colCount() {
|
||||
let { colCount } = this.appConfig;
|
||||
if (!colCount) return null;
|
||||
if (colCount < 1) colCount = 1;
|
||||
if (colCount > 8) colCount = 8;
|
||||
return colCount;
|
||||
},
|
||||
/* Combines sections from config file, with those in local storage */
|
||||
allSections() {
|
||||
// If the user has stored sections in local storage, return those
|
||||
@ -227,7 +239,6 @@ export default {
|
||||
.home {
|
||||
padding-bottom: 1px;
|
||||
background: var(--background);
|
||||
// min-height: calc(100vh - 126px);
|
||||
min-height: calc(99.9vh - var(--footer-height));
|
||||
}
|
||||
|
||||
@ -256,26 +267,27 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/* Specify number of columns, based on screen size */
|
||||
@include phone {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
@include tablet {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
@include laptop {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
@include monitor {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
@include big-screen {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
@include big-screen-up {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
/* Specify number of columns, based on screen size or user preference */
|
||||
@include phone { --col-count: 1; }
|
||||
@include tablet { --col-count: 2; }
|
||||
@include laptop { --col-count: 2; }
|
||||
@include monitor { --col-count: 3; }
|
||||
@include big-screen { --col-count: 4; }
|
||||
@include big-screen-up { --col-count: 5; }
|
||||
|
||||
@include tablet-up {
|
||||
&.col-count-1 { --col-count: 1; }
|
||||
&.col-count-2 { --col-count: 2; }
|
||||
&.col-count-3 { --col-count: 3; }
|
||||
&.col-count-4 { --col-count: 4; }
|
||||
&.col-count-5 { --col-count: 5; }
|
||||
&.col-count-6 { --col-count: 6; }
|
||||
&.col-count-7 { --col-count: 7; }
|
||||
&.col-count-8 { --col-count: 8; }
|
||||
}
|
||||
|
||||
grid-template-columns: repeat(var(--col-count, 2), minmax(0, 1fr));
|
||||
|
||||
/* Hide when search term returns nothing */
|
||||
.no-results { display: none; }
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="work-space">
|
||||
<SideBar :sections="sections" @launch-app="launchApp" />
|
||||
<SideBar :sections="sections" @launch-app="launchApp" :initUrl="getInitialUrl()" />
|
||||
<WebContent :url="url" v-if="!isMultiTaskingEnabled" />
|
||||
<MultiTaskingWebComtent :url="url" v-else />
|
||||
</div>
|
||||
@ -21,7 +21,7 @@ export default {
|
||||
appConfig: Object,
|
||||
},
|
||||
data: () => ({
|
||||
url: '', // this.$route.query.url || '',
|
||||
url: '',
|
||||
GetTheme,
|
||||
ApplyLocalTheme,
|
||||
ApplyCustomVariables,
|
||||
@ -37,8 +37,12 @@ export default {
|
||||
MultiTaskingWebComtent,
|
||||
},
|
||||
methods: {
|
||||
launchApp(url) {
|
||||
this.url = url;
|
||||
launchApp(options) {
|
||||
if (options.target === 'newtab') {
|
||||
window.open(options.url, '_blank');
|
||||
} else {
|
||||
this.url = options.url;
|
||||
}
|
||||
},
|
||||
setTheme() {
|
||||
const theme = this.GetTheme();
|
||||
@ -51,16 +55,21 @@ export default {
|
||||
fontAwesomeScript.setAttribute('src', `https://kit.fontawesome.com/${faKey}.js`);
|
||||
document.head.appendChild(fontAwesomeScript);
|
||||
},
|
||||
repositionFooter() {
|
||||
document.getElementsByTagName('footer')[0].style.position = 'fixed';
|
||||
/* Returns a service URL, if set as a URL param, or if user has specified landing URL */
|
||||
getInitialUrl() {
|
||||
const route = this.$route;
|
||||
if (route.query && route.query.url) {
|
||||
return decodeURI(route.query.url);
|
||||
} else if (this.appConfig.workspaceLandingUrl) {
|
||||
return this.appConfig.workspaceLandingUrl;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const route = this.$route;
|
||||
if (route.query && route.query.url) this.url = decodeURI(route.query.url);
|
||||
this.setTheme();
|
||||
this.initiateFontAwesome();
|
||||
// this.repositionFooter();
|
||||
this.url = this.getInitialUrl();
|
||||
},
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user