aboutsummaryrefslogtreecommitdiff
path: root/examples/portfolio/src/pages
diff options
context:
space:
mode:
Diffstat (limited to 'examples/portfolio/src/pages')
-rw-r--r--examples/portfolio/src/pages/404.astro8
-rw-r--r--examples/portfolio/src/pages/about.astro120
-rw-r--r--examples/portfolio/src/pages/index.astro252
-rw-r--r--examples/portfolio/src/pages/work.astro39
-rw-r--r--examples/portfolio/src/pages/work/[...slug].astro152
5 files changed, 571 insertions, 0 deletions
diff --git a/examples/portfolio/src/pages/404.astro b/examples/portfolio/src/pages/404.astro
new file mode 100644
index 000000000..e3995899a
--- /dev/null
+++ b/examples/portfolio/src/pages/404.astro
@@ -0,0 +1,8 @@
+---
+import Hero from '../components/Hero.astro';
+import BaseLayout from '../layouts/BaseLayout.astro';
+---
+
+<BaseLayout title="Not Found" description="404 Error — this page was not found">
+ <Hero title="Page Not Found" tagline="Not found" />
+</BaseLayout>
diff --git a/examples/portfolio/src/pages/about.astro b/examples/portfolio/src/pages/about.astro
new file mode 100644
index 000000000..14e34ba81
--- /dev/null
+++ b/examples/portfolio/src/pages/about.astro
@@ -0,0 +1,120 @@
+---
+import BaseLayout from '../layouts/BaseLayout.astro';
+
+import ContactCTA from '../components/ContactCTA.astro';
+import Hero from '../components/Hero.astro';
+---
+
+<BaseLayout title="About | Jeanine White" description="About Jeanine White Lorem Ipsum">
+ <div class="stack gap-20">
+ <main class="wrapper about">
+ <Hero
+ title="About"
+ tagline="Thanks for stopping by. Read below to learn more about myself and my background."
+ >
+ <img
+ width="1553"
+ height="873"
+ src="/assets/at-work.jpg"
+ alt="Jeanine White at work with a colleague"
+ />
+ </Hero>
+
+ <section>
+ <h2 class="section-title">Background</h2>
+ <div class="content">
+ <p>
+ Lorem ipsum dolor sit amet, <a href="https://astro.build/">Astro</a> makes people happy.
+ Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Proin nibh nisl condimentum
+ id venenatis a condimentum vitae. Dapibus ultrices in iaculis nunc. Arcu odio ut sem nulla
+ pharetra diam sit amet. Diam quis enim lobortis scelerisque fermentum dui faucibus in ornare.
+ </p>
+ <p>
+ Arcu dui vivamus arcu felis bibendum ut tristique et egestas. Eget gravida cum sociis
+ natoque penatibus. Cras fermentum odio eu feugiat pretium nibh. Proin nibh nisl
+ condimentum id venenatis. Porta nibh venenatis cras sed felis eget velit. Id diam vel
+ quam elementum pulvinar etiam non.
+ </p>
+ <p>
+ Ultrices tincidunt arcu non sodales neque sodales ut. Sed enim ut sem viverra aliquet
+ eget sit amet. Lacus luctus accumsan tortor posuere ac ut consequat semper viverra.
+ Viverra accumsan in nisl nisi scelerisque eu ultrices. In massa tempor nec feugiat nisl
+ pretium fusce.
+ </p>
+ </div>
+ </section>
+ <section>
+ <h2 class="section-title">Education</h2>
+ <div class="content">
+ <p>Corporis voluptates tenetur laudantium.</p>
+ </div>
+ </section>
+ <section>
+ <h2 class="section-title">Skills</h2>
+ <div class="content">
+ <p>officia unde omnis</p>
+ </div>
+ </section>
+ </main>
+
+ <ContactCTA />
+ </div>
+</BaseLayout>
+
+<style>
+ .about {
+ display: flex;
+ flex-direction: column;
+ gap: 3.5rem;
+ }
+
+ img {
+ margin-top: 1.5rem;
+ border-radius: 1.5rem;
+ box-shadow: var(--shadow-md);
+ }
+
+ section {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ color: var(--gray-200);
+ }
+
+ .section-title {
+ grid-column-start: 1;
+ font-size: var(--text-xl);
+ color: var(--gray-0);
+ }
+
+ .content {
+ grid-column: 2 / 4;
+ }
+
+ .content :global(a) {
+ text-decoration: 1px solid underline transparent;
+ text-underline-offset: 0.25em;
+ transition: text-decoration-color var(--theme-transition);
+ }
+
+ .content :global(a:hover),
+ .content :global(a:focus) {
+ text-decoration-color: currentColor;
+ }
+
+ @media (min-width: 50em) {
+ .about {
+ display: grid;
+ grid-template-columns: 1fr 60% 1fr;
+ }
+
+ .about > :global(:first-child) {
+ grid-column-start: 2;
+ }
+
+ section {
+ display: contents;
+ font-size: var(--text-lg);
+ }
+ }
+</style>
diff --git a/examples/portfolio/src/pages/index.astro b/examples/portfolio/src/pages/index.astro
new file mode 100644
index 000000000..5f67e3860
--- /dev/null
+++ b/examples/portfolio/src/pages/index.astro
@@ -0,0 +1,252 @@
+---
+import { getCollection } from 'astro:content';
+
+// Layout import — provides basic page elements: <head>, <nav>, <footer> etc.
+import BaseLayout from '../layouts/BaseLayout.astro';
+
+// Component Imports
+import CallToAction from '../components/CallToAction.astro';
+import Grid from '../components/Grid.astro';
+import Hero from '../components/Hero.astro';
+import Icon from '../components/Icon.astro';
+import Pill from '../components/Pill.astro';
+import PortfolioPreview from '../components/PortfolioPreview.astro';
+
+// Page section components
+import ContactCTA from '../components/ContactCTA.astro';
+import Skills from '../components/Skills.astro';
+
+// Content Fetching: List four most recent work projects
+const projects = (await getCollection('work'))
+ .sort((a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf())
+ .slice(0, 4);
+
+// Full Astro Component Syntax:
+// https://docs.astro.build/basics/astro-components/
+---
+
+<BaseLayout>
+ <div class="stack gap-20 lg:gap-48">
+ <div class="wrapper stack gap-8 lg:gap-20">
+ <header class="hero">
+ <Hero
+ title="Hello, my name is Jeanine White"
+ tagline="I am a Creative Developer who is currently based in Portland, Oregon."
+ align="start"
+ >
+ <div class="roles">
+ <Pill><Icon icon="code" size="1.33em" /> Developer</Pill>
+ <Pill><Icon icon="microphone-stage" size="1.33em" /> Speaker</Pill>
+ <Pill><Icon icon="pencil-line" size="1.33em" /> Writer</Pill>
+ </div>
+ </Hero>
+
+ <img
+ alt="Jeanine White smiling in a red plaid shirt and tortoise shell glasses"
+ width="480"
+ height="620"
+ src="/assets/portrait.jpg"
+ />
+ </header>
+
+ <Skills />
+ </div>
+
+ <main class="wrapper stack gap-20 lg:gap-48">
+ <section class="section with-background with-cta">
+ <header class="section-header stack gap-2 lg:gap-4">
+ <h3>Selected Work</h3>
+ <p>Take a look below at some of my featured work for clients from the past few years.</p>
+ </header>
+
+ <div class="gallery">
+ <Grid variant="offset">
+ {
+ projects.map((project) => (
+ <li>
+ <PortfolioPreview project={project} />
+ </li>
+ ))
+ }
+ </Grid>
+ </div>
+
+ <div class="cta">
+ <CallToAction href="/work/">
+ View All
+ <Icon icon="arrow-right" size="1.2em" />
+ </CallToAction>
+ </div>
+ </section>
+
+ <section class="section with-background bg-variant">
+ <header class="section-header stack gap-2 lg:gap-4">
+ <h3>Mentions</h3>
+ <p>
+ I have been fortunate enough to receive praise for my work in several publications. Take
+ a look below to learn more.
+ </p>
+ </header>
+
+ <div class="gallery">
+ <Grid variant="small">
+ {
+ ['Medium', 'BuzzFeed', 'The Next Web', 'awwwards.', 'TechCrunch'].map((brand) => (
+ <li class="mention-card">
+ <p>{brand}</p>
+ </li>
+ ))
+ }
+ </Grid>
+ </div>
+ </section>
+ </main>
+
+ <ContactCTA />
+ </div>
+</BaseLayout>
+
+<style>
+ .hero {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 2rem;
+ }
+
+ .roles {
+ display: none;
+ }
+
+ .hero img {
+ aspect-ratio: 5 / 4;
+ object-fit: cover;
+ object-position: top;
+ border-radius: 1.5rem;
+ box-shadow: var(--shadow-md);
+ }
+
+ @media (min-width: 50em) {
+ .hero {
+ display: grid;
+ grid-template-columns: 6fr 4fr;
+ padding-inline: 2.5rem;
+ gap: 3.75rem;
+ }
+
+ .roles {
+ margin-top: 0.5rem;
+ display: flex;
+ gap: 0.5rem;
+ }
+
+ .hero img {
+ aspect-ratio: 3 / 4;
+ border-radius: 4.5rem;
+ object-fit: cover;
+ }
+ }
+
+ /* ====================================================== */
+
+ .section {
+ display: grid;
+ gap: 2rem;
+ }
+
+ .with-background {
+ position: relative;
+ }
+
+ .with-background::before {
+ --hero-bg: var(--bg-image-subtle-2);
+
+ content: '';
+ position: absolute;
+ pointer-events: none;
+ left: 50%;
+ width: 100vw;
+ aspect-ratio: calc(2.25 / var(--bg-scale));
+ top: 0;
+ transform: translateY(-75%) translateX(-50%);
+ background:
+ url('/assets/backgrounds/noise.png') top center/220px repeat,
+ var(--hero-bg) center center / var(--bg-gradient-size) no-repeat,
+ var(--gray-999);
+ background-blend-mode: overlay, normal, normal, normal;
+ mix-blend-mode: var(--bg-blend-mode);
+ z-index: -1;
+ }
+
+ .with-background.bg-variant::before {
+ --hero-bg: var(--bg-image-subtle-1);
+ }
+
+ .section-header {
+ justify-self: center;
+ text-align: center;
+ max-width: 50ch;
+ font-size: var(--text-md);
+ color: var(--gray-300);
+ }
+
+ .section-header h3 {
+ font-size: var(--text-2xl);
+ }
+
+ @media (min-width: 50em) {
+ .section {
+ grid-template-columns: repeat(4, 1fr);
+ grid-template-areas: 'header header header header' 'gallery gallery gallery gallery';
+ gap: 5rem;
+ }
+
+ .section.with-cta {
+ grid-template-areas: 'header header header cta' 'gallery gallery gallery gallery';
+ }
+
+ .section-header {
+ grid-area: header;
+ font-size: var(--text-lg);
+ }
+
+ .section-header h3 {
+ font-size: var(--text-4xl);
+ }
+
+ .with-cta .section-header {
+ justify-self: flex-start;
+ text-align: left;
+ }
+
+ .gallery {
+ grid-area: gallery;
+ }
+
+ .cta {
+ grid-area: cta;
+ }
+ }
+
+ /* ====================================================== */
+
+ .mention-card {
+ display: flex;
+ height: 7rem;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ border: 1px solid var(--gray-800);
+ border-radius: 1.5rem;
+ color: var(--gray-300);
+ background: var(--gradient-subtle);
+ box-shadow: var(--shadow-sm);
+ }
+
+ @media (min-width: 50em) {
+ .mention-card {
+ border-radius: 1.5rem;
+ height: 9.5rem;
+ }
+ }
+</style>
diff --git a/examples/portfolio/src/pages/work.astro b/examples/portfolio/src/pages/work.astro
new file mode 100644
index 000000000..233c760bf
--- /dev/null
+++ b/examples/portfolio/src/pages/work.astro
@@ -0,0 +1,39 @@
+---
+import { getCollection } from 'astro:content';
+
+import BaseLayout from '../layouts/BaseLayout.astro';
+
+import ContactCTA from '../components/ContactCTA.astro';
+import PortfolioPreview from '../components/PortfolioPreview.astro';
+import Hero from '../components/Hero.astro';
+import Grid from '../components/Grid.astro';
+
+const projects = (await getCollection('work')).sort(
+ (a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf(),
+);
+---
+
+<BaseLayout
+ title="My Work | Jeanine White"
+ description="Learn about Jeanine White's most recent projects"
+>
+ <div class="stack gap-20">
+ <main class="wrapper stack gap-8">
+ <Hero
+ title="My Work"
+ tagline="See my most recent projects below to get an idea of my past experience."
+ align="start"
+ />
+ <Grid variant="offset">
+ {
+ projects.map((project) => (
+ <li>
+ <PortfolioPreview project={project} />
+ </li>
+ ))
+ }
+ </Grid>
+ </main>
+ <ContactCTA />
+ </div>
+</BaseLayout>
diff --git a/examples/portfolio/src/pages/work/[...slug].astro b/examples/portfolio/src/pages/work/[...slug].astro
new file mode 100644
index 000000000..90eb3ba8d
--- /dev/null
+++ b/examples/portfolio/src/pages/work/[...slug].astro
@@ -0,0 +1,152 @@
+---
+import { type CollectionEntry, getCollection } from 'astro:content';
+
+import BaseLayout from '../../layouts/BaseLayout.astro';
+
+import ContactCTA from '../../components/ContactCTA.astro';
+import Hero from '../../components/Hero.astro';
+import Icon from '../../components/Icon.astro';
+import Pill from '../../components/Pill.astro';
+import { render } from 'astro:content';
+
+interface Props {
+ entry: CollectionEntry<'work'>;
+}
+
+// This is a dynamic route that generates a page for every Markdown file in src/content/
+// Read more about dynamic routes and this `getStaticPaths` function in the Astro docs:
+// https://docs.astro.build/en/core-concepts/routing/#dynamic-routes
+export async function getStaticPaths() {
+ const work = await getCollection('work');
+ return work.map((entry) => ({
+ params: { slug: entry.id },
+ props: { entry },
+ }));
+}
+
+const { entry } = Astro.props;
+const { Content } = await render(entry);
+---
+
+<BaseLayout title={entry.data.title} description={entry.data.description}>
+ <div class="stack gap-20">
+ <div class="stack gap-15">
+ <header>
+ <div class="wrapper stack gap-2">
+ <a class="back-link" href="/work/"><Icon icon="arrow-left" /> Work</a>
+ <Hero title={entry.data.title} align="start">
+ <div class="details">
+ <div class="tags">
+ {entry.data.tags.map((t) => <Pill>{t}</Pill>)}
+ </div>
+ <p class="description">{entry.data.description}</p>
+ </div>
+ </Hero>
+ </div>
+ </header>
+ <main class="wrapper">
+ <div class="stack gap-10 content">
+ {entry.data.img && <img src={entry.data.img} alt={entry.data.img_alt || ''} />}
+ <div class="content">
+ <Content />
+ </div>
+ </div>
+ </main>
+ </div>
+ <ContactCTA />
+ </div>
+</BaseLayout>
+
+<style>
+ header {
+ padding-bottom: 2.5rem;
+ border-bottom: 1px solid var(--gray-800);
+ }
+
+ .back-link {
+ display: none;
+ }
+
+ .details {
+ display: flex;
+ flex-direction: column;
+ padding: 0.5rem;
+ gap: 1.5rem;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .tags {
+ display: flex;
+ gap: 0.5rem;
+ }
+
+ .description {
+ font-size: var(--text-lg);
+ max-width: 54ch;
+ }
+
+ .content {
+ max-width: 65ch;
+ margin-inline: auto;
+ }
+
+ .content > :global(* + *) {
+ margin-top: 1rem;
+ }
+
+ .content :global(h1),
+ .content :global(h2),
+ .content :global(h3),
+ .content :global(h4),
+ .content :global(h5) {
+ margin: 1.5rem 0;
+ }
+
+ .content :global(img) {
+ border-radius: 1.5rem;
+ box-shadow: var(--shadow-sm);
+ background: var(--gradient-subtle);
+ border: 1px solid var(--gray-800);
+ }
+
+ .content :global(blockquote) {
+ font-size: var(--text-lg);
+ font-family: var(--font-brand);
+ font-weight: 600;
+ line-height: 1.1;
+ padding-inline-start: 1.5rem;
+ border-inline-start: 0.25rem solid var(--accent-dark);
+ color: var(--gray-0);
+ }
+
+ .back-link,
+ .content :global(a) {
+ text-decoration: 1px solid underline transparent;
+ text-underline-offset: 0.25em;
+ transition: text-decoration-color var(--theme-transition);
+ }
+
+ .back-link:hover,
+ .back-link:focus,
+ .content :global(a:hover),
+ .content :global(a:focus) {
+ text-decoration-color: currentColor;
+ }
+
+ @media (min-width: 50em) {
+ .back-link {
+ display: block;
+ align-self: flex-start;
+ }
+
+ .details {
+ flex-direction: row;
+ gap: 2.5rem;
+ }
+
+ .content :global(blockquote) {
+ font-size: var(--text-2xl);
+ }
+ }
+</style>