I want to be able to reuse Chip components made with Svelte - components

It is difficult to reuse the Chip components that are currently running in my project.
I would like to modify the code to make it easier to reuse.
For example, I want to make it as easy to use as this
let labels=["foo", "bar"];
<Chips labels="{labels}" >
Current source code
<script>
import { redirectUris } from '../../store/';
import close from '../../asset/icon/tip/close.svg';
function removeFromList(index) {
$redirectUris.splice(index, 1);
$redirectUris = $redirectUris;
}
</script>
<div class="chips">
{#each $redirectUris as uri, index}
<div class="chip">
<p class="chip-name">{uri}</p>
<button
on:click="{() => {
console.log(uri);
removeFromList(index);
console.log($redirectUris);
}}">
<img src="{close}" alt="close" />
</button>
</div>
{/each}
</div>

Remove the reference to your store and replace it with a property:
<script>
import close from '../../asset/icon/tip/close.svg';
export let labels = [];
</script>
<div class="chips">
{#each labels as label, index}
<div class="chip">
<p class="chip-name">{label}</p>
<button
on:click="{() => {
labels.splice(index, 1);
labels = labels;
}}">
<img src="{close}" alt="close" />
</button>
</div>
{/each}
</div>
You can then use it like you posted above. If you need to update the chips in your parent component, use bind which establishes a two-way binding:
<script>
import Chips from '..';
let labels=["foo", "bar"];
</script>
<Chips bind:labels />
If you need a "chip deleted" event, you can use event dispatchers for that: https://svelte.dev/docs#createEventDispatcher
<script>
import { createEventDispatcher } from 'svelte';
import close from '../../asset/icon/tip/close.svg';
export let labels = [];
const dispatch = createEventDispatcher();
</script>
<div class="chips">
{#each labels as label, index}
<div class="chip">
<p class="chip-name">{label}</p>
<button
on:click="{() => {
labels.splice(index, 1);
labels = labels;
dispatch('close', { label, index });
}}">
<img src="{close}" alt="close" />
</button>
</div>
{/each}
</div>

Related

Set heights of a row of components dynamically based on the tallest one

I have three components called blog cards that are rendered with an image and text. Depending on how long the text is the cards are of different heights. I want to render them, then get the tallest one, and sort of re-render them, so they are all the same height.
Here is the Page
import * as React from 'react'
import { SocialIconRow } from '#/components/social-icons'
import BlogPostCard from '#/components/BlogCard'
import Image from 'next/image'
import { useState, useEffect } from 'react'
import { FixedSizeList } from 'react-window'
function BlogPostCardsList({ cards }) {
const tallestCardHeight = useMemo(() => {
return Math.max(...cards.map(card => card.height))
}, [cards])
return (
<FixedSizeList
itemCount={cards.length}
itemSize={tallestCardHeight}
width={'100%'}
height={'100%'}
>
{({ index, style }) => <BlogPostCard style={style} {...cards[index]} />}
</FixedSizeList>
)
}
export default function MyComponent(props) {
const [cardHeight, setCardHeight] = useState(null);
const [maxHeight, setMaxHeight] = useState(0);
useEffect(() => {
const calculateHeight = () => {
const cards = document.querySelectorAll('.blog-post-card');
let heights = [];
cards.forEach(card => {
heights.push(card.clientHeight);
});
setMaxHeight(Math.max(...heights));
}
calculateHeight();
setCardHeight(maxHeight);
}, []);
return (
<>
<div className="container mx-auto flex flex-col">
<div className="container mx-auto flex">
<div className="w-1/2 pr-4">
<div className="text-4xl font-bold">Mike Borman</div>
<div className="text-lg mt-2">Writer, Content Creator and Developer on Cardano</div>
</div>
<div className="w-1/2 flex flex-col justify-center">
<div className="max-h-48 max-w-48 mx-auto my-auto">
<Image
src="/images/myfaceppgray.png"
alt="Picture of the author"
className="max-h-48 max-w-48"
width="150"
height="150"
unoptimized={true}
/>
</div>
<div className="mt-4">
<SocialIconRow className="social-icon-row" />
</div>
</div>
</div>
<div className="mt-8">
<div className="text-3xl font-bold">Featured Blogs</div>
<div className="grid grid-cols-3 gap-4 h-full mt-4 align-items-stretch">
<div style={{height: cardHeight}}>
<BlogPostCard
title="The Hydra Protocol Family — Scaling and Network Optimization for the Cardano Blockchain"
slug="the-hydra-protocol-family-scaling-and-network-optimization-for-the-cardano-blockchain"
imageslug="/images/hydra.png"
className="blog-post-card"
/>
</div>
<div style={{height: cardHeight}}>
<BlogPostCard
title="Ouroboros, A deep dive for non PhDs"
slug="ouroboros-a-deep-dive-for-non-phd"
imageslug="/images/ourobouros.png"
className="blog-post-card"
/>
</div>
<div className="h-full row-auto" style={{height: cardHeight}}>
<BlogPostCard
title="Ouroboros, A deep dive for non PhDs"
slug="ouroboros-a-deep-dive-for-non-phd"
imageslug="/images/ourobouros.png"
className="blog-post-card"
/>
</div>
</div>
</div>
</div>
</>
)
}
Here is the Card component:
import React from 'react'
import Link from 'next/link'
import Image from 'next/image'
function BlogPostCard(props) {
const { title, slug, imageslug } = props
return (
<Link href={`/blog/${slug}`}>
<a className="block flex flex-col justify-between rounded-md border-2 border-teal-400 transition-all duration-300 ease-in-out hover:scale-105 hover:shadow-lg">
<img className="rounded-t-md h-48 w-full object-cover" src={imageslug} alt="blog post cover" />
<span className="text-white text-2xl p-4">{title}</span>
</a>
</Link>
)
}
export default BlogPostCard
I tried dynamically rendering them then setting them, btw I have no idea really what Im doing there.
You actually have all but one class already to do this entirely in CSS. Just add h-full to your a tag inside the BlogPostCard component's Link. Then you can get rid of all of the JS. Optionally, you could also remove the justify-between or change it to justify-stretch so that the titles of the blog posts are directly beneath of the post cover images.
In the demo below, you can see the result by clicking run code snippet. Also, if you're upgrading to NextJS 13, it's worth noting that you no longer need (and in fact can't have) an a tag as a child of Link. I'd suggest using article as I've done below, which will be more semantically correct anyway.
function BlogPage({posts}) {
return (
<main className="container mx-auto my-8">
<div className="flex gap-4">
<div className="w-1/2">
<h1 className="text-4xl font-bold">Mike Borman</h1>
<h2 className="text-lg mt-2">
Writer, Content Creator and Developer on Cardano
</h2>
</div>
<div className="w-1/2 flex flex-col justify-center items-center">
<span className="w-[150px] h-[150px] bg-neutral-300 rounded-full grid place-content-center">author img here</span>
<span>social row here</span>
</div>
</div>
<section className="mt-8">
<header>
<h2 className="text-3xl font-bold">Featured Blogs</h2>
</header>
<div className="grid grid-cols-3 gap-4 h-full mt-4 align-items-stretch">
{posts.map((post) => (
<BlogPostCard key={post.id} {...post} />
))}
</div>
</section>
</main>
)
}
function BlogPostCard({ slug, imageslug, title,}) {
return (
<Link href={`/blog/${slug}`}>
<article className="flex flex-col justify-stretch h-full rounded-md border-2 border-teal-400 bg-neutral-600 transition-all duration-300 ease-in-out hover:scale-105 hover:shadow-lg">
<img
className="rounded-t-md h-48 w-full object-cover"
src={imageslug}
alt="blog post cover"
/>
<span className="text-white text-2xl p-4">{title}</span>
</article>
</Link>
)
}
/* Stubbing out next/link here since I can't run NextJS in code snippets */
function Link({ href, children, className }) {
return (
<a href={href} className={className}>
{children}
</a>
)
}
const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<BlogPage posts={[
{
id: 1,
title: 'The Hydra Protocol Family — Scaling and Network Optimization for the Cardano Blockchain',
slug: 'the-hydra-protocol-family-scaling-and-network-optimization-for-the-cardano-blockchain',
imageslug: 'https://d3lkc3n5th01x7.cloudfront.net/wp-content/uploads/2019/05/15233606/700-X-394.png',
},
{
id: 2,
title: 'Ouroboros, A deep dive for non PhDs',
slug: 'ouroboros-a-deep-dive-for-non-phd',
imageslug: 'https://www.almaviva.it/dam/jcr:6212e8ef-1ed6-40e2-a75f-b6fa7c814662/Blockchain_1280x720.jpg',
},
{
id: 3,
title: 'How Blockchain Is Used',
slug: 'how-blockchain-is-used',
imageslug: 'https://imageio.forbes.com/specials-images/imageserve/5f2a32ee3b52675a453e2881/Fascinating-Examples-Of-How-Blockchain-Is-Used-In-Insurance--Banking-And-Travel/960x0.jpg?format=jpg&width=960',
},
]} />
);
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
<div id="root"></div>

How do I implement percent values per slice of information in Victory Pie component

I would like to add a percentage value per slice of the doughnut chart, but I can't seem to figure out how. Also the data is dynamic not static, which means if there is another item added it needs to be able to recalculate and give accurate percentage per slice. This is the code below which shows the component of home, where there is data being fetched from the server side and getting the results. Then there is a variable called pie data results that maps and stores the occupation and values, and that is being passed as a prop down in the victory pie component.
import React, { Fragment, useState, useEffect } from "react";
//import DoughnutChart from "./DoughnutChart";
//import { Doughnut } from "react-chartjs-2";
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
//import { toast } from "react-toastify";
import "./pagecss/home.css";
import * as V from "victory";
import { VictoryPie } from "victory";
// import pieChartBasic from "./DoughnutChart";
// import { Doughnut } from "react-chartjs-2";
// import { FontAwesomeIcon } from "#fontawesome-free-solid";
// import { encryptStorage } from "./encrypt";
const Home = ({ setAuth }) => {
const [username, setUsername] = useState("");
const [user_id, setuserid] = useState("");
const [occ, setOcc] = useState([]);
// const [personalForm, setpersonalForm] = useState([]);//
// const [Pform, setform] = useState(false);
async function getUsername() {
try {
const response = await fetch("http://localhost:4001/home/", {
method: "GET",
//pass token with localstorage because it is stored in the header
headers: { token: localStorage.token },
});
const parseRes = await response.json();
// setpersonalForm(parseData);
setUsername(parseRes.username);
setuserid(parseRes.user_id); //
// const encryptStorage = new EncryptStorage('secret-key');
// encryptStorage.setItem("user_id", parseRes.user_id);
console.log(parseRes);
} catch (err) {
console.error(err.message);
}
try {
const response = await fetch("http://localhost:4001/results/occ", {
method: "GET",
//pass token with localstorage because it is stored in the header
headers: { token: localStorage.token },
});
const parseRes = await response.json();
// setpersonalForm(parseData);
setOcc(parseRes.data.occupationResults);
console.log(parseRes.data.occupationResults);
} catch (err) {
console.error(err.message);
}
}
//going to make a request when we get to this component, this is for getting from database
useEffect(() => {
getUsername();
}, []);
// const PIEDATAVALUES = occ.map((occupation) =>
// { "x"= occupation.occupation,
// "y"= occupation.values
// },
// );
// console.log(PIEDATAVALUES);
const result = [];
const piedataresults = occ.reduce((a, item) => {
result.push({ x: item.occupation, y: item.values });
return result;
}, []);
//console.log(piedataresults);
return (
<div>
<div className="container">
<div className="row">
<div className="col-md-4 col-sm-12 d-flex justify-content-center">
<div className="card-body text-center text-white">
<i className="fa-solid fa-bullseye fa-6x my-3 "></i>
<h2 className="card-title mb-4">Card Title</h2>
<p className="card-text">
Our Mission is to help the community out by helping people with
mental health issues
</p>
</div>
</div>
<div className="col-md-4 col-sm-12 d-flex justify-content-center">
<div className="card-body text-center text-white">
<i className="fa-solid fa-glasses fa-6x text-center my-3 "></i>
<h2 className="card-title mb-4">Card Title</h2>
<p className="card-text">
Our Mission is to help the community out by helping people with
mental health issues
</p>
</div>
</div>
<div className="col-md-4 col-sm-12 d-flex justify-content-center">
<div className="card-body text-center text-white pb-4">
<i className="fa-solid fa-hand-holding-medical fa-6x text-center my-3 "></i>
<h2 className="card-title mb-4">Card Title</h2>
<p className="card-text">
Our Mission is to help the community out by helping people with
mental health issues
</p>
</div>
</div>
</div>
</div>
<div className="row mb-5 " id="piechartrow">
<div
className="col-md-6 col-sm-12 text-white text-center "
id="pietext"
>
<p id="pietext">
It is a long established fact that a reader will be distracted by
the readable content of a page when looking at its layout. The point
of using Lorem Ipsum is that it has a more-or-less normal
distribution of letters, as opposed to using 'Content here, content
here', making it look like readable English.
</p>
</div>
<div className="col-md-6 col-sm-12 mt-3" id="piechartcol">
<svg viewBox="-15 -25 450 350" id="piechart">
<g transform={"translate(0, -75)"}>
<VictoryPie
colorScale={[
"#6680FF",
"#DFFF00",
"#DF4E4F",
"#FFB600",
"#eeaaaa",
"#23B936",
]}
name="pie"
width={350}
innerRadius={75}
standalone={false}
style={{
labels: { fill: "white", fontSize: 13, padding: 14 },
}}
data={piedataresults}
/>
</g>
</svg>
</div>
</div>
<div className="container-fluid">
<div className="row justify-content-around">
<div
className="card col-lg-5 col-md-6 col-sm-12 d-flex justify-content-center mb-5 "
id="CardOne"
>
<img
src={require("./pictures/ProPic.jpg")}
className="card-img-top"
id="pictureOne"
alt="..."
/>
<div className="card-body text-center text-white">
<h2 className="card-title mb-4">Alexey Aulov</h2>
<p className="card-text">
Hi my name is Alexey Aulov I am a senior at College of Staten
Island studying Information System and Informatics. I had the
original idea of Essential Health after I witnessed that
sometimes the best way for people to get mental help is to have
Therapist that can relate to you as much as possible to help you
out. Helping people gives me the most gratitude in life.
</p>
</div>
</div>
<div
className="card col-lg-5 col-md-6 col-sm-12 d-flex justify-content-center mb-5 "
id="CardTwo"
>
<img
src={require("./pictures/JLTwo.jpg")}
className="card-img-top"
alt="..."
id="pictureTwo"
/>
<div className="card-body text-center text-white">
<h2 className="card-title mb-4">Jonathan Leibovici</h2>
<p className="card-text">
Our Mission is to help the community out by helping people with
mental health issues
</p>
</div>
</div>
</div>
</div>
</div>
);
};
export default Home;

Why is this react component not displaying content loaded?

I'm working on this project and I want to display the content I got from the backend routes via axios to Showcase component. But the code doesn't give the output as expected the updated state console.log(cont) is working and no issue but it doesn't rendering contents.The app.js state is received by the component. I want to display the names. The child functional component as follows.
import React from 'react';
import {
Table,
Button
} from 'reactstrap';
function Showcase(props) {
const title = props.title;
const contents = props.contents;
let items_body = [];
items_body = contents.map(cont => {
console.log(cont)
if(cont.category === 'Men') {
return (
<div className="item_card" key={cont._id}>
<div className="itemC_right">
<div className="itemCR_topA">
<div className="itemCR_topA_title">{cont.name}</div>
</div>
</div>
</div>
)
}
else if(cont.category === 'Women') {
return (
<div className="lead content d-flex d-flex justify-content-center mb-3" key={cont.id}>
<div>Name : {cont.name}</div>
</div>
)
}
else if(cont.category === 'Kids') {
return (
<div className="lead content d-flex d-flex justify-content-center mb-3" key={cont.id}>
<div>Name : {cont.name}</div>
</div>
)
}
else
return (
null
)
})
return (
<div id="showcase">
<div id="showcase_card">
<div className="row">
<div className="col-sm-6 d-flex flex-row mt-1">
<h1 className="display-3 txt_secondary text-left" id="showcase_title">{title}</h1>
</div>
<div className="col-sm-6 d-flex flex-row-reverse mt-4">
<small className="txt_secondary text-right">Oreo is a online shopping store made just for you.</small>
</div>
</div>
<div>
{items_body}
</div>
</div>
</div>
)
}
export default Showcase;
The App.js class component
class App extends React.Component {
state = {
title: 'Oreo',
contents: []
}
changeState = (category,data) => {
this.setState({
title: category,
contents: data
})
}
handleNavigation = (e) => {
const option = e.target.innerHTML;
switch(option) {
case "Men":
axios.get('/api/items/men/2')
.then(res => {
this.changeState('Men',res.data);
// console.log(res.data)
})
break;
}
}
render() {
return (
<div>
<NavigationBar handleNavigation={this.handleNavigation} />
<Showcase title={this.state.title} contents={this.state.contents} />
<ItemWindow />
<BottomBar />
</div>
);
}
}
export default App;
In NavigationComponent.js when clicked on Men I'm sending it to App.js then it handles the click event. Why doesn't Showcase.js cannot show/render results? Help.
So I got rid of the if statements under the Showcase.js and could get my results. It seems that I was checking the category twice(in handleNavigation and here). I also added async and await as tonkalata's way.

Passing props a on button click

<Slider {...settings}>
{this.state.featuredMovies.map(movie =>
<div className="" key={movie._id}>
<Card inverse style={{padding: "10px", width: "90%"}}>
<CardImg src={`/files/${movie.thumbnail}`} alt="Card image cap" />
<CardImgOverlay className="movie-list-overlay">
<CardTitle>{movie.MovieName}</CardTitle>
<CardText>{movie.Description}</CardText>
<CardText>
<small>
<a href="watch">
<Button className="btn-fill btn-movie " color="primary" onClick={movie}>
Watch
</Button></a></small>
</CardText>
</CardImgOverlay>
</Card>
</div>
)}
</Slider>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
i want to pass the movie props on button click to the watch component so the watch component
class WatchMovies extends React.Component {
ComponentDidMount(){
const { player } = this.refs.player.getState();
}
handleDelete = e => {
console.log(this.refs.player.play())
}
handleD = e => {
const {player} = this.refs.player.getState()
console.log(player.currentTime)
console.log(this)
}
render() {
return (
<>
<div className="container-fluid bg-black">
<div className="col-md-12 mx-auto pt-5">
<Row className="" >
<div className="col-md-12 mx-auto py-5">
<Player
ref="player"
width="80%"
playsInline
poster="/assets/bg5.jpg"
src="https://media.w3.org/2010/05/sintel/trailer_hd.mp4"
position="center"
LoadingSpinner
onEnded={() => console.log("ended")}
/>
<Button onClick={this.handleDelete}>D </Button>
<Button onClick={this.handleD}>D </Button>
</div>
</Row>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
i want to pass the movie props on button click to the watch component so the watch component. Watch component is where you will be redirect to watch the movie you selected from the movielist component above
Your onClick needs to be a function
<Button onClick={() => this.doSomething(movie)} />
Then you can access the movie value in that function
const doSomething = (movie) => {
//Do some stuff with the movie
}

Vue.js - Working with Components

I am new to Vue.js. Very new so this question might sound a lot like a first graders. Forgive me.
I have the App.vue and Character.vue setup. I wanted to create characters on the fly and add them to an array (in App.vue) and let the rendering of the look/feel of the characters be done using Character.vue. The characters are created and added to the array and can be retrieved properly. Only thing is...Character.vue doesn't render them properly because for some reason, the character it retrieves from the array is undefined.
Help me?
Attaching files
App.vue
<template>
<div>
<div class='gameHeader'>
<h1>{{ gameHeader }}</h1>
</div>
<div class='gameMessages'>
<div class='gameMessage' v-for="msg in gameMessages">
{{ msg }}
</div>
</div>
<div class='gameMain'>
<button #click="rollNewCharacter">Roll New</button>
<div class="playerParty">
<character v-for="p in playerParty"></character>
</div>
<div class="computerParty">
<character v-for="c in computerParty"></character>
</div>
</div>
<div class='gameFooter'>
{{ gameFooter }}
</div>
</div>
</template>
<script>
import Character from "./assets/components/Character.vue";
export default {
components: { 'character': Character },
data: function(){ return { gameHeader: 'Monster Attack', gameMessages:[], playerParty: [], computerParty: [], gameFooter: '' }; },
methods: {
rollNewCharacter() {
var c = Character;
c.name = 'Usman';
c.type = 'Warrior';
c.mana = 100;
c.health = 100;
c.totalHealth = 100;
c.totalMana = 100;
console.log(c.name);
this.playerParty.push(c);
console.log(this.playerParty[0].name);
//this.computerParty.push(chr2);
}
}
}
</script>
Character.vue
<template>
<div class="character">
<span class='name'>{{ name }}</span><span class='type'>({{ type }})</span>
<div class='health'><div class='total' :class="totalHealth"><div class='health' :class="health"></div></div></div>
<div class='mana'><div class='total' :class="totalMana"><div class='mana' :class="mana"></div></div></div>
<span class='damage'>{{ damage }}</span>
<div class="actions">
<button #click="attack">Attack</button>
<button #click="specialAttack">Special Attack</button>
<button #click="heal">Heal</button>
</div>
</div>
</template>
<script>
export default {
props: [ 'name', 'type', 'mana', 'health', 'damage' , 'totalHealth', 'totalMana' ],
methods: {
attack: function(){},
specialAttack: function(){},
heal: function(){ alert(this.name); console.log(this);}
}
}
</script>
<style>
</style>
You should pass a prop when using the character component:
<character :character="p" v-for="p in playerParty"></character>
I have updated the character to receive only one prop:
export default {
props: [ 'character' ],
methods: {
attack: function(){},
specialAttack: function(){},
heal: function(){ alert(this.name); console.log(this);}
}
}
And this is the character component template with the new prop:
<template>
<div class="character">
<span class='name'>{{ character.name }}</span><span class='type'>({{ character.type }})</span>
<div class='health'><div class='total' :class="character.totalHealth"><div class='health' :class="character.health"></div></div></div>
<div class='mana'><div class='total' :class="character.totalMana"><div class='mana' :class="character.mana"></div></div></div>
<span class='damage'>{{ character.damage }}</span>
<div class="actions">
<button #click="attack">Attack</button>
<button #click="specialAttack">Special Attack</button>
<button #click="heal">Heal</button>
</div>
</div>
</template>

Resources