mirror of
https://github.com/taigrr/homer
synced 2025-01-18 04:53:12 -08:00
Merge branches 'fixDuplicateKeys', 'info' and 'scheme+layout' into main
This commit is contained in:
commit
8ada6cca70
@ -22,10 +22,12 @@ header: true # Set to false to hide the header
|
|||||||
footer: '<p>Created with <span class="has-text-danger">❤️</span> with <a href="https://bulma.io/">bulma</a>, <a href="https://vuejs.org/">vuejs</a> & <a href="https://fontawesome.com/">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>' # set false if you want to hide it.
|
footer: '<p>Created with <span class="has-text-danger">❤️</span> with <a href="https://bulma.io/">bulma</a>, <a href="https://vuejs.org/">vuejs</a> & <a href="https://fontawesome.com/">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>' # set false if you want to hide it.
|
||||||
|
|
||||||
columns: "3" # "auto" or number (must be a factor of 12: 1, 2, 3, 4, 6, 12)
|
columns: "3" # "auto" or number (must be a factor of 12: 1, 2, 3, 4, 6, 12)
|
||||||
|
vlayout: true # default to the vertical layout
|
||||||
connectivityCheck: true # whether you want to display a message when the apps are not accessible anymore (VPN disconnected for example)
|
connectivityCheck: true # whether you want to display a message when the apps are not accessible anymore (VPN disconnected for example)
|
||||||
|
|
||||||
# Optional theming
|
# Optional theming
|
||||||
theme: default # 'default' or one of the theme available in 'src/assets/themes'.
|
theme: default # 'default' or one of the theme available in 'src/assets/themes'.
|
||||||
|
theme_use_dark: false # true or false, useful for overriding browser default in new sessions
|
||||||
|
|
||||||
# Optional custom stylesheet
|
# Optional custom stylesheet
|
||||||
# Will load custom CSS files. Especially useful for custom icon sets.
|
# Will load custom CSS files. Especially useful for custom icon sets.
|
||||||
@ -97,6 +99,8 @@ services:
|
|||||||
tag: "app"
|
tag: "app"
|
||||||
url: "https://www.reddit.com/r/selfhosted/"
|
url: "https://www.reddit.com/r/selfhosted/"
|
||||||
target: "_blank" # optional html tag target attribute
|
target: "_blank" # optional html tag target attribute
|
||||||
|
info: "https://github.com/bastienwirtz/homer/tree/main/docs" # optional link to documentation
|
||||||
|
infotarget: "_blank" # same as target, but for icon link
|
||||||
- name: "Another one"
|
- name: "Another one"
|
||||||
logo: "assets/tools/sample2.png"
|
logo: "assets/tools/sample2.png"
|
||||||
subtitle: "Another application"
|
subtitle: "Another application"
|
||||||
|
25
src/App.vue
25
src/App.vue
@ -28,9 +28,10 @@
|
|||||||
:links="config.links"
|
:links="config.links"
|
||||||
@navbar-toggle="showMenu = !showMenu"
|
@navbar-toggle="showMenu = !showMenu"
|
||||||
>
|
>
|
||||||
<DarkMode @updated="isDark = $event" />
|
<DarkMode :isDark="this.isDark" @updated="isDark = $event" />
|
||||||
|
|
||||||
<SettingToggle
|
<LayoutToggle
|
||||||
|
:vlayout="this.vlayout"
|
||||||
@updated="vlayout = $event"
|
@updated="vlayout = $event"
|
||||||
name="vlayout"
|
name="vlayout"
|
||||||
icon="fa-list"
|
icon="fa-list"
|
||||||
@ -119,7 +120,7 @@ import ConnectivityChecker from "./components/ConnectivityChecker.vue";
|
|||||||
import Service from "./components/Service.vue";
|
import Service from "./components/Service.vue";
|
||||||
import Message from "./components/Message.vue";
|
import Message from "./components/Message.vue";
|
||||||
import SearchInput from "./components/SearchInput.vue";
|
import SearchInput from "./components/SearchInput.vue";
|
||||||
import SettingToggle from "./components/SettingToggle.vue";
|
import LayoutToggle from "./components/LayoutToggle.vue";
|
||||||
import DarkMode from "./components/DarkMode.vue";
|
import DarkMode from "./components/DarkMode.vue";
|
||||||
import DynamicTheme from "./components/DynamicTheme.vue";
|
import DynamicTheme from "./components/DynamicTheme.vue";
|
||||||
|
|
||||||
@ -128,24 +129,24 @@ import defaultConfig from "./assets/defaults.yml";
|
|||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
components: {
|
components: {
|
||||||
Navbar,
|
|
||||||
ConnectivityChecker,
|
ConnectivityChecker,
|
||||||
Service,
|
|
||||||
Message,
|
|
||||||
SearchInput,
|
|
||||||
SettingToggle,
|
|
||||||
DarkMode,
|
DarkMode,
|
||||||
DynamicTheme,
|
DynamicTheme,
|
||||||
|
Message,
|
||||||
|
Navbar,
|
||||||
|
SearchInput,
|
||||||
|
Service,
|
||||||
|
LayoutToggle,
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
config: null,
|
config: null,
|
||||||
services: null,
|
|
||||||
offline: false,
|
|
||||||
filter: "",
|
filter: "",
|
||||||
vlayout: true,
|
|
||||||
isDark: null,
|
isDark: null,
|
||||||
|
offline: false,
|
||||||
|
services: null,
|
||||||
showMenu: false,
|
showMenu: false,
|
||||||
|
vlayout: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created: async function () {
|
created: async function () {
|
||||||
@ -159,6 +160,8 @@ export default {
|
|||||||
}
|
}
|
||||||
this.config = merge(defaults, config);
|
this.config = merge(defaults, config);
|
||||||
this.services = this.config.services;
|
this.services = this.config.services;
|
||||||
|
this.isDark = this.config.theme_use_dark;
|
||||||
|
this.vlayout = this.config.vlayout;
|
||||||
document.title =
|
document.title =
|
||||||
this.config.documentTitle ||
|
this.config.documentTitle ||
|
||||||
`${this.config.title} | ${this.config.subtitle}`;
|
`${this.config.title} | ${this.config.subtitle}`;
|
||||||
|
@ -49,6 +49,14 @@ body {
|
|||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--card-background);
|
background-color: var(--card-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.linkoverlay {
|
||||||
|
position:absolute;
|
||||||
|
left:0;
|
||||||
|
top:0;
|
||||||
|
bottom:0;
|
||||||
|
right:0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
@ -196,17 +204,27 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.media-left {
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
.media-content {
|
.media-content {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: inherit;
|
text-overflow: inherit;
|
||||||
}
|
}
|
||||||
|
.infolink {
|
||||||
|
font-family: "Font Awesome 5 Free";
|
||||||
|
position: absolute;
|
||||||
|
top: 0.5rem;
|
||||||
|
right: 0.5rem;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.tag {
|
.tag {
|
||||||
color: var(--highlight-secondary);
|
color: var(--highlight-secondary);
|
||||||
background-color: var(--highlight-secondary);
|
background-color: var(--highlight-secondary);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 1rem;
|
bottom: 1rem;
|
||||||
right: -0.2rem;
|
right: -0.2rem;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -11,23 +11,23 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "Darkmode",
|
name: "Darkmode",
|
||||||
data: function () {
|
props: {
|
||||||
return {
|
isDark: Boolean,
|
||||||
isDark: null,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
created: function () {
|
created: function () {
|
||||||
this.isDark =
|
let isDark =
|
||||||
"overrideDark" in localStorage
|
"overrideDark" in localStorage
|
||||||
? JSON.parse(localStorage.overrideDark)
|
? JSON.parse(localStorage.overrideDark)
|
||||||
: matchMedia("(prefers-color-scheme: dark)").matches;
|
: this.isDark === null
|
||||||
this.$emit("updated", this.isDark);
|
? matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
|
: this.isDark;
|
||||||
|
this.$emit("updated", isDark);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleTheme: function () {
|
toggleTheme: function () {
|
||||||
this.isDark = !this.isDark;
|
let isDark = !this.isDark;
|
||||||
localStorage.overrideDark = this.isDark;
|
localStorage.overrideDark = isDark;
|
||||||
this.$emit("updated", this.isDark);
|
this.$emit("updated", isDark);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
43
src/components/LayoutToggle.vue
Normal file
43
src/components/LayoutToggle.vue
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<a v-on:click="toggleLayout()" class="navbar-item is-inline-block-mobile">
|
||||||
|
<span>
|
||||||
|
<i :class="['fas', 'fa-fw', vlayout ? icon : secondaryIcon]"></i>
|
||||||
|
</span>
|
||||||
|
<slot></slot>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "LayoutToggle",
|
||||||
|
props: {
|
||||||
|
name: String,
|
||||||
|
icon: String,
|
||||||
|
iconAlt: String,
|
||||||
|
vlayout: Boolean,
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
secondaryIcon: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created: function () {
|
||||||
|
this.secondaryIcon = this.iconAlt || this.icon;
|
||||||
|
let vlayout;
|
||||||
|
if (this.name in localStorage) {
|
||||||
|
vlayout = JSON.parse(localStorage[this.name]);
|
||||||
|
} else {
|
||||||
|
vlayout = this.vlayout === null ? true : this.vlayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit("updated", vlayout);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleLayout: function () {
|
||||||
|
let vlayout = !this.vlayout;
|
||||||
|
localStorage[this.name] = vlayout;
|
||||||
|
this.$emit("updated", vlayout);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
@ -21,8 +21,8 @@
|
|||||||
<a
|
<a
|
||||||
class="navbar-item"
|
class="navbar-item"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
v-for="link in links"
|
v-for="(link, key) in links"
|
||||||
:key="link.url"
|
:key="key"
|
||||||
:href="link.url"
|
:href="link.url"
|
||||||
:target="link.target"
|
:target="link.target"
|
||||||
>
|
>
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a v-on:click="toggleSetting()" class="navbar-item is-inline-block-mobile">
|
|
||||||
<span><i :class="['fas', 'fa-fw', value ? icon : secondaryIcon]"></i></span>
|
|
||||||
<slot></slot>
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "SettingToggle",
|
|
||||||
props: {
|
|
||||||
name: String,
|
|
||||||
icon: String,
|
|
||||||
iconAlt: String,
|
|
||||||
},
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
secondaryIcon: null,
|
|
||||||
value: true,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
created: function () {
|
|
||||||
this.secondaryIcon = this.iconAlt || this.icon;
|
|
||||||
|
|
||||||
if (this.name in localStorage) {
|
|
||||||
this.value = JSON.parse(localStorage[this.name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$emit("updated", this.value);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggleSetting: function () {
|
|
||||||
this.value = !this.value;
|
|
||||||
localStorage[this.name] = this.value;
|
|
||||||
this.$emit("updated", this.value);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -2,7 +2,8 @@
|
|||||||
export default {};
|
export default {};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style> */
|
<style></style>
|
||||||
|
*/
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {};
|
export default {};
|
||||||
@ -13,29 +14,42 @@ export default {};
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="card" :class="item.class">
|
<div class="card" :class="item.class">
|
||||||
<a :href="item.url" :target="item.target" rel="noreferrer">
|
<a
|
||||||
<div class="card-content">
|
:href="item.url"
|
||||||
<div class="media">
|
class="linkoverlay"
|
||||||
<div v-if="item.logo" class="media-left">
|
:target="item.target"
|
||||||
<figure class="image is-48x48">
|
rel="noreferrer"
|
||||||
<img :src="item.logo" :alt="`${item.name} logo`" />
|
></a>
|
||||||
</figure>
|
<div class="card-content">
|
||||||
</div>
|
<div class="media">
|
||||||
<div v-if="item.icon" class="media-left">
|
<div v-if="item.logo" class="media-left">
|
||||||
<figure class="image is-48x48">
|
<figure class="image is-48x48">
|
||||||
<i style="font-size: 35px;" :class="['fa-fw', item.icon]"></i>
|
<img :src="item.logo" :alt="`${item.name} logo`" />
|
||||||
</figure>
|
</figure>
|
||||||
</div>
|
|
||||||
<div class="media-content">
|
|
||||||
<p class="title is-4">{{ item.name }}</p>
|
|
||||||
<p class="subtitle is-6">{{ item.subtitle }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="tag" :class="item.tagstyle" v-if="item.tag">
|
<div v-if="item.icon" class="media-left">
|
||||||
<strong class="tag-text">#{{ item.tag }}</strong>
|
<figure class="image is-48x48">
|
||||||
|
<i style="font-size: 35px;" :class="['fa-fw', item.icon]"></i>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
<div class="media-content">
|
||||||
|
<p class="title is-4">{{ item.name }}</p>
|
||||||
|
<p class="subtitle is-6">{{ item.subtitle }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
<a v-if="item.info"
|
||||||
|
:href="item.info"
|
||||||
|
:target="item.infotarget"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
<div class="infolink">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<div class="tag" :class="item.tagstyle" v-if="item.tag">
|
||||||
|
<strong class="tag-text">#{{ item.tag }}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user