diff options
-rw-r--r-- | compiler/ldgallery.1.md | 6 | ||||
-rw-r--r-- | compiler/src/Config.hs | 8 | ||||
-rw-r--r-- | example/src/gallery.yaml | 4 | ||||
-rw-r--r-- | viewer/src/@types/gallery.d.ts | 3 | ||||
-rw-r--r-- | viewer/src/@types/tag.d.ts | 6 | ||||
-rw-r--r-- | viewer/src/assets/scss/global.scss | 4 | ||||
-rw-r--r-- | viewer/src/assets/scss/theme.scss | 4 | ||||
-rw-r--r-- | viewer/src/components/LdProposition.vue | 52 | ||||
-rw-r--r-- | viewer/src/components/LdTagInput.vue | 9 | ||||
-rw-r--r-- | viewer/src/locales/en.json | 5 | ||||
-rw-r--r-- | viewer/src/services/indexfactory.ts | 30 | ||||
-rw-r--r-- | viewer/src/store/galleryStore.ts | 15 | ||||
-rw-r--r-- | viewer/src/views/PanelLeft.vue | 24 |
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 | ||
108 | tags | 108 | tags |
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 | ||
142 | tagCategories[] | ||
143 | : Top-level tag categories. | ||
144 | Defaults to [] (none). | ||
145 | |||
142 | tagsFromDirectories.fromParents | 146 | tagsFromDirectories.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 | ||
82 | data ViewerConfig = ViewerConfig | 84 | data 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 | ||
87 | viewerConfig :: GalleryConfig -> ViewerConfig | 89 | viewerConfig :: GalleryConfig -> ViewerConfig |
88 | viewerConfig GalleryConfig{galleryTitle} = ViewerConfig galleryTitle | 90 | viewerConfig 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 | ||
17 | tagCategories: | ||
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 26cb355..feb8543 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; |
@@ -61,11 +63,13 @@ $panel-left-txtcolor: $primary; | |||
61 | $command-buttons-bgcolor: $palette-700; | 63 | $command-buttons-bgcolor: $palette-700; |
62 | $content-bgcolor: $palette-900; | 64 | $content-bgcolor: $palette-900; |
63 | $scrollbar-color: $palette-300; | 65 | $scrollbar-color: $palette-300; |
66 | $scrollbar-width: 10px; | ||
64 | $loader-color: $palette-800; | 67 | $loader-color: $palette-800; |
65 | $input-tag-delete-background-color: $palette-700; | 68 | $input-tag-delete-background-color: $palette-700; |
66 | $breadcrumb-margins: 12px; | 69 | $breadcrumb-margins: 12px; |
67 | $breadcrumb-overflow-mask-size: $breadcrumb-margins + 60px; | 70 | $breadcrumb-overflow-mask-size: $breadcrumb-margins + 60px; |
68 | $thumbnail-other-size: 120px; | 71 | $thumbnail-other-size: 120px; |
72 | $proposed-category-bgcolor: $palette-700; | ||
69 | 73 | ||
70 | // Layout | 74 | // Layout |
71 | 75 | ||
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 |
56 | export default class LdProposition extends Vue { | 57 | export 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 | } |