-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
When using Nuxt, how to use NuxtLink
component inside a rich text field, instead of the standard a
element?
#289
Comments
I am dealing with the exact same problem. Does anyone have any advice on the best way to solve routing using ? |
I think the options are to try to get it to work with the schema system that is built in (https://github.com/storyblok/storyblok-js#rendering-rich-text) or do a manual loop of all the nodes and do your own handling (https://gist.github.com/SebbeJohansson/99aa4f1f622552d29927c208c528b489 and https://gist.github.com/SebbeJohansson/31b64c5c4f914abfec2660210ec7795a). |
I agree with @SebbeJohansson Did you try it @stefanobartoletti ? |
Hey @alvarosabu thanks for checking out, I had a try some time ago but at the moment I'm working on a couple of projects that use another tech stack, so I will check this as soon as possible :) |
So strange that this is not easily archivable, since this is a Nuxt Specific module. Has anyone figured out how to do it with the schema system? https://github.com/storyblok/storyblok-js#rendering-rich-text |
Hi @madebyfabian maybe I can throw some light about the richtext. What the js client of storyblok offer is a way to parse the richtext into semantic html. NuxtLink is not semantic, is a vue component. For that you would need an specific package that allow you to overwrite tags to vue components. https://github.com/m4rvr/storyblok-rich-text-renderer is the most solid option for this. |
@alvarosabu Sure, but this is the nuxt/vue package, so I would expect the richtext renderer to support vue components. The package you suggested is not maintained, outdated, has nearly 0 docs and has various issues. I cannot even get it to run at all in Nuxt 3.7.0 with SSR. (nothing against @m4vrv here, I think it's not on the community to build this). I would offer my help in creating a proper renderer, but currently don't have any resources available to focus on this. |
Yes, @madebyfabian we are aware of the package being no longer maintained. All the rich text renderers of the ecosystem are done by the community:
The reason is that we don't have enough capacity to maintain SDKs + richtext renderers for every framework. We have discussed it recently to see how we could approach it. For now, max we can do is support the community in building one I'm afraid.
Thanks for offering 🙏🏻. If you ever find time for it or any other dev checking this ticket, I personally will support you to get this build. |
I know it's not the answer you were looking for, but here is an example of how I used |
@stefanobartoletti a solution for NuxtLink and NuxtImage would be: // /plugins/storyblok.ts
import { plugin, defaultResolvers } from '@marvr/storyblok-rich-text-vue-renderer'
import { NodeTypes } from '@marvr/storyblok-rich-text-types'
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(
plugin({
resolvers: {
...defaultResolvers,
[NodeTypes.IMAGE]: NuxtImage,
[NodeTypes.LINK]: NuxtLink
},
}),
)
}) |
@alvarosabu Thanks for your answers. I managed to get it up and running with those. I understand that this is time consuming, I just think SDKs should be priorized higher, since this is what customers mostly will interact with. Same for the Content Delivery APIs. |
is there a solution to handle this elemantary problem for nuxt-users without integrating thirt party libaries/ projects (doesn't work in my case anyway)? |
@alvarosabu thanks for your help and for the suggestion, I will test this as soon as possible. |
@alvarosabu I could potentially be interested in building something. At least for vue/nuxt3. What exactly would be needed? |
FYI: I got maintainer access to the suggested library, and added all of the currently missing marks/nodes. Again, don't have much capacity to go into detail but maybe if there is something urgent to fix, you can add an issue/PR. |
@madebyfabian that is brilliant. Maybe we could open it up a bit more? |
@SebbeJohansson Do you mean functionality-wise? or Docs? |
@madebyfabian I specifically meant adding more developers and more of a collaboration :D |
@SebbeJohansson Sure! You can ask @m4rvr. Not sure if I just should invite other devs. |
Hi @madebyfabian and @SebbeJohansson thanks for jumping in! Would it make things easier if we created a repo ourselves? |
@alvarosabu I think it would make sense if it was storyblok that had control over it so to speak and allow for easy administration by the community. A solution could be a fork at like storyblok/rich-text-renderer, but i do think that it would require @m4rvr's okay first. |
@madebyfabian if you have a way to contact him, feel free to ask about this! |
@SebbeJohansson sounds great, yeah. I asked him, will let you know the response. |
@SebbeJohansson
So that in the end people can use it as Feel free to suggest a different solution :) |
Hey Alvaro, sorry to say that, but IMO it has a bad taste to just copy a repo from someone. The richtext is an important part of Storyblok and I can't believe there are no capacities and money left for creating an own version, but instead relying on the free outdated solution of the community. It's open source, yes, and I'm fine with it, but it feels weird to just copy the work. Without @madebyfabian's work, it would be still a pain for the Storyblok users. They pay for it and get an outdated, non-working solution. That's not what you expect from a business that gets $47 million Series B funding TBH. I hope you can do better in the future and consider spending more time and money on creating a great solution. Feel free to take the repo as inspiration, but not just copy it and sell it. Especially not if the work is so important and stated like it's Storyblok's made solution, without me having any benefit from it. Thanks |
Hi @m4rvr First of all, we are really grateful for all your work on the rich text renderer because it has enabled a lot of users to use it with Vue. Let me clarify that my message never states to copy your work by any means.
Create a new repo in Storyblok org so we can support in terms of administration of the repo and implement a renderer (not copying yours) in case you don't have the capacity or desire to continue supporting the original repository. So I clarify again "we are not going to use your code" if we develop a renderer, The original idea we had was supporting the open source repos (you) in case you wanted to continue with it. I'm really sorry if you felt that way, but to be strictly frank, your code can be easily forked and used by anyone, If you really want to control how your codebase is used, I suggest you add a LICENSE file to your projects. Storyblok is a SaaS product, not an open-source product, The SDKs exist entirely because the DevRel team of Storyblok wanted to improve the developer experience of the users. Any product could provide you with just a single SDK JS client and that's it, We don't, we offer SDKS for all the major technologies and we sponsor open source which most companies don't.
Could you elaborate on how we are selling open-source code? Are you paying for using this Nuxt module? Are you paying for any of the SDKs? Are you aware that we suggest your solution everywhere on our content? Please reflect on your message because it's at all unfair. I'm here to support administrate, help, and even code any solution that the community wants to create and the credit will be always for the people who build it. Thanks |
I won't respond to specific points, but I just wanted to chime in and say that this is exactly why I wanted @m4rvr to be properly included in the discussion. Because taking over an abandoned open source project is always sensitive. I do agree to a certain extent that rich text rendering should be something that storyblok solves on their end, but if the community gotta do it then I think it makes sense if we try to do it together to the best of our ability. Not sure I agree with just using some parts in a different repo. I think it makes more sense to just continue with the actual package repo, no matter where it is. @m4rvr maybe a better solution would be to allow storyblok to administrate the devrel stuff for the package? |
@SebbeJohansson thanks for jumping in. Please, could you both elaborate on how the following question
Means copy/forking or |
To clarify and avoid further misunderstandings:
Let's move forward constructively, we want the same goal at the end. |
@alvarosabu I don't think reinventing the wheel makes sense if Marvin is on board, no matter if we keep going in his repo or make a new one.
I hope that is more clear and I hope we can come to an agreement on what to do! I would love it if @m4rvr could clarify what exactly he is afraid of could potentially happen and what he wants to get out of this. Marvin, if you wanna chat more easily with me, feel free to reach out on discord! |
Hi @m4rvr have you considered the proposals stated above?
|
I don't necessarily want to butt into the ongoing discussion here, but for others who (like me) find this thread from Google in the future, I needed to make the following changes to this snippet to make it all work as expected: // /plugins/storyblok.ts
import {
plugin,
defaultResolvers,
} from "@marvr/storyblok-rich-text-vue-renderer";
import { NodeTypes} from "@marvr/storyblok-rich-text-types";
import { AppLink } from "#components";
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(
plugin({
resolvers: {
...defaultResolvers,
[NodeTypes.LINK]: AppLink,
components: {},
},
}),
);
}); <!-- /components/global/AppLink.vue -->
<template>
<NuxtLink
v-if="linktype === 'story'"
:to="`${href}${anchor ? `#${anchor}` : ''}`"
>
<slot />
</NuxtLink>
<a
v-else
:href="linktype === 'email' ? `mailto:${href}` : href"
:target="target"
:rel="target === '_blank' ? 'noopener noreferrer' : ''"
>
<slot />
</a>
</template>
<script setup lang="ts">
defineProps({ href: String, linktype: String, anchor: String, target: String });
</script> I also needed to install Thanks to everyone in this thread for raising the issue and working on it! |
Some news about this? Are there still some plans to bring this functionality inside the module, or a user-made custom solution is to be implemented? Thanks :) |
the solution from marvr doesn't work for us (pflege.de). the component gets the richtext-json and loop trough the root level and rearranged it into 3 categories:
.. the template renders the new array with "categorization" and renders each category individually. <template>
<div>
<template v-for="node in renderedContent">
<component
:is="node.blok.component"
v-if="node.blok"
:key="`c_${node.index}`"
:blok="node.blok"
/>
<NuxtImg
v-else-if="node.image?.src"
:key="`i_${node.index}`"
format="webp"
placeholder
:src="node.image.src"
:alt="node.image.alt"
:title="node.image.title"
:data-copyright="node.image.copyright"
loading="lazy"
/>
<div v-else :key="`t_${node.index}`" ref="textNodes" class="text" v-html="node.html" />
</template>
</div>
</template>
<script setup>
const props = defineProps({
blok: {
type: Object,
required: false,
default: () => {}
}
})
const renderedContent = computed(() => {
const nodes = []
props.blok.content.forEach((textSectionObject, index) => {
if (textSectionObject.type === 'blok') {
textSectionObject.attrs?.body.forEach((blok) => {
nodes.push({
index,
blok
})
})
return
}
if (textSectionObject.content && textSectionObject.content[0].type === 'image') {
nodes.push({
index,
image: textSectionObject.content[0].attrs
})
return
}
const html = useStoryblokApi()
.richTextResolver.render({
type: 'doc',
content: [textSectionObject]
})
.replace('//a.storyblok.com', '//assets.pflege.de')
.replace('href="//', 'href="/')
nodes.push({
index,
html
})
})
return nodes
})
const useRichtextResolverInternalLinkTransformer = (textNodes) => {
const router = useRouter()
const onAnchorClick = (e) => {
e.stopPropagation()
if (e.currentTarget.hasAttribute('uuid') && e.currentTarget.hasAttribute('href')) {
e.preventDefault()
router.push({ path: e.currentTarget.getAttribute('href') })
}
}
const setEventListener = (isOnMount) => {
textNodes.forEach((textNode) => {
const listOfAnchorNodes = textNode.getElementsByTagName('a')
for (const anchorNode of listOfAnchorNodes) {
if (isOnMount) {
anchorNode.addEventListener('click', onAnchorClick)
} else {
anchorNode.removeEventListener('click', onAnchorClick)
}
}
})
}
onMounted(() => {
setEventListener(true)
})
onBeforeUnmount(() => {
setEventListener(false)
})
}
const textNodes = ref([])
useRichtextResolverInternalLinkTransformer(textNodes.value)
</script> i hope this will help others :) |
Thanks for your reply and your solution @menschner ! |
Context: website built with Storyblok as CMS and Nuxt 3 for the static frontend.
When editing Rich Text content within Storyblok, the user (not necessarily the developer) can also insert links.
From what I see, these are rendered on the frontend as standard
a
elements. This is not optimal, since Nuxt provides theNuxtLink
component that applies various optimizations, like prefetching, to links where it is used.Especially for internal links,
NuxtLink
navigates to the specified route without forcing a full refresh of the page, resulting in a smooth transition between the pages and a SPA feel. While the defaulta
anchor fully refreshes the page, like in plain HTML websites.Is there a way to render links inside a Rich Text as
NuxtLink
components, or make them have the same behaviour?Thanks! Let me know if you need more context/info.
The text was updated successfully, but these errors were encountered: