I'm creating a component with a background being provided as a its attribute, like this:
<overlay-card src="https://static.pexels.com/photos/51387/mount-everest-himalayas-nuptse-lhotse-51387.jpeg" color="rgba-bluegrey-strong">
My component template:
`<div class="card card-image mb-3" style="background-image: url({{src}});" [ngClass]="(alignment==='left')?'text-left':(alignment==='right')?'text-right':'text-center'">
<div class="text-white d-flex py-5 px-4 {{color}}"
>
<ng-content></ng-content></div>
</div>`
What I get is:
// WARNING: sanitizing unsafe style value background-image: url(https://static.pexels.com/photos/51387/mount-everest-himalayas-nuptse-lhotse-51387.jpeg); (see http://g.co/ng/security#xss).
As it's a <div>, I cannot really count on [ngSrc].
You can use ngStyle for that:
<div [ngStyle]="{'background-image': 'url(' + src + ')'}">...</div>
You should make this url trusted in your component code and a litle bit change you component template like this:
import {DomSanitizer} from '#angular/platform-browser';
...
export class OverlayCard {
#Input() src: string;
constructor(private sanitizer: DomSanitizer) {
this.trustedSrc = sanitizer.bypassSecurityTrustUrl(this.src);
}
<div class="card card-image mb-3" style="background-image: url({{trustedSrc}});" [ngClass]="(alignment==='left')?'text-left':(alignment==='right')?'text-right':'text-center'">
<div class="text-white d-flex py-5 px-4 {{color}}">
<ng-content></ng-content>
</div>
</div>
Related
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>
My problem is I have created a sidebar but when I hide it using transform and translate, It hides in laptop but not in smaller devices.
I have used tailwind css
Mobile Device Problem screenshot
My code is:
import Image from "next/image";
import Link from "next/link";
import { AiOutlineShoppingCart, AiFillCloseCircle,AiOutlinePlusCircle,AiOutlineMinusCircle } from "react-icons/ai";
import { useRef } from "react";
const Navbar = () => {
const toggleCart = () => {
if (ref.current.classList.contains('translate-x-full')) {
ref.current.classList.remove('translate-x-full')
ref.current.classList.add('translate-x-0')
}
else if (!ref.current.classList.contains('translate-x-full')) {
ref.current.classList.remove('translate-x-0')
ref.current.classList.add('translate-x-full')
}
}
const ref = useRef()
return (
<div>
<header className="text-gray-600 body-font shadow-xl">
<div className="container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center">
<Link
href={"/"}
className="flex title-font font-medium items-center text-gray-900 mb-4 md:mb-0"
>
<a>
<Image src={"/mithanSweets.png"} height={45} width={256} />
</a>
</Link>
<nav className="md:ml-auto md:mr-auto flex flex-wrap items-center text-base justify-center">
<Link href={"/categories/burger"}>
<a className="mr-5 hover:text-gray-900">Burgers</a>
</Link>
<Link href={"/categories/italian"}>
<a className="mr-5 hover:text-gray-900">Italian</a>
</Link>
<Link href={"/categories/noodles"}>
<a className="mr-5 hover:text-gray-900">Noodles</a>
</Link>
<Link href={"/categories/pizza"}>
<a className="mr-5 hover:text-gray-900">Pizzas</a>
</Link>
</nav>
<div
onClick={toggleCart}
className=" cursor-pointer inline-flex items-center bg-gray-100 border-0 py-1 px-3 focus:outline-none hover:bg-gray-200 rounded text-base mt-4 md:mt-0"
>
<AiOutlineShoppingCart className="mr-3 text-2xl" />
Cart
</div>
</div>
<div
ref={ref}
className=" w-72 sideCart absolute top-0 right-0 bg-gray-200 px-8 py-10 transform transition-transform translate-x-full"
>
<h2 className="font-bold text-xl text-center">Shopping Cart</h2>
<span
onClick={toggleCart}
className="absolute top-5 right-2 cursor-pointer text-2xl text-gray-600"
>
<AiFillCloseCircle />
</span>
<ol className="list-decimal font-semibold">
<li>
<div className="item flex my-5">
<div className="w-2/3 font-semibold">Spicy Seafood Pasta</div>
<div className="w-1/3 font-semibold flex items-center justify-center text-lg"><AiOutlineMinusCircle className="cursor-pointer" /><span className="mx-2">1</span><AiOutlinePlusCircle className="cursor-pointer" /></div>
</div>
</li>
</ol>
</div>
</header>
</div>
);
};
export default Navbar;
And It is working fine in laptop device
Laptop screenshot
but not in inspect mode
Inspect mode screenshot
First thing you can do is to refresh the page. Secondly below is another approach, although its not the perfect solution but it works for me.
Solution
One thing you can do is that instead of translating you can hide and unhide the side bar like this
const toggleCart = () => {
if (ref.current.classList.contains("hidden")) {
ref.current.classList.remove("hidden");
ref.current.classList.add('block');
}
else if (!ref.current.classList.contains("hidden")) {
ref.current.classList.remove('block');
ref.current.classList.add('hidden');
}
}
And then change the sidecart as
<div
ref={ref}
className=" w-72 sideCart absolute top-0 right-0 bg-gray-200 px-8 py-10 transform transition-transform hidden"
>
<h2 className="font-bold text-xl text-center">Shopping Cart</h2>
<span
onClick={toggleCart}
className="absolute top-5 right-2 cursor-pointer text-2xl text-gray-600"
>
<AiFillCloseCircle />
</span>
<ol className="list-decimal font-semibold">
<li>
<div className="item flex my-5">
<div className="w-2/3 font-semibold">Spicy Seafood Pasta</div>
<div className="w-1/3 font-semibold flex items-center justify-center text-lg"><AiOutlineMinusCircle className="cursor-pointer" /><span className="mx-2">1</span><AiOutlinePlusCircle className="cursor-pointer" /></div>
</div>
</li>
</ol>
</div>
I would like to use two layouts for my Aurelia app.
Home - FAQ - Login page don't contain a sidebar;
But everything else do contain this sidebar.
My architecture, with a sidebar is pretty complicated in HTML and is like:
div.container
div.sidebar
div.sidebar_content
div.site_content
So i can't just enable or disable the sidebar because it contains the view.
I have to make two pages like "app.html", defined in main.js, but how tell to Aurelia "Choose app.html for this page, and app2.html for this other page"?
I have found the setRoot function but i have bugs with it (the routes does not work properly when i change setroot)
Thank you for your answers
The router supports the concept of "layouts." This is documented here: http://aurelia.io/hub.html#/doc/article/aurelia/router/latest/router-configuration/10
Basically, you specify a layout for each route (you can specify a default layout on the router-view custom element:
app.html
<router-view layout-view="./layout-with-sidebar.html"></router-view>
app.js
export class App {
configureRouter(config, router) {
config.title = 'Aurelia';
var model = {
id: 1
};
config.map([
{ route: ['home', ''], name: 'home', title: "Home", moduleId: 'home', nav: true },
{ route: 'no-sidebar', name: 'no-sidebar', title: "No Sidebar", moduleId: 'no-sidebar', nav: true, layoutView: 'layout-without-sidebar.html' }
]);
this.router = router;
}
}
layout-with-sidebar.html
<template>
<div class="container">
<div class="row">
<div class="col-sm-2">
<slot name="sidebar"></slot>
</div>
<div class="col-sm-10">
<slot name="main-content"></slot>
</div>
</div>
</div>
</template>
layout-without-sidebar.html
<template>
<div class="container">
<div class="row">
<div class="col-sm-12">
<slot name="main-content"></slot>
</div>
</div>
</div>
</template>
home.html
<template>
<div slot="sidebar">
<p>I'm content that will show up on the right.</p>
</div>
<div slot="main-content">
<p>I'm content that will show up on the left.</p>
</div>
</template>
no-sidebar.html
<template>
<div slot="main-content">
<p>Look ma! No sidebar!</p>
</div>
</template>
I'm newbie with Aurelia and frontend frameworks generally.
I have page with List
list.html
<template>
<require from="services/list-item"></require>
<div class="container-fluid">
<div class="row row-centered container-top-space">
<div repeat.for="item of items">
<list-item item.bind="item"></list-item>
</div>
</div>
</div>
</template>
list.js
import { inject } from 'aurelia-framework';
import { HttpClient, json } from 'aurelia-fetch-client';
#inject(HttpClient)
export class ListItem{
constructor(httpClient) {
this.items= [];
httpClient.configure(...);
}
}
and ListItem
list-item.html
<template>
<div class="row">
<div class="list-item">
<div class="form-control-inline" style="width:33%">
<span>${item.name} </span>
</div>
<div class="form-control-inline" style="width:54%">
<span>${item.value}</span>
</div>
<div class="pull-right" style="width:100px">
<button class="btn btn-list-item" type="submit" name="submit" click.delegate="edit($event.target.parentElement)">Edit</button>
</div>
</div>
</div>
</template>
list-item.js
import { bindable } from 'aurelia-framework';
export class ListItem{
#bindable item;
edit(element){
//I'd like to replace view component with update component here
}
}
I'd like to change template of list-item on list-item-edit when edit function will be called, but completely don't know how to make it.
I'm building a site with susy to allow flexibility with the grids I need, I have not set any settings at the moment so Im only using the defaults.
I want to be able to change the gutters (make them smaller) for a section of the site.
I built it out here:
http://sassmeister.com/gist/89243b68852fdd9cf282
SCSS
.feature-box-container
{
#include container(80em);
.feature-box
{
#include gallery(4 of 12);
img
{
margin-bottom:20px;
width: 100%;
}
}
}
HTML
<div class="feature-box-container container">
<div class="feature-box">
<!-- 450 -->
<div>
<img src="http://placehold.it/355x170" alt="">
</div>
<div>
<img src="http://placehold.it/355x280" alt="">
</div>
</div>
<div class="feature-box">
<div>
<img src="http://placehold.it/355x317" alt="">
</div>
<div>
<img src="http://placehold.it/355x133" alt="">
</div>
</div>
<div class="feature-box">
<div>
<img src="http://placehold.it/355x270" alt="">
</div>
<div>
<img src="http://placehold.it/355x180" alt="">
</div>
</div>
</div>
In the picture it has the sites default, but I need only this section to have at least half the gutter width it has now.
You can use the with-layout mixin to [change your grid settings for a nested block of code]](http://susydocs.oddbird.net/en/latest/settings/#with-layout).
#include with-layout($new-settings) {
// code you want affected...
}