How to use local svg files in NavItems in Fluent UI React - fluent-ui

I was trying to use custom svg files in my nav bar but not able to render then. I'm using fluentui-react
onLinkClick={onLinkClick}
className="menuLinks"
selectedKey={'quickStart'}
ariaLabel="Nav bar"
styles={navStyles}
groups={navLinkGroups}
/>
................................
export const navLinkGroups: INavLinkGroup[] = [
{
links: [
{
name: 'Home',
url: '',
key: 'home',
desc: 'Home',
icon: '' //--> need to render custom icon here
}
]}
I had tried using "registerIcons" from 'office-ui-fabric-react/lib/Styling' but it doesnt worked for me.
Please help me in this.

Property icon inside INavLink is reserved for FluentUI Icons. More info here.
If you want to render a custom Icon for specific menu item you need to use onRenderLink prop inside Nav component:
const renderCustomMenuItem = (props, defaultRender) => {
// Set custom icon for documents menu item.
if(props.name === 'Documents') {
return (
<div>
<img src={mySVGIcon} />
<span>{props.name}</span>
</div>
)
} else {
return defaultRender(props);
}
}
<Nav
...
onRenderLink={renderCustomMenuItem}
/>
Codepen working example.
FluentUI Documentation.

Related

Storybook: Clicking a button redirects user

I have a link component that I want to display in Storybook. I'm using Vue.
This is the component
NavigationLink.vue:
<ul>
<li :class="{selected: isSelected}">
<a :href="linkUrl">
<i :class="'isax isax-' + linkIcon"></i>
{{ linkName }}
</a>
</li>
</ul>
This is the story NavigationLink.stories.js:
import NavigationLink from '../app/javascript/components/NavigationLink.vue'
export default {
title: 'Navigation/Links',
component: NavigationLink,
argTypes: { ...argTypes here... }
}
const Template = (args) => ({
components: { NavigationLink },
setup() {
return { args };
},
template: '<NavigationLink v-bind="args"></NavigationLink>',
});
export const UnselectedLink = Template.bind({});
UnselectedLink.args = { ...args here... }
export const SelectedLink = Template.bind({});
SelectedLink.args = { ...args here... }
Unfortunately, you're still able to 'click' the link in Storybook and this then redirects to the 'Introduction' page within Storybook. But I don't want it to redirect there at all. In fact, if possible, I'd prefer to not be able to click it at all.
Any suggestions? Thanks in advance.
In the end I couldn't find a fancy way of doing this, so I just set the :href prop to be linkHref: '/?path=/story/navigation-links--unselected-link' in the args for UnselectedLink (and then similar for the SelectedLink). This still allows for the link to be clicked but will just redirect you back to the same story within Storybook.

Trying to load an image inside a assets/img folder in a v-for, but the images does not load

I'm trying to load the images in the assets/img folder in my vue3 project using a v-for inside a div, but they are not loading, just display my alt.
So, I have a vue component what will display a title and a paragraph and also a image. The images are in the assets/img folder, I'm getting the path of the image with a store that I created. When I try to just put the path of the image like this: src="../assets/img/img2.jpg" the images renders.
Here is 1 of my state in the store.js:
content: [
{
headline: 'Teste',
paragraph: 'this is a paragraph',
img: '#/assets/img/img.jpg'
},]
Here is my template using the v-for:
<template>
<div>
<div
class="slider"
v-for="item, i in content"
:key='i'
>
<h1>{{item.headline}}</h1>
<p>{{item.paragraph}}</p>
<img
:src="item.img"
alt="test"
/>
</div>
</div>
</template>
My setup:
setup () {
const store = useStore()
const content = store.getters.getContent
return { content }
}
I tryed to use :src="require(item.img)" but i got a webpack error by doing this:
Uncaught Error: Cannot find module '#/assets/img/img.jpg' webpackEmptyContext components sync:2
Also tryed to point the folder of the images in the src, :src="#/assets/img + item.img", but it didn't work.
I met this question before.
Maybe the following code could help you.
// create a function in util.js
export const getSrc = ( name ) => {
const path = `/src/assets/img/${name}`
const modules = import.meta.globEager('/src/assets/img/*.jpg')
return modules[path].default
}
// use getSrc in someItem.vue
import { getSrc } from '#/util/util.js'
content: [
{
headline: 'Teste',
paragraph: 'this is a paragraph',
img: getSrc('img.jpg')
}
]

How can I can show a div if an object doesn't have a value outside of the object scope

I have a small Nuxt issue that I can't work out how to get around.
Essentially, I have an object (used for a carousel slider).
<template>
<div
:class="[$style.swiperSlide, 'swiper-slide']"
v-for="slide in slides"
:key="slide.id">
<nuxt-img
:class="[$style.img]"
:alt="slide.alt"
:src="imgSources(slide)"
sizes="sm:100vw"
/>
<div :class="[$style.info, 'info-b']" v-if="slide.info">
{{ slide.info }}
</div>
</div>
<button :class="[$style.infoOpen]"
#click="showTab"
v-if="slideInfoAvailable"
>
Close
</button>
</template>
<script>
export default {
props: {
slides: {
type: Array,
required: true,
default: () => []
}
},
computed: {
slideInfoAvailable() {
return this.slide?.info
}
},
mounted() {
const swiper = new Swiper(".swiper-container", {
. . .
});
},
methods: {
imgSources(slide) {
return `/img${slide.imgPath}.jpg`;
},
};
</script>
All works o.k, the problem is that I have a button outside of this v-for that I need to only be visible if there's slide.info but because this div is outside of the v-for it can't tell if it's available.
Cannot read property 'info' of undefined
The easiest way out of this is to add the button inside of the slider - but I can't for Z-index CSS issues. It has to be outside of the 'slider' div.
Any ideas how I can only show the button if there's slide.info? For some of my slides, there won't be.
<slider
:slides="[
{
imgPath: '/demo',
info: 'Demo info for this slide',
alt: 'Homepage'
},
{
imgPath: '/demo2',
alt: 'Homepage'
},
]"
/>
One way I could do it would be to see if .slide-active .style.info exists. If it doesn't exist then I can hide the button as slide-active is added to the active div by the slider API.
The issue is coming from the fact that you probably have some async fetching and that slides are not available upon initial render. To prevent this, you can use a computed with some optional chaining like this
export default {
computed: {
slideInfoAvailable() {
return this.slide?.info
}
}
}
Then, call it like this
<button :class="[$style.infoOpen]" #click="showTab" v-if="slideInfoAvailable">
You cannot use ?. directly in the template.
You could also do the classic way of
<button :class="[$style.infoOpen]" #click="showTab" v-if="slide && slide.info">
but it does not look as sexy IMO (but you do not need any computed).
And yeah, for this kind of thing, better to handle it with Vue than relying on some hacky dirty CSS tricks!

cant change type(danger,success) and add animated on vue strap

i Want to make a progress bar using vue strap . i install vue strap on this link
this link
now i add a progress bar, this progress bar is showing , this bar is only showing color primary and cant showing animated .
<template>
<div class="progress">
<progressbar now="99" type="danger" striped animated ></progressbar>
</div>
</template>
<script>
import { progressbar } from 'vue-strap'
export default {
components: {
progressbar
},
mounted() {
console.log('Component mounted.')
}
}
</script>
with this code , this type is primary and this animated didnt work .
i change browser from chrome to mozila , but its still didnt work . my browser is newest .
whats wrong about this ? i dont know why animated didnt work
There is a bug in VueStrap library when it comes to progress bar animations. The template for progress bar in VueStrap uses class active to animate, whereas, in Bootstrap 4 we have to use class progress-bar-animated. A work around of this problem is to created your own Progress Bar component which makes use of the Bootstrap 4.
Custom Progress Bar component could be written as:
Vue.component('c-progressbar', {
template: `
<div class="progress">
<div class="progress-bar" :class="progressClasses"
role="progressbar"
:style="progressStyle"></div>
</div>`,
props: {
striped: Boolean,
animated: Boolean,
now: {
type: Number,
required: true
},
contextType: {
type: String,
default: 'primary'
}
},
data: function() {
let context = 'bg-' + this.contextType
return {
progressClasses: {
'progress-bar-striped': this.striped,
'progress-bar-animated': this.animated,
[context]: true
},
progressStyle: {
width: this.now + '%'
}
}
}
})
new Vue({ el: '#app' })
You can use this pen for testing: https://codepen.io/abdullah-shabaz/pen/YzXdYgd

Experiencing navbar flicker with Vue.js

I'm experiencing a flicker in my navbar before a function is evaluated to either true or false.
The function that needs to evaluate is the following:
export default {
methods: {
isAuthenticated () {
return this.$store.state.user.authenticated
}
},
data: () => {
return {
unauthenticated: [
{
title: 'Link1',
url: '/link1'
},
{
title: 'Link2',
url: '/link2'
},
{
title: 'Link3',
url: '/link3'
}
],
authenticated: [
{
title: 'otherLink1',
url: '/otherlink1'
},
{
title: 'otherLink2',
url: '/otherlink2'
},
{
title: 'otherLink3',
url: '/otherlink3'
}
]
}
}
}
And the navbar has the following:
<template v-if="isAuthenticated()">
<b-nav is-nav-bar>
<b-nav-item v-for="nav in authenticated" :key="nav.title" :href="nav.url">{{nav.title}}</b-nav-item>
</b-nav>
</template>
<template v-else>
<b-nav is-nav-bar>
<b-nav-item v-for="nav in unauthenticated" :key="nav.title" :href="nav.url">{{nav.title}}</b-nav-item>
</b-nav>
</template>
However, when I click through the navigation, the unauthenticated links appear for a second and then the authenticated links appear as if the isAuthenticated() function hasn't evaluated yet. What can I do to remove this flicker?
My store file (user.js) file looks like this:
export const state = () => ({
headers: {},
profile: {}
})
export const mutations = {
updateHeaders (state, headers) {
state.headers.access_token = headers['access-token']
state.headers.token_type = headers['token-type']
state.headers.client = headers['client']
state.headers.expiry = headers['expiry']
state.headers.uid = headers['uid']
if (state.headers.expiry == null) {
state.authenticated = false
} else {
let timeToExpiry = new Date(state.headers.expiry * 1000)
let now = new Date()
state.authenticated = now < timeToExpiry
}
},
signout (state) {
state.headers = {}
state.profile = {}
}
}
The login/logout methods occur via API calls to a Rails app. The Devise gem handles the rest.
Thanks in advance!
EDIT:
I am using Nuxt.js for the layouts/pages/components so I believe that links submit with a this.$router.push(url) under the hood.
The b-nav tags are coming from Bootstrap Vue
When using bootstrap-vue there are two ways to add links to the navbar. One is to bind to :href attribute, which creates a regular html anchor. The other is to use :to attribute, which creates a link that interacts with vue-router.
<b-navbar-nav v-if="isAuthenticated()">
<b-nav-item v-for="nav in authenticated" :key="nav.title" :to="nav.url">{{nav.title}}</b-nav-item>
</b-navbar-nav>
<b-navbar-nav v-if="!isAuthenticated()">
<b-nav-item v-for="nav in unauthenticated" :key="nav.title" :to="nav.url">{{nav.title}}</b-nav-item>
</b-navbar-nav>
No reason to use <template> tags here to encapsulate the . Also note that 'is-nav-bar' is deprecated. See here where they note the deprecation.
What code executes when you click one of the links is not stated, I assume it's something like this.$router.push(url). If this is the case, you've probably have included your navbar in the <router-view>, so when you switch current route, components inside <router-view> rerender, so the navbar flashes. Move them out of the <router-view> should fix this.
edit: so the OP is not using vue-router yet, in this case, either manually change the root component's data to make parts other than the navs change, or add vue-router and use this.$router.push() to navigate so parts outside <router-view> won't change or flash.
Anyway, we need the vue component to stay to let vue to rerender only part of the view, while simply navigating by <a> or something will destruct everything and reconstruct them again, hence the flashing.