aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/ldgallery.1.md6
-rw-r--r--compiler/src/Config.hs8
-rw-r--r--example/src/gallery.yaml4
-rw-r--r--viewer/src/@types/gallery.d.ts3
-rw-r--r--viewer/src/@types/tag.d.ts6
-rw-r--r--viewer/src/assets/scss/global.scss4
-rw-r--r--viewer/src/assets/scss/theme.scss4
-rw-r--r--viewer/src/components/LdProposition.vue52
-rw-r--r--viewer/src/components/LdTagInput.vue9
-rw-r--r--viewer/src/locales/en.json5
-rw-r--r--viewer/src/services/indexfactory.ts30
-rw-r--r--viewer/src/store/galleryStore.ts15
-rw-r--r--viewer/src/views/PanelLeft.vue24
13 files changed, 131 insertions, 39 deletions
diff --git a/compiler/ldgallery.1.md b/compiler/ldgallery.1.md
index 3c52f9d..4f9935b 100644
--- a/compiler/ldgallery.1.md
+++ b/compiler/ldgallery.1.md
@@ -107,7 +107,7 @@ description
107 107
108tags 108tags
109: List of tags for the item. 109: List of tags for the item.
110 Tag groups can be defined using prefixes separated by ":" (colon). 110 Tag categories can be defined using prefixes separated by ":" (colon).
111 Tags specified in a directory metadata sidecar are applied to all items within that directory. 111 Tags specified in a directory metadata sidecar are applied to all items within that directory.
112 112
113 113
@@ -139,6 +139,10 @@ excludedTags[]
139: Glob patterns of tags to exclude from the gallery. 139: Glob patterns of tags to exclude from the gallery.
140 Defaults to [] (none). 140 Defaults to [] (none).
141 141
142tagCategories[]
143: Top-level tag categories.
144 Defaults to [] (none).
145
142tagsFromDirectories.fromParents 146tagsFromDirectories.fromParents
143: Automatically generate tags from the name of parent directories, 147: Automatically generate tags from the name of parent directories,
144 looking up in the hierarchy as far as indicated by this parameter. 148 looking up in the hierarchy as far as indicated by this parameter.
diff --git a/compiler/src/Config.hs b/compiler/src/Config.hs
index 8796c3c..0ae0fa1 100644
--- a/compiler/src/Config.hs
+++ b/compiler/src/Config.hs
@@ -57,6 +57,7 @@ data GalleryConfig = GalleryConfig
57 , excludedFiles :: [String] 57 , excludedFiles :: [String]
58 , includedTags :: [String] 58 , includedTags :: [String]
59 , excludedTags :: [String] 59 , excludedTags :: [String]
60 , tagCategories :: [String]
60 , tagsFromDirectories :: TagsFromDirectoriesConfig 61 , tagsFromDirectories :: TagsFromDirectoriesConfig
61 , thumbnailMaxResolution :: Resolution 62 , thumbnailMaxResolution :: Resolution
62 , pictureMaxResolution :: Maybe Resolution 63 , pictureMaxResolution :: Maybe Resolution
@@ -71,6 +72,7 @@ instance FromJSON GalleryConfig where
71 <*> v .:? "excludedFiles" .!= [] 72 <*> v .:? "excludedFiles" .!= []
72 <*> v .:? "includedTags" .!= ["*"] 73 <*> v .:? "includedTags" .!= ["*"]
73 <*> v .:? "excludedTags" .!= [] 74 <*> v .:? "excludedTags" .!= []
75 <*> v .:? "tagCategories" .!= []
74 <*> v .:? "tagsFromDirectories" .!= (TagsFromDirectoriesConfig 0 "") 76 <*> v .:? "tagsFromDirectories" .!= (TagsFromDirectoriesConfig 0 "")
75 <*> v .:? "thumbnailMaxResolution" .!= (Resolution 400 300) 77 <*> v .:? "thumbnailMaxResolution" .!= (Resolution 400 300)
76 <*> v .:? "pictureMaxResolution" 78 <*> v .:? "pictureMaxResolution"
@@ -80,9 +82,9 @@ readConfig = decodeYamlFile
80 82
81 83
82data ViewerConfig = ViewerConfig 84data ViewerConfig = ViewerConfig
83 { -- TODO: add viewer config keys (tag groups...) 85 { galleryTitle :: String
84 galleryTitle :: String 86 , tagCategories :: [String]
85 } deriving (Generic, ToJSON, Show) 87 } deriving (Generic, ToJSON, Show)
86 88
87viewerConfig :: GalleryConfig -> ViewerConfig 89viewerConfig :: GalleryConfig -> ViewerConfig
88viewerConfig GalleryConfig{galleryTitle} = ViewerConfig galleryTitle 90viewerConfig GalleryConfig{galleryTitle, tagCategories} = ViewerConfig galleryTitle tagCategories
diff --git a/example/src/gallery.yaml b/example/src/gallery.yaml
index dba6b39..b569910 100644
--- a/example/src/gallery.yaml
+++ b/example/src/gallery.yaml
@@ -14,6 +14,10 @@ includedFiles:
14#includedTags: ["*"] 14#includedTags: ["*"]
15#excludedTags: [] 15#excludedTags: []
16 16
17tagCategories:
18 - photographer
19 - location
20
17#tagsFromDirectories: 21#tagsFromDirectories:
18# fromParents: 0 22# fromParents: 0
19# prefix: '' 23# prefix: ''
diff --git a/viewer/src/@types/gallery.d.ts b/viewer/src/@types/gallery.d.ts
index 4fa544f..de1c0dd 100644
--- a/viewer/src/@types/gallery.d.ts
+++ b/viewer/src/@types/gallery.d.ts
@@ -23,7 +23,8 @@ declare namespace Gallery {
23 } 23 }
24 24
25 interface GalleryProperties { 25 interface GalleryProperties {
26 galleryTitle: string 26 galleryTitle: string,
27 tagCategories: RawTag[]
27 } 28 }
28 interface Index { 29 interface Index {
29 properties: GalleryProperties, 30 properties: GalleryProperties,
diff --git a/viewer/src/@types/tag.d.ts b/viewer/src/@types/tag.d.ts
index a390c80..229c418 100644
--- a/viewer/src/@types/tag.d.ts
+++ b/viewer/src/@types/tag.d.ts
@@ -21,6 +21,7 @@ declare namespace Tag {
21 interface Node { 21 interface Node {
22 tag: Gallery.RawTag; 22 tag: Gallery.RawTag;
23 tagfiltered: Gallery.RawTag; 23 tagfiltered: Gallery.RawTag;
24 rootPart: boolean;
24 items: Gallery.Item[]; 25 items: Gallery.Item[];
25 children: Index; 26 children: Index;
26 } 27 }
@@ -31,4 +32,9 @@ declare namespace Tag {
31 } 32 }
32 type SearchByOperation = { [index: string]: Tag.Search[] }; 33 type SearchByOperation = { [index: string]: Tag.Search[] };
33 type Index = { [index: string]: Node }; 34 type Index = { [index: string]: Node };
35
36 interface Category {
37 tag: string;
38 index: Index;
39 }
34} 40}
diff --git a/viewer/src/assets/scss/global.scss b/viewer/src/assets/scss/global.scss
index bd7a7e7..9e61b8b 100644
--- a/viewer/src/assets/scss/global.scss
+++ b/viewer/src/assets/scss/global.scss
@@ -85,8 +85,8 @@ button svg + span {
85 overflow: auto; 85 overflow: auto;
86} 86}
87.scrollbar::-webkit-scrollbar { 87.scrollbar::-webkit-scrollbar {
88 width: 10px; 88 width: $scrollbar-width;
89 height: 10px; 89 height: $scrollbar-width;
90} 90}
91.scrollbar::-webkit-scrollbar-corner { 91.scrollbar::-webkit-scrollbar-corner {
92 background-color: transparent; 92 background-color: transparent;
diff --git a/viewer/src/assets/scss/theme.scss b/viewer/src/assets/scss/theme.scss
index 0028688..9e9cdc8 100644
--- a/viewer/src/assets/scss/theme.scss
+++ b/viewer/src/assets/scss/theme.scss
@@ -42,6 +42,8 @@ $radius: 0;
42$loading-background: $palette-800; 42$loading-background: $palette-800;
43$title-color: $palette-200; 43$title-color: $palette-200;
44$title-size: $size-5; 44$title-size: $size-5;
45$subtitle-color: $palette-200;
46$subtitle-size: $size-5;
45$tag-background-color: $palette-800; 47$tag-background-color: $palette-800;
46$button-color: $palette-100; 48$button-color: $palette-100;
47$button-active-color: $palette-100; 49$button-active-color: $palette-100;
@@ -62,11 +64,13 @@ $panel-left-txtcolor: $primary;
62$command-buttons-bgcolor: $palette-700; 64$command-buttons-bgcolor: $palette-700;
63$content-bgcolor: $palette-900; 65$content-bgcolor: $palette-900;
64$scrollbar-color: $palette-300; 66$scrollbar-color: $palette-300;
67$scrollbar-width: 10px;
65$loader-color: $palette-800; 68$loader-color: $palette-800;
66$input-tag-delete-background-color: $palette-700; 69$input-tag-delete-background-color: $palette-700;
67$breadcrumb-margins: 12px; 70$breadcrumb-margins: 12px;
68$breadcrumb-overflow-mask-size: $breadcrumb-margins + 60px; 71$breadcrumb-overflow-mask-size: $breadcrumb-margins + 60px;
69$thumbnail-other-size: $body-line-height * 9em; 72$thumbnail-other-size: $body-line-height * 9em;
73$proposed-category-bgcolor: $palette-700;
70 74
71// Layout 75// Layout
72 76
diff --git a/viewer/src/components/LdProposition.vue b/viewer/src/components/LdProposition.vue
index 3357777..c69a7c3 100644
--- a/viewer/src/components/LdProposition.vue
+++ b/viewer/src/components/LdProposition.vue
@@ -19,8 +19,9 @@
19--> 19-->
20 20
21<template> 21<template>
22 <div> 22 <div class="proposition">
23 <div v-for="proposed in proposedTags" :key="proposed.rawTag" class="proposition"> 23 <h2 v-if="showCategory && proposedTags.length" class="subtitle category">{{title}}</h2>
24 <div v-for="proposed in proposedTags" :key="proposed.rawTag">
24 <a 25 <a
25 class="operation-btns link" 26 class="operation-btns link"
26 :title="$t('tag-propositions.substraction')" 27 :title="$t('tag-propositions.substraction')"
@@ -54,6 +55,8 @@ import { Operation } from "@/@types/Operation";
54 55
55@Component 56@Component
56export default class LdProposition extends Vue { 57export default class LdProposition extends Vue {
58 @Prop() readonly category?: Tag.Node;
59 @Prop({ type: Boolean, required: true }) readonly showCategory!: boolean;
57 @Prop({ type: Array, required: true }) readonly currentTags!: string[]; 60 @Prop({ type: Array, required: true }) readonly currentTags!: string[];
58 @Prop({ required: true }) readonly tagsIndex!: Tag.Index; 61 @Prop({ required: true }) readonly tagsIndex!: Tag.Index;
59 @PropSync("searchFilters", { type: Array, required: true }) model!: Tag.Search[]; 62 @PropSync("searchFilters", { type: Array, required: true }) model!: Tag.Search[];
@@ -69,13 +72,14 @@ export default class LdProposition extends Vue {
69 this.extractDistinctItems(this.model) 72 this.extractDistinctItems(this.model)
70 .flatMap(item => item.tags) 73 .flatMap(item => item.tags)
71 .map(this.rightmost) 74 .map(this.rightmost)
72 .filter(rawTag => !this.model.find(search => search.tag === rawTag)) 75 .filter(rawTag => this.tagsIndex[rawTag] && !this.model.find(search => search.tag === rawTag))
73 .forEach(rawTag => (propositions[rawTag] = (propositions[rawTag] ?? 0) + 1)); 76 .forEach(rawTag => (propositions[rawTag] = (propositions[rawTag] ?? 0) + 1));
74 } else { 77 } else {
75 // Tags count from the current directory 78 // Tags count from the current directory
76 this.currentTags 79 this.currentTags
77 .flatMap(tag => tag.split(":")) 80 .flatMap(tag => tag.split(":"))
78 .map(tag => this.tagsIndex[tag]) 81 .map(tag => this.tagsIndex[tag])
82 .filter(Boolean)
79 .forEach(tagindex => (propositions[tagindex.tag] = tagindex.items.length)); 83 .forEach(tagindex => (propositions[tagindex.tag] = tagindex.items.length));
80 } 84 }
81 85
@@ -84,6 +88,10 @@ export default class LdProposition extends Vue {
84 .map(entry => ({ rawTag: entry[0], count: entry[1] })); 88 .map(entry => ({ rawTag: entry[0], count: entry[1] }));
85 }