]> git.immae.eu Git - github/bastienwirtz/homer.git/commitdiff
Extendable base service for easier development.
authorBastien Wirtz <bastien.wirtz@gmail.com>
Wed, 6 Oct 2021 20:55:09 +0000 (22:55 +0200)
committerBastien Wirtz <bastien.wirtz@gmail.com>
Wed, 6 Oct 2021 20:55:09 +0000 (22:55 +0200)
CONTRIBUTING.md
docs/development.md
src/components/Service.vue
src/components/services/AdGuardHome.vue
src/components/services/Generic.vue
src/components/services/Ping.vue

index f29b7d83a537538606c21aea29e2608b33404ef9..de893b6c7e512649b13ef44e1613e76e4b8f0059 100644 (file)
@@ -12,10 +12,6 @@ UX and usability. If you are looking for a full featured dashboard, there is ton
 - 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).
 - 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.
 
-### Roadmap
-
-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)!
-Feel free to open an issue if you have any question.
 
 # Ground Rules
 
@@ -40,8 +36,9 @@ feel free to open an issue to present your idea.
 ### How to submit a contribution
 
 The general process to submit a contribution is as follow:
-1. Create your own fork of the code
-2. Do the changes in your fork
-3. Make sure to fill the [pull request description](https://github.com/bastienwirtz/homer/blob/main/.github/PULL_REQUEST_TEMPLATE.md) properly.
+1. Take a look to the [development guideline](https://github.com/bastienwirtz/homer/blob/main/docs/development.md).
+2. Create your own fork of the code
+3. Do the changes in your fork
+4. Make sure to fill the [pull request description](https://github.com/bastienwirtz/homer/blob/main/.github/PULL_REQUEST_TEMPLATE.md) properly.
 
 ### Happy coding :metal:
index 5e432f1deef86cd21d9e64da3037f5b89440e781..a22ae0b2b6b648a25a5dd8a08ff2ed327d025c04 100644 (file)
@@ -1,5 +1,7 @@
 # Development
 
+If you want to contribute to Homer, please read the [contributing guidelines](https://github.com/bastienwirtz/homer/blob/main/CONTRIBUTING.md) first. 
+
 ```sh
 # Using yarn (recommended)
 yarn install
@@ -10,6 +12,49 @@ npm install
 npm run serve
 ```
 
+## Custom services
+
+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.
+A dashboard can contain a lot of items, so performance is very important. 
+
+The [`Generic`](https://github.com/bastienwirtz/homer/blob/main/src/components/services/Generic.vue) service provides a typical card layout which
+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`. 
+Each one is **optional**, and will display the usual information if omitted.
+
+Each service must implement the `item` [property](https://vuejs.org/v2/guide/components-props.html) and bind it the Generic component if used.
+
+### Skeleton
+```Vue
+<template>
+  <Generic :item="item">
+    <template #icon>
+      <!-- left area containing the icon -->
+    </template>
+    <template #content>
+      <!-- main area containing the title, subtitle, ... -->
+    </template>
+    <template #indicator>
+      <!-- top right area, empty by default -->
+    </template>
+  </Generic>
+</template>
+
+<script>
+import Generic from "./Generic.vue";
+
+export default {
+  name: "MyNewService",
+  props: {
+    item: Object,
+  },
+  components: {
+    Generic,
+  }
+};
+</script>
+```
+
+
 ## Themes
 
 Themes are meant to be simple customization (written in [scss](https://sass-lang.com/documentation/syntax)).
index 868675957a201d59f24578e666cf2ecccf354469..39a9ac41e0df81855e4970f012d775eb2b09a398 100644 (file)
@@ -7,16 +7,13 @@ import Generic from "./services/Generic.vue";
 
 export default {
   name: "Service",
-  components: {
-    Generic,
-  },
   props: {
     item: Object,
   },
   computed: {
     component() {
       const type = this.item.type || "Generic";
-      if (type == "Generic") {
+      if (type === "Generic") {
         return Generic;
       }
       return () => import(`./services/${type}.vue`);
index 61d4bed916d999a59f8bf283b1695e971e689d0f..16881fa59ea6d93ceb43bd4573e785fb1107cce1 100644 (file)
@@ -1,49 +1,35 @@
 <template>
-  <div>
-    <div class="card" :class="item.class">
-      <a :href="item.url" :target="item.target" rel="noreferrer">
-        <div class="card-content">
-          <div class="media">
-            <div v-if="item.logo" class="media-left">
-              <figure class="image is-48x48">
-                <img :src="item.logo" :alt="`${item.name} logo`" />
-              </figure>
-            </div>
-            <div v-if="item.icon" class="media-left">
-              <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">
-                <template v-if="item.subtitle">
-                  {{ item.subtitle }}
-                </template>
-                <template v-else-if="stats">
-                  {{ percentage }}&percnt; blocked
-                </template>
-              </p>
-            </div>
-            <div class="status" :class="protection">
-              {{ protection }}
-            </div>
-          </div>
-          <div class="tag" :class="item.tagstyle" v-if="item.tag">
-            <strong class="tag-text">#{{ item.tag }}</strong>
-          </div>
-        </div>
-      </a>
-    </div>
-  </div>
+  <Generic :item="item">
+    <template #content>
+      <p class="title is-4">{{ item.name }}</p>
+      <p class="subtitle is-6">
+        <template v-if="item.subtitle">
+          {{ item.subtitle }}
+        </template>
+        <template v-else-if="stats">
+          {{ percentage }}&percnt; blocked
+        </template>
+      </p>
+    </template>
+    <template #indicator>
+      <div class="status" :class="protection">
+        {{ protection }}
+      </div>
+    </template>
+  </Generic>
 </template>
 
 <script>
+import Generic from "./Generic.vue";
+
 export default {
   name: "AdGuardHome",
   props: {
     item: Object,
   },
+  components: {
+    Generic,
+  },
   data: () => {
     return {
       status: null,
index 08bd3f6bf0ab3db2f1851bcfaaf949763f49387b..af65a8c6ad8580f496906b53891e47035b58afca 100644 (file)
@@ -8,22 +8,27 @@
       <a :href="item.url" :target="item.target" rel="noreferrer">
         <div class="card-content">
           <div :class="mediaClass">
-            <div v-if="item.logo" class="media-left">
-              <figure class="image is-48x48">
-                <img :src="item.logo" :alt="`${item.name} logo`" />
-              </figure>
-            </div>
-            <div v-if="item.icon" class="media-left">
-              <figure class="image is-48x48">
-                <i style="font-size: 35px" :class="['fa-fw', item.icon]"></i>
-              </figure>
-            </div>
+            <slot name="icon">
+              <div v-if="item.logo" class="media-left">
+                <figure class="image is-48x48">
+                  <img :src="item.logo" :alt="`${item.name} logo`" />
+                </figure>
+              </div>
+              <div v-if="item.icon" class="media-left">
+                <figure class="image is-48x48">
+                  <i style="font-size: 35px" :class="['fa-fw', item.icon]"></i>
+                </figure>
+              </div>
+            </slot>
             <div class="media-content">
-              <p class="title is-4">{{ item.name }}</p>
-              <p class="subtitle is-6" v-if="item.subtitle">
-                {{ item.subtitle }}
-              </p>
+              <slot name="content">
+                <p class="title is-4">{{ item.name }}</p>
+                <p class="subtitle is-6" v-if="item.subtitle">
+                  {{ item.subtitle }}
+                </p>
+              </slot>
             </div>
+            <slot name="indicator" class="indicator"></slot>
           </div>
           <div class="tag" :class="item.tagstyle" v-if="item.tag">
             <strong class="tag-text">#{{ item.tag }}</strong>
index e693af4cc210eb66ca530a1f9f2fa502bd3a0e1d..6fd3ec57f987e34719e7b169f5adaa16ab604303 100644 (file)
@@ -1,46 +1,24 @@
 <template>
-  <div>
-    <div class="card" :class="item.class">
-      <a :href="item.url" :target="item.target" rel="noreferrer">
-        <div class="card-content">
-          <div class="media">
-            <div v-if="item.logo" class="media-left">
-              <figure class="image is-48x48">
-                <img :src="item.logo" :alt="`${item.name} logo`" />
-              </figure>
-            </div>
-            <div v-if="item.icon" class="media-left">
-              <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">
-                <template v-if="item.subtitle">
-                  {{ item.subtitle }}
-                </template>
-              </p>
-            </div>
-            <div v-if="status" class="status" :class="status">
-              {{ status }}
-            </div>
-          </div>
-          <div class="tag" :class="item.tagstyle" v-if="item.tag">
-            <strong class="tag-text">#{{ item.tag }}</strong>
-          </div>
-        </div>
-      </a>
-    </div>
-  </div>
+  <Generic :item="item">
+    <template #indicator>
+      <div v-if="status" class="status" :class="status">
+        {{ status }}
+      </div>
+    </template>
+  </Generic>
 </template>
 
 <script>
+import Generic from "./Generic.vue";
+
 export default {
   name: "Ping",
   props: {
     item: Object,
   },
+  components: {
+    Generic,
+  },
   data: () => ({
     status: null,
   }),
@@ -70,9 +48,6 @@ export default {
 </script>
 
 <style scoped lang="scss">
-.media-left img {
-  max-height: 100%;
-}
 .status {
   font-size: 0.8rem;
   color: var(--text-title);