Ligonier Code Challenge.
This commit is contained in:
commit
86fa02eec9
21 changed files with 4912 additions and 0 deletions
14
app/ligonier/control_bar.tsx
Normal file
14
app/ligonier/control_bar.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
export function ControlBar({ isGallery, handleClick }) {
|
||||
return(
|
||||
<div className="hidden md:flex ml-auto">
|
||||
<button className="hover:bg-[#839b39] bg-[#789031] text-white p-2 rounded-lg mr-20 xl:mr-50 min-w-[130px]"
|
||||
onClick={handleClick}
|
||||
>
|
||||
{isGallery ? 'List' : 'Gallery'} View
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
15
app/ligonier/footer.tsx
Normal file
15
app/ligonier/footer.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
export function Footer() {
|
||||
return (
|
||||
<div className="flex justify-center">
|
||||
<div className="ml-10 mr-10 mb-5 md:ml-10 md:mr-10 flex flex-col max-w-[600px]">
|
||||
<strong className="font-libre">2 Corinthians 3:18</strong>
|
||||
<p className="font-libre">
|
||||
And we all, with unveiled face, beholding the glory of the Lord, are being transformed into the same image from one degree of glory to another. For this comes from the Lord who is the Spirit.
|
||||
</p>
|
||||
<strong className="font-libre mt-2 w-full text-center">
|
||||
<em>Soli Deo Gloria</em>
|
||||
</strong>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
14
app/ligonier/header.tsx
Normal file
14
app/ligonier/header.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { Logo } from "./logo";
|
||||
import { ControlBar } from "./control_bar"
|
||||
|
||||
export function Header({ isGallery, handleClick }) {
|
||||
return (
|
||||
<div className="header flex flex-row m-5 mr-10 md:mr-0 ml-10 md:ml-20 xl:ml-50 gap-5 items-center">
|
||||
<a href="https://www.ligonier.org">
|
||||
<Logo />
|
||||
</a>
|
||||
<h1 className="font-libre">Ligonier Code Challenge - Ben Nilsen</h1>
|
||||
<ControlBar isGallery={isGallery} handleClick={handleClick} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
8
app/ligonier/logo.tsx
Normal file
8
app/ligonier/logo.tsx
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export function Logo() {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" data-testid="icon-24-logo" role="img" aria-label="image-icon" fill="transparent" className="logo block fill-body-copy transition-colors group-hover:fill-cool-copy">
|
||||
<path fillRule="evenodd" d="M19.847 8.32c-2.354-3.467-5.173-6.317-7.61-7.233L12 1l-.239.087c-2.435.916-5.255 3.766-7.608 7.232C1.823 11.793.013 15.86 0 19.34c.004.741.432 1.325.95 1.75 1.57 1.26 4.464 1.889 6.767 1.91.473 0 .92-.03 1.33-.096 1.433-.243 2.547-.603 2.953-.585.407-.018 1.52.342 2.95.585.412.066.859.096 1.332.096a14.713 14.713 0 0 0 4.827-.861c.747-.28 1.414-.615 1.941-1.05.517-.425.945-1.009.95-1.75-.013-3.48-1.823-7.546-4.153-11.02zm-7.684-.638c-.1-.006-.235-.19-.235-.19l.078-1.034c.061-.804-.013-1.916.058-1.843.2.208.438 1.45.415 1.806-.023.357-.124 1.247-.316 1.26zm9.998 12.31c-1.03.891-3.872 1.612-5.879 1.59-.413 0-.793-.027-1.105-.078a13.74 13.74 0 0 1-.688-.13c-.235-.058-.904-.2-1.298-.771-.259-.375-.522-1.532.07-2.002.952-.758 1.89.145 3.053.013 2.791-.316 2.753-2.055 4.725-3.18-3.737-.992-6.825.257-7.523 1.654-.6 1.198-.913.706-.906.303l-.002-.944c0-.414.012-1.235.697-1.712.715-.501.89-.136 2.367-.254 2.128-.171 2.412-2.084 3.638-2.884-1.213.078-4.517-1.334-6.135 2.127-.106.227-.472.494-.602.741-.007-1.328-.06-1.733-.001-2.277.035-.336.27-1.18.676-1.254.32-.056 1.024-.111 1.398-.194.995-.221 2.167-1.365 2.108-2.952-.878.364-3.086-.322-3.987 2.348-.088.191-.23.6-.307.823.038-.35-.157-2.087-.057-2.777.085-.088 1.536-1.277.539-3.097-.426-.774-.95-1.7-.95-1.7s-.523.926-.947 1.7c-.998 1.82.462 3.018.547 3.105 0 0-.011 2.177-.039 2.35-.094.622-.379-.974-.794-1.507-.497-.642-1.002-.993-1.96-1.114-.565-.07-.627.011-1.589-.13 1.061 3.496 2.75 2.87 3.675 3.079.396.09.59 1.326.59 1.326.029-.222-.01 2.1.005 2.108-.721-.419-1.527-3.06-3.678-2.91-1.608.111-2.852-.012-2.946-.065 1.087 1.924 1.852 3.598 5.36 3.106.693-.099 1.131 1.02 1.14 1.255 0 0 .05 1.015-.027 1.74-.073.695-.492.104-.92-.342-.428-.447-2.041-2.152-4.802-1.74-1.538.23-1.338.16-2.645-.021.592.787 2.323 4.303 5.53 2.952 1.815-.764 3.089.434 2.392 2.194-.142.358-.627.703-1.405.91-.21.044-.425.086-.656.123a7.19 7.19 0 0 1-1.106.079c-1.342.001-3.045-.29-4.343-.775-.65-.239-1.196-.532-1.536-.815-.35-.293-.44-.517-.436-.654-.012-2.974 1.67-6.91 3.91-10.222C7.436 5.937 10.125 3.31 12 2.514c1.875.796 4.563 3.423 6.687 6.603 2.242 3.311 3.922 7.248 3.91 10.222.004.137-.086.36-.436.653zm-7.696-2.847c.002-.001.988-1.56 3.894-1.524.17.001.556.042.736.061 0 0 .041.053-.157.073-.865.117-2.852.94-3.313 1.151-.328.145-.938.426-1.146.43-.042 0-.059-.076-.014-.19zm3.152-5.107c-.129.196-2.282.576-3.699 1.659 0 0-.112-.07-.083-.137.946-1.777 3.24-1.542 3.782-1.522zm-4.239-1.926c.295-1.069 1.543-1.55 2.455-1.649l.17-.018c-.243.453-1.684.852-2.534 1.783 0 0-.113-.033-.09-.116zm-2.761-.17c0 .099-.122.08-.122.08s-1.153-.9-2.278-1.635c-.055-.022-.05-.068-.05-.068 1.355.135 2.339.934 2.45 1.623zm-.369 3.576c0 .054-.098.069-.098.069-.109-.008-.995-.49-1.713-.842-.883-.431-1.881-.69-1.881-.69 1.817-.203 2.94.29 3.58 1.233.068.104.104.153.112.23zm-5.324 2.588c.008-.059 1.086-.22 1.483-.22 2.117 0 3.16 1.2 3.181 1.29 0 .052-.08.08-.088.08-.247-.007-2.71-1.002-4.51-1.108 0 0-.064-.024-.066-.042z">
|
||||
</path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
30
app/ligonier/photo_card.tsx
Normal file
30
app/ligonier/photo_card.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
// A Card, rendering an image and toggling photographer information when clicked
|
||||
export function PhotoCard({ data }) {
|
||||
const [infoToggled, setInfoToggled] = useState(false);
|
||||
|
||||
function handleClick() {
|
||||
setInfoToggled(!infoToggled);
|
||||
}
|
||||
|
||||
if (data["id"] == 1) {
|
||||
console.log(data);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<div className="relative flex justify-center">
|
||||
<div onClick={handleClick} className="overflow-hidden rounded-2xl">
|
||||
<img className={`transition-blur duration-500 ease-in-out ${infoToggled ? 'blur-sm' : 'blur-none'}`}
|
||||
src={data["download_url"]}
|
||||
/>
|
||||
</div>
|
||||
<p className={`font-libre absolute self-center text-center bg-mist-500/70 p-2 rounded-lg text-white transition-opacity duration-500 ease-in-out ${infoToggled ? 'opacity-100' : 'opacity-0'}`}
|
||||
onClick={handleClick}
|
||||
>
|
||||
Photographer: {data['author']}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
36
app/ligonier/photo_gallery.tsx
Normal file
36
app/ligonier/photo_gallery.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { useLoaderData } from 'react-router';
|
||||
import { useState } from 'react';
|
||||
import { Header } from './header';
|
||||
import { Footer } from './footer';
|
||||
import { ControlBar } from './control_bar';
|
||||
import { PhotoCard } from './photo_card';
|
||||
|
||||
export function PhotoGallery({ numColumns }) {
|
||||
const imageData = useLoaderData();
|
||||
const [isGallery, setGallery] = useState(false);
|
||||
return (
|
||||
<div>
|
||||
<Header isGallery={isGallery} handleClick={()=> setGallery(!isGallery)} />
|
||||
<Photos
|
||||
imageData={imageData}
|
||||
isGallery={isGallery}
|
||||
/>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Photos({ imageData, isGallery}) {
|
||||
const listClassNames = "flex flex-wrap"
|
||||
const galleryClassNames = "grid md:grid-cols-2 xl:grid-cols-3"
|
||||
const photoCards = imageData.map(image =>
|
||||
<PhotoCard
|
||||
key={image.id}
|
||||
data={image}
|
||||
/>);
|
||||
return (
|
||||
<div className={`${isGallery ? galleryClassNames : listClassNames} md:m-20 md:mt-10 m-10 gap-10 mt-10 xl:ml-50 xl:mr-50`}>
|
||||
{photoCards}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue