Skip to content

Commit 6e1b24c

Browse files
committed
Add UI for copying browse location URLs
Closes #1253
1 parent a1f5a6f commit 6e1b24c

File tree

7 files changed

+80
-38
lines changed

7 files changed

+80
-38
lines changed

Tekst-Web/i18n/ui/deDE.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,10 @@ routes:
200200
browse:
201201
location:
202202
goTo: Gehe zu Belegstelle
203-
aliasesTip: Suchen Sie nach diesem Belegstellen-Alias in der Schnellsuche, um direkt zu dieser Belegstelle zu gelangen.
203+
aliasesTip: |
204+
Klicken Sie hier, um eine URL zur aktuellen Belegstelle mit diesem Belegstellen-Alias
205+
zu kopieren. Tipp: Suchen Sie nach diesem Belegstellen-Alias in der Schnellsuche,
206+
um direkt zu dieser Belegstelle zu gelangen.
204207
msgNoNearest: Es gibt keine weiteren Belegstellen mit Inhalten dieser Ressource in dieser Richtung.
205208
toolbar:
206209
tipSelectLocation: Belegstelle auswählen

Tekst-Web/i18n/ui/enUS.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,9 @@ routes:
197197
browse:
198198
location:
199199
goTo: Go to location
200-
aliasesTip: Search for this location alias in the Quick Search to directly jump to this location.
200+
aliasesTip: |
201+
Click here to copy a URL to the current location using this location alias.
202+
Hint: Search for this location alias in the Quick Search to directly jump to this location.
201203
msgNoNearest: There are no more locations holding contents of this resource in this direction.
202204
toolbar:
203205
tipSelectLocation: Select location
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<script setup lang="ts">
2+
import CopyToClipboardButton from '@/components/generic/CopyToClipboardButton.vue';
3+
import env from '@/env';
4+
import { NFlex } from 'naive-ui';
5+
6+
defineProps<{
7+
textSlug: string;
8+
aliases?: string[];
9+
}>();
10+
11+
const baseUrl = `${origin}/${env.WEB_PATH_STRIPPED}`.replace(/\/+$/, '');
12+
</script>
13+
14+
<template>
15+
<n-flex align="center" class="my-lg">
16+
<copy-to-clipboard-button
17+
v-for="alias in aliases"
18+
:key="alias"
19+
tertiary
20+
size="tiny"
21+
:text="`${baseUrl}/bookmark/${textSlug}/${alias}`"
22+
:title="$t('browse.location.aliasesTip')"
23+
show-msg
24+
>
25+
{{ alias }}
26+
</copy-to-clipboard-button>
27+
</n-flex>
28+
</template>
29+
30+
<style scoped>
31+
.loc-alias-tag {
32+
cursor: pointer;
33+
}
34+
35+
.loc-alias-tag:hover {
36+
background-color: var(--main-bg-color);
37+
}
38+
</style>

Tekst-Web/src/components/content/LocationMetadataContentTags.vue

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { LocationMetadataContentRead, LocationMetadataResourceRead } from '
33
import ResourceInfoWidget from '@/components/resource/ResourceInfoWidget.vue';
44
import { useResourcesStore, useStateStore } from '@/stores';
55
import { groupAndSortItems, pickTranslation } from '@/utils';
6-
import { NTag } from 'naive-ui';
6+
import { NFlex, NTag } from 'naive-ui';
77
import { computed } from 'vue';
88
99
const props = defineProps<{
@@ -73,20 +73,22 @@ const contentsProcessed = computed(() => {
7373
</script>
7474

7575
<template>
76-
<template v-for="content in contentsProcessed" :key="content.id">
77-
<template v-for="group in content.groups" :key="group.group">
78-
<resource-info-widget
79-
v-for="(item, index) in group.items"
80-
:key="`${item.key || 'no_key'}_${index}`"
81-
:resource="content.res"
82-
>
83-
<n-tag size="small" :color="tagColor" :title="item.title" class="loc-meta-tag">
84-
<span v-if="item.key">{{ item.key }}: </span>
85-
<span :style="{ 'font-family': content.font }">{{ item.value }}</span>
86-
</n-tag>
87-
</resource-info-widget>
76+
<n-flex align="center" class="my-lg">
77+
<template v-for="content in contentsProcessed" :key="content.id">
78+
<template v-for="group in content.groups" :key="group.group">
79+
<resource-info-widget
80+
v-for="(item, index) in group.items"
81+
:key="`${item.key || 'no_key'}_${index}`"
82+
:resource="content.res"
83+
>
84+
<n-tag size="small" :color="tagColor" :title="item.title" class="loc-meta-tag">
85+
<span v-if="item.key">{{ item.key }}: </span>
86+
<span :style="{ 'font-family': content.font }">{{ item.value }}</span>
87+
</n-tag>
88+
</resource-info-widget>
89+
</template>
8890
</template>
89-
</template>
91+
</n-flex>
9092
</template>
9193

9294
<style scoped>

Tekst-Web/src/components/generic/CopyToClipboardButton.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup lang="ts">
2+
import { useMessages } from '@/composables/messages';
23
import { $t } from '@/i18n';
34
import { CopyIcon } from '@/icons';
45
import { useClipboard } from '@vueuse/core';
@@ -11,19 +12,25 @@ const props = withDefaults(
1112
text?: string | (() => string);
1213
copiedDuring?: number;
1314
title?: string;
15+
showMsg?: boolean;
1416
}>(),
1517
{
1618
copiedDuring: 1000,
1719
}
1820
);
1921
22+
const { message } = useMessages();
23+
2024
const attrs: Record<string, unknown> = useAttrs();
2125
const { copy, copied, isSupported } = useClipboard({ copiedDuring: 1000 });
2226
2327
function copyToClipboard() {
2428
if (!props.text) return;
2529
const txt = typeof props.text === 'function' ? props.text() : props.text;
2630
copy(txt);
31+
if (props.showMsg) {
32+
message.success($t('common.copiedMsg', { text: txt }));
33+
}
2734
}
2835
</script>
2936

Tekst-Web/src/env.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
class Environment {
22
WEB_PATH: string;
3+
WEB_PATH_STRIPPED: string;
34
STATIC_PATH: string;
45
TEKST_API_PATH: string;
56

67
constructor() {
78
const baseHref = document.querySelector('base')?.href;
89
this.WEB_PATH = baseHref ? new URL(baseHref).pathname : import.meta.env.BASE_URL || '/';
9-
const webPathStripped = this.WEB_PATH.replace(/\/+$/, '');
10-
this.STATIC_PATH = webPathStripped + '/static';
10+
this.WEB_PATH_STRIPPED = this.WEB_PATH.replace(/\/+$/, '');
11+
this.STATIC_PATH = this.WEB_PATH_STRIPPED + '/static';
1112
// construct API path: If the API path is set via an env var, it's assumed to
1213
// contain the COMPLETE path to the API (including the web path
1314
// or any other path prefix).
1415
// If not, we assume that we're running the official container image and
1516
// the API is located under the web path.
16-
this.TEKST_API_PATH = import.meta.env.TEKST_API_PATH || webPathStripped + '/api';
17+
this.TEKST_API_PATH = import.meta.env.TEKST_API_PATH || this.WEB_PATH_STRIPPED + '/api';
1718
}
1819
}
1920

Tekst-Web/src/views/BrowseView.vue

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import HelpButtonWidget from '@/components/HelpButtonWidget.vue';
44
import LocationLabel from '@/components/LocationLabel.vue';
55
import BrowseToolbar from '@/components/browse/BrowseToolbar.vue';
66
import ContentContainer from '@/components/browse/ContentContainer.vue';
7+
import LocationAliasesWidget from '@/components/browse/LocationAliasesWidget.vue';
78
import ResourceToggleDrawer from '@/components/browse/ResourceToggleDrawer.vue';
89
import LocationMetadataContentTags from '@/components/content/LocationMetadataContentTags.vue';
910
import IconHeading from '@/components/generic/IconHeading.vue';
1011
import { $t } from '@/i18n';
1112
import { BookIcon, ErrorIcon, HourglassIcon, NoContentIcon } from '@/icons';
1213
import { useAuthStore, useBrowseStore, useResourcesStore, useStateStore } from '@/stores';
13-
import { NButton, NEmpty, NFlex, NIcon, NTag } from 'naive-ui';
14+
import { NButton, NEmpty, NFlex, NIcon } from 'naive-ui';
1415
import { computed, onMounted, watch } from 'vue';
1516
1617
const props = defineProps<{
@@ -86,24 +87,12 @@ onMounted(() => {
8687
<help-button-widget help-key="browseView" />
8788
</icon-heading>
8889

89-
<!-- LOCATION ALIASES -->
90-
<n-flex v-if="showLocAliases" align="center" class="my-lg">
91-
<n-tag
92-
v-for="alias in browse.locationPathHead?.aliases"
93-
:key="alias"
94-
size="small"
95-
class="loc-alias-tag"
96-
:title="$t('browse.location.aliasesTip')"
97-
>
98-
{{ alias }}
99-
</n-tag>
100-
</n-flex>
101-
102-
<!-- EMBED LOCATION METADATA AS TAGS -->
103-
<n-flex v-if="!!embeddedMetadata.length" align="center" class="my-lg">
104-
<location-metadata-content-tags v-if="!!embeddedMetadata.length" :contents="embeddedMetadata" />
105-
</n-flex>
106-
90+
<location-aliases-widget
91+
v-if="showLocAliases"
92+
:aliases="browse.locationPathHead?.aliases || undefined"
93+
:text-slug="state.textSlug"
94+
/>
95+
<location-metadata-content-tags v-if="!!embeddedMetadata.length" :contents="embeddedMetadata" />
10796
<browse-toolbar v-if="browse.locationPath.length" />
10897

10998
<div

0 commit comments

Comments
 (0)