diff --git a/components/molecules/VRoadizLink/Default.stories.vue b/components/molecules/VRoadizLink/Default.stories.vue index 07869cb..6ac8ec0 100644 --- a/components/molecules/VRoadizLink/Default.stories.vue +++ b/components/molecules/VRoadizLink/Default.stories.vue @@ -16,7 +16,7 @@ const currentBaseUrl = computed(() => (window?.origin ? joinURL(window.origin, ' (window?.origin ? joinURL(window.origin, ' - + @@ -42,7 +42,7 @@ const currentBaseUrl = computed(() => (window?.origin ? joinURL(window.origin, ' - + External Link diff --git a/components/molecules/VRoadizLink/Schemes.stories.vue b/components/molecules/VRoadizLink/Schemes.stories.vue new file mode 100644 index 0000000..84ae77c --- /dev/null +++ b/components/molecules/VRoadizLink/Schemes.stories.vue @@ -0,0 +1,25 @@ + + + diff --git a/components/molecules/VRoadizLink/VRoadizLink.vue b/components/molecules/VRoadizLink/VRoadizLink.vue index 56d86d4..41533e6 100644 --- a/components/molecules/VRoadizLink/VRoadizLink.vue +++ b/components/molecules/VRoadizLink/VRoadizLink.vue @@ -4,7 +4,6 @@ import { h, type PropType } from 'vue' import type { NuxtLinkProps } from '#app/components/nuxt-link' import { NuxtLink } from '#components' import type { ReachableItem } from '~/types/app' -import { isInternalUrl } from '~/utils/url' export const vRoadizLinkProps = { label: [String, Boolean], @@ -21,47 +20,57 @@ export default defineComponent({ setup(props, { attrs, slots }) { const reference = computed(() => { if (!props.reference) return - return Array.isArray(props.reference) ? props.reference[0] : props.reference - }) - const url = computed(() => { - return props.url || reference.value?.url || props.document?.relativePath + return Array.isArray(props.reference) ? props.reference[0] : props.reference }) const runtimeConfig = useRuntimeConfig() const siteUrl = runtimeConfig?.public?.site.url - const isInternal = computed(() => isInternalUrl(url.value, siteUrl)) - const isExternal = computed(() => !!url.value && !isInternal.value) - const isDownload = computed(() => !!url.value && !isExternal.value && !!props.document?.relativePath) - const attributes = computed(() => { - const mergedAttrs = { ...attrs, ...props.nuxtLinkProps } - if (!url.value) return mergedAttrs + const defaultAttrs = { ...attrs, ...props.nuxtLinkProps } - if (isDownload.value) { - Object.assign(mergedAttrs, { + // Download + if (props.document?.relativePath) { + return { + ...defaultAttrs, href: useRoadizDocumentUrl(props.document?.relativePath), target: attrs?.target || '_blank', - rel: attrs?.rel || 'noopener', + rel: attrs?.rel || 'noopener noreferrer', download: '', - }) + } } - else if (isExternal.value) { - Object.assign(mergedAttrs, { + + // External link + if (props.url && isExternalUrl(props.url, siteUrl)) { + return { + ...defaultAttrs, href: props.url, target: attrs?.target || '_blank', - rel: attrs?.rel || 'noopener', - }) + rel: attrs?.rel || 'noopener noreferrer', + } } - else if (isInternal.value) { + + // Internal link + const internalUrl = props.url && isInternalURL(props.url, siteUrl) ? props.url : reference.value && isInternalURL(reference.value.url, siteUrl) ? reference.value.url : undefined + + if (internalUrl) { // Prevent NuxtLink to add rel attrs if it is absolute internal url - Object.assign(mergedAttrs, { - to: url.value?.replace(siteUrl, ''), // Force relative path - }) + return { + ...defaultAttrs, + to: internalUrl?.replace(siteUrl, ''), // Force relative path + } + } + + // Other kind of links (mailto, tel, javascript, etc.) + if (props.url) { + return { + ...defaultAttrs, + to: props.url, + } } - return mergedAttrs + return defaultAttrs }) return () => { diff --git a/utils/url.ts b/utils/url.ts index fb8970a..18b2f00 100644 --- a/utils/url.ts +++ b/utils/url.ts @@ -4,12 +4,18 @@ export function encodeUrlParams(params: object): string { .join('&') } -export function isRelativeUrl(url: string | undefined | null) { - return url?.charAt(0) === '/' || url?.charAt(0) === '#' +export function isHttpUrlScheme(url: string) { + return url.startsWith('http://') || url.startsWith('https://') } -export function isInternalUrl(url: string | undefined | null, siteUrl?: string) { - if (!url) return false +export function isRelativeUrl(url: string) { + return url.charAt(0) === '/' +} +export function isInternalURL(url: string, siteUrl?: string) { return isRelativeUrl(url) || (siteUrl && url.startsWith(siteUrl)) } + +export function isExternalUrl(url: string, siteUrl?: string) { + return isHttpUrlScheme(url) && !isInternalURL(url, siteUrl) +}