Styling my contentful blog page on my website - api

I'm trying to style my blogs page for my website. I integrated my Contentful blog using API's and its all displayed correctly, but I just don't know how to target individual elements to style them individually. I would like to be able to
Style my main blogs page asa grid layout, attached is the specific grid layout I would like to achieve. I've also attached what my current main blogs page looks like now. I just don't know the code syntax to achieve this
I would like to style my individual (slug) blogs page simply adding space between each paragraphs, I jus don't know the code syntax to achieve this
I would like to be able to add tags to fetch the tags from my Contentful and display them on my blogs main page and on the individual slugs page
I've also attatched all the data that I have from contentful, could someone point me in the right direction for the syntax to use for the things I want to do? Thanks!
The grid layout I would like to achieve
My current grid layout
My blogs.js code
```import Navbar from "../components/Navbar/Navbar";
import Footer from "../components/Footer/Footer";
import { createClient } from "contentful";
import BlogCard from "../components/BlogCard/BlogCard";
export async function getStaticProps() {
const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
previewacessToken: process.env.PREVIEW_ACCESS_TOKEN,
});
const res = await client.getEntries({ content_type: "menuItem" });
return {
props: {
blog: res.items,
},
};
}
export default function Blog({ blog }) {
console.log(blog);
return (
<div>
<div className="bg-[#F5f5f5] pt-16">
<div className="flex flex-col">
<header>
{" "}
<Navbar />
</header>
<main className="flex-1">
<div className="relative left-1/2 mt-12 min-w[100vw] translate-x-[-50%]">
<div className="relative mx-auto pb-30 lg:pb-30">
<div className="px-6 md:px-8.5 lg:px-40">
<div className="mx-auto max-w-container">
<div className="max-md:w-screen max-md:pr-5">
<div className="grid grid-cols-2 grid-rows-2 gap-10 mt-24 mb-32 h-full sm:grid-cols-2 sm:h-full sm:w-full md:mb-24 md:w-full max-lg:block max-md:mt-16">
{blog.map((menuItem) => (
<BlogCard key={menuItem.sys.id} menuItem={menuItem} />
))}
</div>
</div>
</div>
<Footer />
</div>
</div>
</div>
</main>
</div>
</div>
</div>
);
}```
My slug.js code
``` return (
<div>
<div className="bg-[#F5f5f5] pt-16">
<div className="flex flex-col">
<header>
<Navbar />
</header>
<main className="flex-1">
<div className="relative left-1/2 mt-12 min-w[100vw] translate-x-[-50%]">
<div className="relative mx-auto pb-30 lg:pb-30">
<div className="px-6 md:px-8.5 lg:px-40">
<div className="mx-auto max-w-container">
<div className="py-24 px-40 mx-auto leading-7 text-center0 md:mx-auto max-lg:px-0 max-md:px-0 max-md:py-16">
<p>{date}</p>
<p className="leading-7 text-left pb-10 max-md:-mb-5">
{author}
</p>
<h1 className="pb-20 w-full max-w-full h-auto text-5xl font-bold text-left md:w-full">
{title}
</h1>
<Image
className="pb-20 w-full max-w-full h-auto leading-7 max-md:-mt-8 max-md:pb-5"
src={"https:" + image.fields.file.url}
width={image.fields.file.details.image.width}
height={image.fields.file.details.image.height}
alt=""
/>
<div>
<div>{documentToReactComponents(text)}</div>
<div className="pb-10">
{documentToReactComponents(text.content.paragraph)}
</div>
</div>
</div>
<Footer />
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</div>
);
}
```
My Individual blog card code
````export function BlogCard({ menuItem }) {
const { title, slug, date, author, image, shortDescription } =
menuItem.fields;
return (
<Link href={"/Blogs/" + slug}>
<div>
<Image
src={"https:" + image.fields.file.url}
width={image.fields.file.details.image.width}
height={image.fields.file.details.image.height}
alt=""
/>
</div>
<div className="mr-auto">
<div className="content">
<div className="info">
<h2>{title}</h2>
<p className="pb-5">{shortDescription}</p>
<p className="pb-2">{date}</p>
<p>{author}</p>
</div>
</div>
</div>
</Link>
);
}
export default BlogCard;```

Related

AxiosError: Request failed with status code 403

I tried using this api-key provided by RapidAPI for my code. I made sure that the API key entered is correct. I was previously using the .env file,'X-RapidAPI-Host': process.env.COIN_RANKING_HOST, for both the api host and api key but to make sure that the error is not caused by the .env file not loading, I entered both directly. This is my code:
import Header from '../components/Header'
import PortfolioChart from '../components/PortfolioChart'
import BuyTokens from '../components/BuyTokens'
import Notice from '../components/Notice'
import Asset from '../components/Asset'
import { BiDotsHorizontalRounded } from 'react-icons/bi'
import { AiOutlinePlus } from 'react-icons/ai'
import axios from 'axios'
const styles = {
wrapper: 'w-screen h-screen flex flex-col',
mainContainer: 'w-2/3 h-full m-auto flex mt-16',
leftMain: 'flex flex-col w-3/4 h-full p-6 overflow-y-scroll',
portfolioAmountContainer: 'flex flex-col ',
portfolioAmount: 'text-white text-4xl',
portfolioPercent: 'text-white font-bold text-sm',
pastHour: 'text-gray-400',
chartContainer:
'text-5xl flex justify-center w-full h-1/3 text-white mt-11 mb-11',
buyingPowerContainer:
'w-full border-t mb-24 border-b h-16 border-[#30363b] flex justify-between items-center p-4',
buyingPowerTitle: 'text-white font-bolder text-lg',
buyingPowerAmount: 'text-white font-bolder text-xl',
notice: 'flex border border-[#30363b] mx-11 my-4 p-5 flex-col flex-1',
noticeContainer: 'flex-1',
noticeTitle: 'text-gray-500',
noticeMessage: 'text-white font-bold',
noticeCTA: 'font-bold text-green-500 cursor-pointer mt-5',
rightMain:
'flex flex-col flex-1 h-4/5 bg-[#1E2123] mt-6 rounded-lg overflow-y-scroll noScroll',
rightMainItem: 'flex items-center text-white p-5 border-b border-[#30363b]',
ItemTitle: 'flex-1 font-bold',
moreOptions: 'cursor-pointer text-xl',
}
export default function Home({coins}) {
console.log(coins)
return(
<div className={styles.wrapper}>
<Header />
<div className={styles.mainContainer}>
<div className={styles.leftMain}>
<div className={styles.portfolioAmountContainer}>
<div className={styles.portfolioAmount}>
23 SOLANA
</div>
<div className={styles.portfolioPercent}>
+0.0008(+0.57%)
<span className={styles.pastHour}>
Past Hour
</span>
</div>
</div>
<div>
<div className={styles.chartContainer}>
<PortfolioChart />
</div>
</div>
<div className={styles.buyingPowerContainer}>
<div className={styles.buyingPowerTitle}>Buying Power</div>
<div className={styles.buyingPowerAmount}>12 SOLANA</div>
</div>
<div className={styles.notice}>
<div className={styles.noticeContainer}>
<div className={styles.noticeTitle}>
Send Funds
</div>
<div className={styles.noticeMessage}>
Transfer your funds here.
</div>
<BuyTokens />
</div>
</div>
<Notice />
</div>
<div className={styles.rightMain}>
<div className={styles.rightMainItem}>
<div className={styles.ItemTitle}>
Crypto Currencies
</div>
<BiDotsHorizontalRounded className={styles.moreOptions} />
</div>
<Asset coin={"BTC"} price={0.89} />
<Asset coin={"SOL"} price={0.90} />
<Asset coin={"ETH"} price={-1} />
<Asset coin={"USDC"} price={2} />
<div className={styles.rightMain}>
<div className={styles.ItemTitle}>
Lists
</div>
<AiOutlinePlus className={styles.moreOptions} />
</div>
</div>
</div>
</div>
)
}
export const getStaticProps = async () => {
const options = {
method: 'GET',
url: 'https://coinranking1.p.rapidapi.com/coins',
params: {
referenceCurrencyUuid: 'yhjMzLPhuIDl',
timePeriod: '24h',
tiers: '1',
orderBy: 'marketCap',
orderDirection: 'desc',
limit: '50',
offset: '0',
},
headers: {
'X-RapidAPI-Host': 'coinranking1.p.rapidapi.com',
'X-RapidAPI-Key': '23734db4e2msha5580c4a7b981c0p1557d0jsn9c9dcf2b8505',
},
}
const res = await axios.request(options)
const coins = res.data.data.coins
return {
props: { coins },
}
}
The error showing in the terminal is this.The error was very lengthy and I couldn't post the entire error due to character limit. I have put up the initial two lines and the last two lines of the error though.
error - [AxiosError: Request failed with status code 403] {
code: 'ERR_BAD_REQUEST',
...
data: { message: 'You are not subscribed to this API.' }
},
page: '/'
}
I am unable to figure out why I am getting this error. Please help.
I am subscribed to RapidAPI.

Variable interpolation inside nested quotations in React JSX

I am new in react, don't know how to display photo inside nested quotations, I know the usages of
Variable interpolation inside single quote: {assets/images/categories/${photo}} but don't know how to make dynamic cat-2.jpg
const AllItems = ({ post: { id, name, type, photo } }) => {
return (
<div className="col-lg-2 col-md-2 col-sm-4 col-xs-6">
<div className="product__discount__item">
<div
className="product__discount__item__pic set-bg"
style={{
backgroundImage: "url('assets/images/categories/cat-2.jpg')"
}}
>
<div className="product__discount__percent">-20%</div>
</div>
<div className="product__discount__item__text">
<span>{name}</span>
</div>
</div>
</div>
);
};
I have solved using variable
const AllItems = ({ post: { id, name, type, photo } }) => {
const imgPath = `assets/images/categories/${photo}`;
return (
<div className="col-lg-2 col-md-2 col-sm-4 col-xs-6">
<div className="product__discount__item">
<div
className="product__discount__item__pic set-bg"
style={{
backgroundImage: `url(${imgPath})`
}}
>
<div className="product__discount__percent">-20%</div>
</div>
<div className="product__discount__item__text">
<span>{name}</span>
</div>
</div>
</div>
);
};

How can I make my section hide only after the submit button is pressed. right now the section disappears after I press one letter

vue.js, how can I make my section hide only after the submit button is pressed. right now the section disappears after I press one letter. I want the V-if and V-else to activate only after the user has submitted their request. or if routing the results on to a different page would easier id like to go that route also.
<template>
<div class="home">
<section id="whiteClawVideo" class="videoWrapper d-block w-100">
<div class="video-container fluid">
<iframe width="100%" height="600" src="https://www.youtube.com/embed/JORN2hkXLyM?
autoplay=1&loop=1" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope;
picture-in-picture" allowfullscreen></iframe>
</div>
</section>
<form #submit.prevent="SearchMovies()" class="search-box">
<input type="text" placeholder="What are you looking for? " v-model="search" />
<input type="submit" value="Search">
</form>
<div class="movies-list" v-if="search !== ''" >
<div class="container">
<div class="row">
<div class="col-3" v-for="movie in movies" :key="movie.imdbID">
<router-link :to="'/movie/'+movie.imdbID" class="movie-link">
<img class="movieImg" height="100%" :src="movie.Poster" alt="Movie Poster" />
<div class="type">{{ movie.Type }}</div>
<div class="detail">
<p class="year">{{movie.Year}}</p>
<h3>{{ movie.Title }}</h3>
<p>{{movie.imdbID}}</p>
</div>
</router-link>
</div>
</div>
</div>
</div>
<div class="container" v-else>
<MovieSection />
<SecondMovieSection />
</div>
</div>
</template>
import { ref } from 'vue';
import env from '#/env.js';
import MovieSection from '#/components/MovieSection.vue';
import SecondMovieSection from '#/components/SecondMovieSection.vue'
export default {
components: {
MovieSection,
SecondMovieSection
},
setup () {
const search = ref("");
const movies = ref([]);
const SearchMovies = () => {
if (search.value !== "") {
fetch(`API_HERE`)
.then(response => response.json())
.then(data => {
console.log(data)
movies.value = data.Search;
})
}
}
return {
search,
movies,
SearchMovies
}
}
}
Well, it closes once you type a single character because search is a model - it updates on every keypress you do within input it's bound to. What you wanna do instead is hide form based on whether you have entries in your movies array or not, so try changing v-if="search !== ''" to v-if="!movies.length"

MeiliSearch — change the limit of 20 documents

I'm new to MeiliSearch and trying to set up a simple demo. It is very similar to this official demo. I'm wondering how could I change the default limit of 20 documents in the app?
This can be done with <ais-configure :hitsPerPage="50" />. For example:
<div class="search-panel__results">
<ais-search-box placeholder="Search here…" autofocus/>
<ais-hits :transform-items="transformItems">
<template slot="item" slot-scope="{ item }">
<ais-configure :hitsPerPage="50" />
<div>
<div class="hit-info">🏅 {{ item.year }}</div>
<div class="hit-info">
<ais-highlight :hit="item" attribute="firstname" />
<ais-highlight :hit="item" attribute="surname" />
</div>
<div class="hit-info motivation">
<ais-highlight :hit="item" attribute="motivation" />
</div>
</div>
</template>
</ais-hits>
<ais-pagination />
</div>
To change the default pagination limit off 200 hits, in the App.vue file (from the referenced official demo) update the data section to the following (setting paginationTotalHits to the number you want):
data() {
return {
searchClient: instantMeiliSearch(
MEILISEARCH_HOST,
MEILISEARCH_API_KEY,
{
paginationTotalHits: 300, // default: 200.
}
),
};
},

VUE's focus() method return a console error? How to use it correctly?

I'm trying to focus on several elements of my form but the first one, despite being applied, returns an error by console.
This is my template:
<div class="container">
<div class="col-xs-12">
<div class="row">
<h1 class="animal-title">Your selection is : </h1>
</div>
<div class="wrapper">
<form class="first-form" #submit.prevent="onSubmit">
<div class="image-wrapper">
<div class="sel-image">
<div v-on:click="imageSelected = true" v-for="item in items" v-bind:key="item.id">
<label>
<input
type="radio"
name="selectedItem"
ref="item"
:value="item.id"
v-model="itemFormInfo.selectedItem"
#change="onChangeItem($event)"
/>
<img v-if="item.id === 1" src="../../assets/1.png" />
<img v-if="item.id === 2" src="../../assets/2.png" />
<img v-if="item.id === 3" src="../../assets/3.png" />
</label>
<p class="cie-animal-subtitle">{{item.name}}</p>
</div>
</div>
</div>
<div class="form-select">
<div v-show="filteredStock && (imageSelected || itemFormInfo.selectedItem) > 0">
<h1 v-if="this.itemName === 'Phone' || this.itemName === 'Tablet'" for="selectedItem" ref="itemVisible">
Select the brand of your <span>{{this.itemName}}</span> :
</h1>
<h1 v-if="this.itemName === 'PC'" for="selectedBreed" ref="itemVisible">
Select the type of your <span>{{this.itemName}}</span> :
</h1>
<select
ref="brand"
class="form-control"
id="selectedBrand"
v-model="itemFormInfo.selectedBrand"
#change="onChangeBrand($event)">
<option v-for="brand in filteredBrand" v-bind:key="brand.name">{{ brand.name }}</option>
</select>
<div v-show="this.isBrandSelected">
<h1>What are you going to use your
<span>{{itemName}}</span> for ?
</h1>
<input
type="text"
id="componentName"
ref="componentName"
class="form-control fields"
style="text-transform: capitalize"
v-model="itemFormInfo.component"
#keypress="formChange($event)"
/>
<div class="loader-spinner" v-if="loading">
<app-loader/>
</div>
</div>
</div>
</div>
<div class="service-options" v-show="isComponentCompleted">
<div class="from-group">
<h1>
Here are the options for your <span>{{this.itemFormInfo.component}}</span> :
</h1>
<div class="services">
<div class="column-service" v-for="option in options" v-bind:key="option.name">
<div class="service-name">{{option.name}}</div>
<div class="service-price">{{option.price.toString().replace(".", ",")}} </div>
</div>
</div>
and here my first method
onChangeItem(event) {
let item = event.target._value;
this.itemName = this.getItemName(item);
if (this.isItemSelected = true) {
this.isItemSelected = false;
this.isComponentCompleted = false;
this.isLoaderFinished = false;
this.itemFormInfo.name = ""
}
this.$refs.item.focus();
},
in this function that I control my first input, the focus is working but it returns me by console the following error:
"this.$refs.item.focus is not a function at VueComponent.onChangeItem"
I have seen some references to similar cases where they involved the reference in a setTimeout or used the this.$nextTick(() => method but it didn't work in my case.
What am I doing wrong?
How can I focus on the next select with ref brand, once I have chosen the value of the first input?
Thank you all for your time and help in advance
How can I focus on the next select with ref brand, once I have chosen the value of the first input?
You want to put focus on brand but your onChangeItem handler is calling this.$refs.item.focus() (trying to focus item). Seems strange to me...
Reason for the error is you are using ref inside v-for.
Docs: When used on elements/components with v-for, the registered reference will be an Array containing DOM nodes or component instances
So the correct way for accessing item ref will be this.$refs.item[index].focus().
Just be aware that right now v-for refs do not guarantee the same order as your source Array - you can find some workarounds in the issue discussion...