Skip to content

Commit

Permalink
feat(desc-text): add linkify option (#555) (#556)
Browse files Browse the repository at this point in the history
close #555

---------

Co-authored-by: Kia King Ishii <[email protected]>
  • Loading branch information
brc-dd and kiaking authored Sep 25, 2024
1 parent 89a9e8d commit 2cd0eef
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 5 deletions.
14 changes: 14 additions & 0 deletions docs/components/desc.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,20 @@ You may also use `:pre-wrap` to preserve line breaks in the text. This is especi
</SDesc>
```

By specifying `:linkify`, the component will automatically convert URLs and email addresses in the text into clickable links. It will not convert any Markdown syntax or raw HTML tags. Note that this feature only works when passing in text as a prop through `:value`.

```vue-html
<SDesc cols="2" gap="24">
<SDescItem span="1">
<SDescLabel value="About" />
<SDescText
linkify
value="Clickable link: https://example.com"
/>
</SDescItem>
</SDesc>
```

## Number value

Use `<SDescNumber>` which is a specialized version of `<SDescText>` that is tailored to display numbers. It provides additional styling and formatting options that are not available in `<SDescText>`.
Expand Down
19 changes: 15 additions & 4 deletions lib/components/SDescText.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { useLinkifyIt } from 'sefirot/composables/Markdown'
import { computed } from 'vue'
import { useHasSlotContent } from '../composables/Utils'
import SDescEmpty from './SDescEmpty.vue'
Expand All @@ -7,6 +8,7 @@ const props = defineProps<{
value?: string | null
lineClamp?: string | number
preWrap?: boolean
linkify?: boolean
}>()
const classes = computed(() => [
Expand All @@ -17,14 +19,23 @@ const classes = computed(() => [
const hasSlot = useHasSlotContent()
const lineClamp = computed(() => props.lineClamp ?? 'none')
const linkifyIt = useLinkifyIt()
const _value = computed(() => {
if (props.linkify) {
return linkifyIt(props.value ?? '')
}
return props.value
})
</script>

<template>
<div v-if="hasSlot || value" class="SDescText" :class="classes">
<div class="value">
<slot v-if="hasSlot" />
<template v-else>{{ value }}</template>
<div v-if="hasSlot || _value" class="SDescText" :class="classes">
<div class="value" v-if="hasSlot">
<slot />
</div>
<div class="value" v-else v-html="_value" />
</div>
<SDescEmpty v-else />
</template>
Expand Down
14 changes: 14 additions & 0 deletions lib/composables/Markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ export function useMarkdown(options: UseMarkdownOptions = {}): UseMarkdown {
}
}

export function useLinkifyIt() {
const md = new MarkdownIt('zero', { linkify: true })
md.enable('linkify')

md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
const token = tokens[idx]
token.attrSet('target', '_blank')
token.attrSet('rel', 'noreferrer')
return self.renderToken(tokens, idx, options)
}

return (source: string) => md.renderInline(source)
}

export interface UseLink {
addListeners(): void
removeListeners(): void
Expand Down
52 changes: 52 additions & 0 deletions stories/components/SDesc.04_Text.story.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<script setup lang="ts">
import SDesc from 'sefirot/components/SDesc.vue'
import SDescItem from 'sefirot/components/SDescItem.vue'
import SDescLabel from 'sefirot/components/SDescLabel.vue'
import SDescText from 'sefirot/components/SDescText.vue'
const title = 'Components / SDesc / 04. Text'
const docs = '/components/desc'
function state() {
return {
lineClamp: 10,
preWrap: false,
linkify: true
}
}
</script>

<template>
<Story :title="title" :init-state="state" source="Not available" auto-props-disabled>
<template #controls="{ state }">
<HstNumber
title="lineClamp"
v-model="state.lineClamp"
/>
<HstCheckbox
title="preWrap"
v-model="state.preWrap"
/>
<HstCheckbox
title="linkify"
v-model="state.linkify"
/>
</template>

<template #default="{ state }">
<Board :title="title" :docs="docs">
<SDesc cols="2" gap="24">
<SDescItem span="2">
<SDescLabel>Label</SDescLabel>
<SDescText
:line-clamp="state.lineClamp"
:pre-wrap="state.preWrap"
:linkify="state.linkify"
:value="'By specifying the `:linkify`, you can enable the automatic conversion of URLs such as https://globalbrains.com and emails such as [email protected] inside text to clickable links. It will only convert plain URLs and any other Markdown syntax such as [link](https://globalbrains.com) and **Strong Text** will not be parsed.\nWhen enabling `preWrap`, this sentence should have a line break.'"
/>
</SDescItem>
</SDesc>
</Board>
</template>
</Story>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import SDescAvatar from 'sefirot/components/SDescAvatar.vue'
import SDescItem from 'sefirot/components/SDescItem.vue'
import SDescLabel from 'sefirot/components/SDescLabel.vue'
const title = 'Components / SDesc / 04. Avatar Many'
const title = 'Components / SDesc / 05. Avatar Many'
const docs = '/components/desc'
const avatars = [
Expand Down

0 comments on commit 2cd0eef

Please sign in to comment.