diff options
-rw-r--r-- | viewer/.env | 2 | ||||
-rw-r--r-- | viewer/src/assets/scss/buefy.scss | 24 | ||||
-rw-r--r-- | viewer/src/assets/scss/global.scss | 11 | ||||
-rw-r--r-- | viewer/src/components/LdModeRadio.vue | 22 | ||||
-rw-r--r-- | viewer/src/locales/en.json | 8 | ||||
-rw-r--r-- | viewer/src/plugins/fontawesome.ts | 4 | ||||
-rw-r--r-- | viewer/src/store/galleryStore.ts | 21 | ||||
-rw-r--r-- | viewer/src/store/uiStore.ts | 19 | ||||
-rw-r--r-- | viewer/src/views/Gallery.vue | 31 | ||||
-rw-r--r-- | viewer/src/views/GalleryDirectory.vue | 5 | ||||
-rw-r--r-- | viewer/src/views/GalleryImage.vue | 2 | ||||
-rw-r--r-- | viewer/src/views/GallerySearch.vue | 25 | ||||
-rw-r--r-- | viewer/src/views/GalleryThumbnail.vue | 10 | ||||
-rw-r--r-- | viewer/src/views/MainLayout.vue | 2 | ||||
-rw-r--r-- | viewer/src/views/PanelLeft.vue | 9 | ||||
-rw-r--r-- | viewer/vue.config.js | 4 |
16 files changed, 148 insertions, 51 deletions
diff --git a/viewer/.env b/viewer/.env index f256c63..d06d633 100644 --- a/viewer/.env +++ b/viewer/.env | |||
@@ -1,2 +1,4 @@ | |||
1 | VUE_APP_I18N_LOCALE=en | 1 | VUE_APP_I18N_LOCALE=en |
2 | VUE_APP_I18N_FALLBACK_LOCALE=en | 2 | VUE_APP_I18N_FALLBACK_LOCALE=en |
3 | VUE_APP_DATA_URL=/gallery | ||
4 | VUE_APP_EXAMPLE_PROJECT=example | ||
diff --git a/viewer/src/assets/scss/buefy.scss b/viewer/src/assets/scss/buefy.scss index 5249899..b018fd3 100644 --- a/viewer/src/assets/scss/buefy.scss +++ b/viewer/src/assets/scss/buefy.scss | |||
@@ -5,28 +5,20 @@ | |||
5 | @import "buefy_variables"; | 5 | @import "buefy_variables"; |
6 | 6 | ||
7 | // 2. Setup your Custom Colors | 7 | // 2. Setup your Custom Colors |
8 | $linkedin: #0077b5; | 8 | // $linkedin: #0077b5; |
9 | $linkedin-invert: findColorInvert($linkedin); | 9 | // $linkedin-invert: findColorInvert($linkedin); |
10 | $twitter: #55acee; | ||
11 | $twitter-invert: findColorInvert($twitter); | ||
12 | $github: #333; | ||
13 | $github-invert: findColorInvert($github); | ||
14 | 10 | ||
15 | @import "~bulma/sass/utilities/derived-variables"; | 11 | @import "~bulma/sass/utilities/derived-variables"; |
16 | 12 | ||
17 | // 3. Add new color variables to the color map. | 13 | // 3. Add new color variables to the color map. |
18 | $addColors: ( | 14 | $addColors: ( |
19 | "twitter": ( | 15 | "green": ( |
20 | $twitter, | 16 | $green, |
21 | $twitter-invert | 17 | $green-invert |
22 | ), | 18 | ), |
23 | "linkedin": ( | 19 | "purple": ( |
24 | $linkedin, | 20 | $purple, |
25 | $linkedin-invert | 21 | $purple-invert |
26 | ), | ||
27 | "github": ( | ||
28 | $github, | ||
29 | $github-invert | ||
30 | ) | 22 | ) |
31 | ); | 23 | ); |
32 | $colors: map-merge($colors, $addColors); | 24 | $colors: map-merge($colors, $addColors); |
diff --git a/viewer/src/assets/scss/global.scss b/viewer/src/assets/scss/global.scss index 0bfeab9..5d12976 100644 --- a/viewer/src/assets/scss/global.scss +++ b/viewer/src/assets/scss/global.scss | |||
@@ -12,3 +12,14 @@ | |||
12 | .nowrap { | 12 | .nowrap { |
13 | white-space: nowrap; | 13 | white-space: nowrap; |
14 | } | 14 | } |
15 | |||
16 | .flex { | ||
17 | display: flex; | ||
18 | } | ||
19 | .flex-column { | ||
20 | display: flex; | ||
21 | flex-direction: column; | ||
22 | } | ||
23 | .flex-center { | ||
24 | align-items: center; | ||
25 | } | ||
diff --git a/viewer/src/components/LdModeRadio.vue b/viewer/src/components/LdModeRadio.vue new file mode 100644 index 0000000..614bf33 --- /dev/null +++ b/viewer/src/components/LdModeRadio.vue | |||
@@ -0,0 +1,22 @@ | |||
1 | <template> | ||
2 | <div class="flex"> | ||
3 | <b-radio-button v-model="$uiStore.mode" native-value="navigation" type="is-green"> | ||
4 | <fa-icon icon="folder" /> | ||
5 | <span>{{$t('mode.navigation')}}</span> | ||
6 | </b-radio-button> | ||
7 | <b-radio-button v-model="$uiStore.mode" native-value="search" type="is-purple"> | ||
8 | <fa-icon icon="search" /> | ||
9 | <span>{{$t('mode.search')}}</span> | ||
10 | </b-radio-button> | ||
11 | </div> | ||
12 | </template> | ||
13 | |||
14 | <script lang="ts"> | ||
15 | import { Component, Vue } from "vue-property-decorator"; | ||
16 | |||
17 | @Component | ||
18 | export default class LdModeRadio extends Vue {} | ||
19 | </script> | ||
20 | |||
21 | <style lang="scss"> | ||
22 | </style> | ||
diff --git a/viewer/src/locales/en.json b/viewer/src/locales/en.json index f24ac1f..d885872 100644 --- a/viewer/src/locales/en.json +++ b/viewer/src/locales/en.json | |||
@@ -1,5 +1,9 @@ | |||
1 | { | 1 | { |
2 | "tagInput.placeholder": "Tags", | 2 | "tagInput.placeholder": "Tags", |
3 | "panelLeft.title": "Filters", | 3 | "panelLeft.filters": "Filters", |
4 | "tagInput.nomatch": "No match" | 4 | "tagInput.nomatch": "No match", |
5 | "panelLeft.mode": "Mode", | ||
6 | "mode.navigation": "Navigation", | ||
7 | "mode.search": "Search", | ||
8 | "search.no-results": "No results" | ||
5 | } \ No newline at end of file | 9 | } \ No newline at end of file |
diff --git a/viewer/src/plugins/fontawesome.ts b/viewer/src/plugins/fontawesome.ts index 9bf4dba..3af77b6 100644 --- a/viewer/src/plugins/fontawesome.ts +++ b/viewer/src/plugins/fontawesome.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import Vue from "vue"; | 1 | import Vue from "vue"; |
2 | 2 | ||
3 | import { library } from "@fortawesome/fontawesome-svg-core"; | 3 | import { library } from "@fortawesome/fontawesome-svg-core"; |
4 | import { faExpandArrowsAlt } from "@fortawesome/free-solid-svg-icons"; | 4 | import { faExpandArrowsAlt, faFolder, faSearch } from "@fortawesome/free-solid-svg-icons"; |
5 | import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; | 5 | import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; |
6 | 6 | ||
7 | library.add(faExpandArrowsAlt); | 7 | library.add(faExpandArrowsAlt, faFolder, faSearch); |
8 | 8 | ||
9 | Vue.component("fa-icon", FontAwesomeIcon); | 9 | Vue.component("fa-icon", FontAwesomeIcon); |
diff --git a/viewer/src/store/galleryStore.ts b/viewer/src/store/galleryStore.ts index c875837..ca36a32 100644 --- a/viewer/src/store/galleryStore.ts +++ b/viewer/src/store/galleryStore.ts | |||
@@ -22,6 +22,7 @@ export default class GalleryStore extends VuexModule { | |||
22 | 22 | ||
23 | // --- | 23 | // --- |
24 | 24 | ||
25 | // Fetches the gallery's JSON metadata | ||
25 | @action async fetchGalleryItems(url: string) { | 26 | @action async fetchGalleryItems(url: string) { |
26 | fetch(url) | 27 | fetch(url) |
27 | .then(response => response.json()) | 28 | .then(response => response.json()) |
@@ -29,14 +30,18 @@ export default class GalleryStore extends VuexModule { | |||
29 | .then(this.indexTags); | 30 | .then(this.indexTags); |
30 | } | 31 | } |
31 | 32 | ||
33 | // Indexes the gallery | ||
32 | @action async indexTags() { | 34 | @action async indexTags() { |
33 | let index = {}; | 35 | let index = {}; |
34 | if (this.galleryItemsRoot) | 36 | if (this.galleryItemsRoot) |
35 | GalleryStore.pushTagsForItem(index, this.galleryItemsRoot); | 37 | GalleryStore.pushTagsForItem(index, this.galleryItemsRoot); |
36 | console.log(index); | 38 | console.log("Index: ", index); |
37 | this.setTags(index); | 39 | this.setTags(index); |
38 | } | 40 | } |
39 | 41 | ||
42 | // --- | ||
43 | |||
44 | // Pushes all tags for a root item (and its children) to the index | ||
40 | private static pushTagsForItem(index: Tag.Index, item: Gallery.Item) { | 45 | private static pushTagsForItem(index: Tag.Index, item: Gallery.Item) { |
41 | console.log("IndexingTagsFor: ", item.path); | 46 | console.log("IndexingTagsFor: ", item.path); |
42 | for (const tag of item.tags) { | 47 | for (const tag of item.tags) { |
@@ -44,7 +49,7 @@ export default class GalleryStore extends VuexModule { | |||
44 | let lastPart: string | null = null; | 49 | let lastPart: string | null = null; |
45 | for (const part of parts) { | 50 | for (const part of parts) { |
46 | if (!index[part]) index[part] = { tag: part, items: [], children: {} }; | 51 | if (!index[part]) index[part] = { tag: part, items: [], children: {} }; |
47 | index[part].items.push(item); | 52 | if (!index[part].items.includes(item)) index[part].items.push(item); |
48 | if (lastPart) index[lastPart].children[part] = index[part]; | 53 | if (lastPart) index[lastPart].children[part] = index[part]; |
49 | lastPart = part; | 54 | lastPart = part; |
50 | } | 55 | } |
@@ -52,4 +57,16 @@ export default class GalleryStore extends VuexModule { | |||
52 | if (item.properties.type === "directory") | 57 | if (item.properties.type === "directory") |
53 | item.properties.items.forEach(item => this.pushTagsForItem(index, item)); | 58 | item.properties.items.forEach(item => this.pushTagsForItem(index, item)); |
54 | } | 59 | } |
60 | |||
61 | // Searches for an item by path from a root item (navigation) | ||
62 | static searchCurrentItem(item: Gallery.Item, path: string): Gallery.Item | null { | ||
63 | if (path === item.path) return item; | ||
64 | if (item.properties.type === "directory" && path.startsWith(item.path)) { | ||
65 | const itemFound = item.properties.items | ||
66 | .map(item => this.searchCurrentItem(item, path)) | ||
67 | .find(item => Boolean(item)); | ||
68 | return itemFound || null; | ||
69 | } | ||
70 | return null; | ||
71 | } | ||
55 | } \ No newline at end of file | 72 | } \ No newline at end of file |
diff --git a/viewer/src/store/uiStore.ts b/viewer/src/store/uiStore.ts index e04b507..4a6f487 100644 --- a/viewer/src/store/uiStore.ts +++ b/viewer/src/store/uiStore.ts | |||
@@ -8,11 +8,30 @@ const VuexModule = createModule({ | |||
8 | export default class UIStore extends VuexModule { | 8 | export default class UIStore extends VuexModule { |
9 | 9 | ||
10 | fullscreen: boolean = false; | 10 | fullscreen: boolean = false; |
11 | mode: "navigation" | "search" = "navigation"; | ||
11 | currentTags: Tag.Node[] = []; | 12 | currentTags: Tag.Node[] = []; |
12 | 13 | ||
13 | // --- | 14 | // --- |
14 | 15 | ||
16 | get isModeSearch() { | ||
17 | return this.mode === "search"; | ||
18 | } | ||
19 | |||
20 | get isModeNavigation() { | ||
21 | return this.mode === "navigation"; | ||
22 | } | ||
23 | |||
24 | // --- | ||