Skip to content

Commit 2ca4faa

Browse files
committed
Extendable base service for easier development.
1 parent c7dc6bf commit 2ca4faa

File tree

6 files changed

+104
-99
lines changed

6 files changed

+104
-99
lines changed

CONTRIBUTING.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ UX and usability. If you are looking for a full featured dashboard, there is ton
1212
- Configuration is stored in a simple config file, avoiding the need for a backend/database while making possible to use versioning or [config template](https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html).
1313
- Only modern browsers are supported, feel free to use any JS features without any polyfill as soon as the latest version of the major browsers supports them.
1414

15-
### Roadmap
16-
17-
If you want to know more about the project direction or looking for something to work on, checkout the [roadmap](https://github.com/bastienwirtz/homer#Roadmap)!
18-
Feel free to open an issue if you have any question.
1915

2016
# Ground Rules
2117

@@ -40,8 +36,9 @@ feel free to open an issue to present your idea.
4036
### How to submit a contribution
4137

4238
The general process to submit a contribution is as follow:
43-
1. Create your own fork of the code
44-
2. Do the changes in your fork
45-
3. Make sure to fill the [pull request description](https://github.com/bastienwirtz/homer/blob/main/.github/PULL_REQUEST_TEMPLATE.md) properly.
39+
1. Take a look to the [development guideline](https://github.com/bastienwirtz/homer/blob/main/docs/development.md).
40+
2. Create your own fork of the code
41+
3. Do the changes in your fork
42+
4. Make sure to fill the [pull request description](https://github.com/bastienwirtz/homer/blob/main/.github/PULL_REQUEST_TEMPLATE.md) properly.
4643

4744
### Happy coding :metal:

docs/development.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Development
22

3+
If you want to contribute to Homer, please read the [contributing guidelines](https://github.com/bastienwirtz/homer/blob/main/CONTRIBUTING.md) first.
4+
35
```sh
46
# Using yarn (recommended)
57
yarn install
@@ -10,6 +12,49 @@ npm install
1012
npm run serve
1113
```
1214

15+
## Custom services
16+
17+
Custom services are small VueJs component (see `src/components/services/`) that add little features to a classic, "static", dashboard item. It should be very simple.
18+
A dashboard can contain a lot of items, so performance is very important.
19+
20+
The [`Generic`](https://github.com/bastienwirtz/homer/blob/main/src/components/services/Generic.vue) service provides a typical card layout which
21+
you can extend to add specific features. Unless you want a completely different design, extended the generic service is the recommended way. It gives you 3 [slots](https://vuejs.org/v2/guide/components-slots.html#Named-Slots) to extend: `icon`, `content` and `indicator`.
22+
Each one is **optional**, and will display the usual information if omitted.
23+
24+
Each service must implement the `item` [property](https://vuejs.org/v2/guide/components-props.html) and bind it the Generic component if used.
25+
26+
### Skeleton
27+
```Vue
28+
<template>
29+
<Generic :item="item">
30+
<template #icon>
31+
<!-- left area containing the icon -->
32+
</template>
33+
<template #content>
34+
<!-- main area containing the title, subtitle, ... -->
35+
</template>
36+
<template #indicator>
37+
<!-- top right area, empty by default -->
38+
</template>
39+
</Generic>
40+
</template>
41+
42+
<script>
43+
import Generic from "./Generic.vue";
44+
45+
export default {
46+
name: "MyNewService",
47+
props: {
48+
item: Object,
49+
},
50+
components: {
51+
Generic,
52+
}
53+
};
54+
</script>
55+
```
56+
57+
1358
## Themes
1459

1560
Themes are meant to be simple customization (written in [scss](https://sass-lang.com/documentation/syntax)).

src/components/Service.vue

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,13 @@ import Generic from "./services/Generic.vue";
77
88
export default {
99
name: "Service",
10-
components: {
11-
Generic,
12-
},
1310
props: {
1411
item: Object,
1512
},
1613
computed: {
1714
component() {
1815
const type = this.item.type || "Generic";
19-
if (type == "Generic") {
16+
if (type === "Generic") {
2017
return Generic;
2118
}
2219
return () => import(`./services/${type}.vue`);

src/components/services/AdGuardHome.vue

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,35 @@
11
<template>
2-
<div>
3-
<div class="card" :class="item.class">
4-
<a :href="item.url" :target="item.target" rel="noreferrer">
5-
<div class="card-content">
6-
<div class="media">
7-
<div v-if="item.logo" class="media-left">
8-
<figure class="image is-48x48">
9-
<img :src="item.logo" :alt="`${item.name} logo`" />
10-
</figure>
11-
</div>
12-
<div v-if="item.icon" class="media-left">
13-
<figure class="image is-48x48">
14-
<i style="font-size: 35px" :class="['fa-fw', item.icon]"></i>
15-
</figure>
16-
</div>
17-
<div class="media-content">
18-
<p class="title is-4">{{ item.name }}</p>
19-
<p class="subtitle is-6">
20-
<template v-if="item.subtitle">
21-
{{ item.subtitle }}
22-
</template>
23-
<template v-else-if="stats">
24-
{{ percentage }}&percnt; blocked
25-
</template>
26-
</p>
27-
</div>
28-
<div class="status" :class="protection">
29-
{{ protection }}
30-
</div>
31-
</div>
32-
<div class="tag" :class="item.tagstyle" v-if="item.tag">
33-
<strong class="tag-text">#{{ item.tag }}</strong>
34-
</div>
35-
</div>
36-
</a>
37-
</div>
38-
</div>
2+
<Generic :item="item">
3+
<template #content>
4+
<p class="title is-4">{{ item.name }}</p>
5+
<p class="subtitle is-6">
6+
<template v-if="item.subtitle">
7+
{{ item.subtitle }}
8+
</template>
9+
<template v-else-if="stats">
10+
{{ percentage }}&percnt; blocked
11+
</template>
12+
</p>
13+
</template>
14+
<template #indicator>
15+
<div class="status" :class="protection">
16+
{{ protection }}
17+
</div>
18+
</template>
19+
</Generic>
3920
</template>
4021

4122
<script>
23+
import Generic from "./Generic.vue";
24+
4225
export default {
4326
name: "AdGuardHome",
4427
props: {
4528
item: Object,
4629
},
30+
components: {
31+
Generic,
32+
},
4733
data: () => {
4834
return {
4935
status: null,

src/components/services/Generic.vue

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@
88
<a :href="item.url" :target="item.target" rel="noreferrer">
99
<div class="card-content">
1010
<div :class="mediaClass">
11-
<div v-if="item.logo" class="media-left">
12-
<figure class="image is-48x48">
13-
<img :src="item.logo" :alt="`${item.name} logo`" />
14-
</figure>
15-
</div>
16-
<div v-if="item.icon" class="media-left">
17-
<figure class="image is-48x48">
18-
<i style="font-size: 35px" :class="['fa-fw', item.icon]"></i>
19-
</figure>
20-
</div>
11+
<slot name="icon">
12+
<div v-if="item.logo" class="media-left">
13+
<figure class="image is-48x48">
14+
<img :src="item.logo" :alt="`${item.name} logo`" />
15+
</figure>
16+
</div>
17+
<div v-if="item.icon" class="media-left">
18+
<figure class="image is-48x48">
19+
<i style="font-size: 35px" :class="['fa-fw', item.icon]"></i>
20+
</figure>
21+
</div>
22+
</slot>
2123
<div class="media-content">
22-
<p class="title is-4">{{ item.name }}</p>
23-
<p class="subtitle is-6" v-if="item.subtitle">
24-
{{ item.subtitle }}
25-
</p>
24+
<slot name="content">
25+
<p class="title is-4">{{ item.name }}</p>
26+
<p class="subtitle is-6" v-if="item.subtitle">
27+
{{ item.subtitle }}
28+
</p>
29+
</slot>
2630
</div>
31+
<slot name="indicator" class="indicator"></slot>
2732
</div>
2833
<div class="tag" :class="item.tagstyle" v-if="item.tag">
2934
<strong class="tag-text">#{{ item.tag }}</strong>

src/components/services/Ping.vue

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,24 @@
11
<template>
2-
<div>
3-
<div class="card" :class="item.class">
4-
<a :href="item.url" :target="item.target" rel="noreferrer">
5-
<div class="card-content">
6-
<div class="media">
7-
<div v-if="item.logo" class="media-left">
8-
<figure class="image is-48x48">
9-
<img :src="item.logo" :alt="`${item.name} logo`" />
10-
</figure>
11-
</div>
12-
<div v-if="item.icon" class="media-left">
13-
<figure class="image is-48x48">
14-
<i style="font-size: 35px" :class="['fa-fw', item.icon]"></i>
15-
</figure>
16-
</div>
17-
<div class="media-content">
18-
<p class="title is-4">{{ item.name }}</p>
19-
<p class="subtitle is-6">
20-
<template v-if="item.subtitle">
21-
{{ item.subtitle }}
22-
</template>
23-
</p>
24-
</div>
25-
<div v-if="status" class="status" :class="status">
26-
{{ status }}
27-
</div>
28-
</div>
29-
<div class="tag" :class="item.tagstyle" v-if="item.tag">
30-
<strong class="tag-text">#{{ item.tag }}</strong>
31-
</div>
32-
</div>
33-
</a>
34-
</div>
35-
</div>
2+
<Generic :item="item">
3+
<template #indicator>
4+
<div v-if="status" class="status" :class="status">
5+
{{ status }}
6+
</div>
7+
</template>
8+
</Generic>
369
</template>
3710

3811
<script>
12+
import Generic from "./Generic.vue";
13+
3914
export default {
4015
name: "Ping",
4116
props: {
4217
item: Object,
4318
},
19+
components: {
20+
Generic,
21+
},
4422
data: () => ({
4523
status: null,
4624
}),
@@ -70,9 +48,6 @@ export default {
7048
</script>
7149

7250
<style scoped lang="scss">
73-
.media-left img {
74-
max-height: 100%;
75-
}
7651
.status {
7752
font-size: 0.8rem;
7853
color: var(--text-title);

0 commit comments

Comments
 (0)