💥 Removes default footer, if not configured by user

This commit is contained in:
Alicia Sykes
2026-04-19 18:29:03 +01:00
parent 98a508078d
commit 4eab074172
10 changed files with 24 additions and 71 deletions

View File

@@ -73,7 +73,7 @@ The following file provides a reference of all supported configuration options.
**`title`** | `string` | Required | Your dashboard title, displayed in the header and browser tab
**`description`** | `string` | _Optional_ | Description of your dashboard, also displayed as a subtitle
**`navLinks`** | `array` | _Optional_ | Optional list of a maximum of 6 links, which will be displayed in the navigation bar. See [`navLinks`](#pageinfonavlinks-optional)
**`footerText`** | `string` | _Optional_ | Text to display in the footer (note that this will override the default footer content). This can also include HTML and inline CSS
**`footer`** | `string` | _Optional_ | Text to display in the footer. When omitted, no footer is rendered. Supports inline HTML (sanitized before render)
**`logo`** | `string` | _Optional_ | The path to an image to display in the header (to the right of the title). This can be either local, where `/` is the root of `./public`, or any remote image, such as `https://i.ibb.co/yhbt6CY/dashy.png`. It's recommended to scale your image down, so that it doesn't impact load times
**[⬆️ Back to Top](#configuring)**
@@ -128,7 +128,7 @@ For more info, see the[Multi-Page docs](/docs/pages-and-sections.md#multi-page-s
**`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
**`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
**`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)
**`hideComponents`** | `object` | _Optional_ | A list of key page components (header, nav, search, settings) 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
**`preventWriteToDisk`** | `boolean` | _Optional_ | If set to `true`, users will be prevented from saving config changes to disk through the UI
@@ -235,7 +235,6 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)**
**`hideNav`** | `boolean` | _Optional_ | If set to `true`, the navigation menu will not be visible. Defaults to `false`
**`hideSearch`** | `boolean` | _Optional_ | If set to `true`, the search bar will not be visible. Defaults to `false`
**`hideSettings`** | `boolean` | _Optional_ | If set to `true`, the settings menu will be initially collapsed. Defaults to `false`
**`hideFooter`** | `boolean` | _Optional_ | If set to `true`, the footer will not be visible. Defaults to `false`
**[⬆️ Back to Top](#configuring)**

View File

@@ -5,7 +5,7 @@
<Header :pageInfo="pageInfo" />
<router-view v-if="!isFetching" />
<CriticalError v-if="hasCriticalError" />
<Footer :text="footerText" v-if="visibleComponents.footer && !isFetching" />
<Footer :text="footerText" v-if="footerVisible && !isFetching" />
</div>
</template>
<script>
@@ -51,7 +51,11 @@ export default {
computed: {
/* If the user has specified custom text for footer - get it */
footerText() {
return this.pageInfo && this.pageInfo.footerText ? this.pageInfo.footerText : '';
return this.pageInfo && this.pageInfo.footer ? this.pageInfo.footer : '';
},
/* Footer renders only when the user has set text/html */
footerVisible() {
return !!this.footerText;
},
/* Determine if splash screen should be shown */
shouldShowSplash() {
@@ -85,8 +89,8 @@ export default {
topLevelStyleModifications() {
const vc = this.visibleComponents;
let styles = '';
if (!vc.footer && !vc.pageTitle) styles += '--footer-height: 1rem;';
else if (!vc.footer) styles += '--footer-height: 5rem;';
if (!this.footerVisible && !vc.pageTitle) styles += '--footer-height: 1rem;';
else if (!this.footerVisible) styles += '--footer-height: 5rem;';
else if (!vc.pageTitle) styles += '--footer-height: 4rem;';
const maxWidth = this.parseContentMaxWidth(this.appConfig.contentMaxWidth);
if (maxWidth) {

View File

@@ -11,8 +11,8 @@
<input v-model="formElements.description" />
</div>
<div class="row">
<span>Footer Text</span>
<input v-model="formElements.footerText" />
<span>Footer</span>
<input v-model="formElements.footer" />
</div>
</div>
<div class="form">
@@ -59,7 +59,7 @@ export default {
const pageInfo = { ...this.config.pageInfo };
pageInfo.title = this.formElements.title;
pageInfo.description = this.formElements.description;
pageInfo.footerText = this.formElements.footerText;
pageInfo.footer = this.formElements.footer;
if (this.formElements.navLinks) {
pageInfo.navLinks = this.formElements.navLinks.filter(link => (link.title !== ''));
}
@@ -76,7 +76,7 @@ export default {
formElements: {
title: this.config.pageInfo.title,
description: this.config.pageInfo.description,
footerText: this.config.pageInfo.footerText,
footer: this.config.pageInfo.footer,
navLinks: this.config.pageInfo.navLinks || [],
},
};

View File

@@ -253,6 +253,7 @@ export default {
/* Icon wraper */
.item-icon {
border-radius: var(--curve-factor);
&.wrapper-medium {
min-height: 2.5rem;
}
@@ -319,7 +320,7 @@ export default {
i.emoji-icon {
font-style: normal;
font-size: 2rem;
margin: 0.2rem;
margin: 0;
&.small {
font-size: 1.5rem;
}

View File

@@ -1,15 +1,5 @@
<template>
<footer v-if="visible">
<!-- User-defined footer -->
<span v-if="text" v-html="sanitizedText"></span>
<!-- Default footer -->
<span v-else>
<a :href="defaultInfo.projectUrl">Dashy</a> is free & open source
- licensed under <a :href="defaultInfo.licenseUrl">{{defaultInfo.license}}</a>,
© <a :href="defaultInfo.authorUrl">{{defaultInfo.authorName}}</a> {{defaultInfo.date}}.
Get support on GitHub, at <a :href="defaultInfo.repoUrl">{{defaultInfo.repoName}}</a>.
</span>
</footer>
<footer v-if="visible && text" v-html="sanitizedText"></footer>
</template>
<script>
@@ -22,20 +12,6 @@ export default {
props: {
text: String,
},
data() {
return {
defaultInfo: {
authorName: 'Alicia Sykes',
authorUrl: 'https://as93.net',
license: 'MIT',
licenseUrl: 'https://gist.github.com/Lissy93/143d2ee01ccc5c052a17',
date: `${new Date().getFullYear()}`,
repoUrl: 'https://github.com/lissy93/dashy',
repoName: 'Lissy93/Dashy',
projectUrl: 'https://dashy.to',
},
};
},
computed: {
visible() {
return shouldBeVisible(this.$route.name);
@@ -60,27 +36,11 @@ footer {
background: var(--footer-background);
margin-top: 1.5rem;
border-top: 1px solid var(--outline-color);
@include tablet-down {
display: none;
}
span.path-to-config {
float: left;
font-size: 0.75rem;
margin: 0.1rem 0.5rem 0 0;
opacity: var(--dimming-factor);
max-width: 10rem;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
max-height: 1rem;
}
}
footer a{
:global(footer a) {
color: var(--footer-text-color);
&:hover {
color: var(--footer-text-color-link);
}
}
</style>

View File

@@ -82,4 +82,3 @@ button svg, a svg {
}
}
}

View File

@@ -68,8 +68,6 @@ export const componentVisibility = (appConfig) => {
? !usersChoice.hideSearch : visibleComponents.searchBar,
settings: isThere(usersChoice.hideSettings)
? !usersChoice.hideSettings : visibleComponents.settings,
footer: isThere(usersChoice.hideFooter)
? !usersChoice.hideFooter : visibleComponents.footer,
};
};

View File

@@ -160,9 +160,9 @@
}
}
},
"footerText": {
"title": "Footer Text",
"description": "Content to display within the global page footer",
"footer": {
"title": "Footer",
"description": "Content to display within the global page footer. Supports inline HTML (sanitized before render).",
"type": "string"
},
"logo": {
@@ -499,12 +499,6 @@
"type": "boolean",
"default": false,
"description": "If set to true, the settings buttons will be hidden"
},
"hideFooter": {
"title": "Hide Footer?",
"type": "boolean",
"default": false,
"description": "If set to true, the page footer will be hidden"
}
}
},

View File

@@ -4,7 +4,7 @@ const defaults = {
title: 'Dashy',
description: '',
navLinks: [],
footerText: '',
footer: '',
},
/* Default appConfig to be used, if user does not specify their own */
appConfig: {},
@@ -111,7 +111,6 @@ const defaults = {
pageTitle: true,
searchBar: true,
settings: true,
footer: true,
},
/* A list of route names that page furniture (header, footer, etc) should be hidden on */
hideFurnitureOn: ['minimal', 'login', 'download'],

View File

@@ -69,7 +69,6 @@ describe('ConfigHelpers - componentVisibility', () => {
expect(result.navigation).toBe(true);
expect(result.searchBar).toBe(true);
expect(result.settings).toBe(true);
expect(result.footer).toBe(true);
});
it('hides components based on config', () => {
@@ -88,11 +87,11 @@ describe('ConfigHelpers - componentVisibility', () => {
it('handles partial config correctly', () => {
const appConfig = {
hideComponents: {
hideFooter: true,
hideSettings: true,
},
};
const result = componentVisibility(appConfig);
expect(result.footer).toBe(false);
expect(result.settings).toBe(false);
expect(result.pageTitle).toBe(true);
});
});