Skip to content

Commit

Permalink
added some basic styling (#6)
Browse files Browse the repository at this point in the history
* added some basic styling

* refactor Card component to use Declarative Shadow DOM

* work on overall styling, responsiveness & some a11y

* fill in demo explanations and share CSS color variables

---------

Co-authored-by: aholtzman <[email protected]>
  • Loading branch information
thescientist13 and aholtzman authored Aug 5, 2023
1 parent f91abde commit 78a56cd
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 64 deletions.
67 changes: 56 additions & 11 deletions src/components/card.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,63 @@ export default class Card extends HTMLElement {
}

connectedCallback() {
const thumbnail = this.getAttribute('thumbnail');
const title = this.getAttribute('title');
if (!this.shadowRoot) {
const thumbnail = this.getAttribute('thumbnail');
const title = this.getAttribute('title');
const template = document.createElement('template');

this.innerHTML = `
<div>
<h1>${title}</h1>
<button onclick="this.parentNode.parentNode.selectArtist()">View Artist Details</button>
<img src="${thumbnail}" loading="lazy" width="50%">
<hr/>
</div>
`;
template.innerHTML = `
<style>
div {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
border: 1px solid #818181;
width: fit-content;
border-radius: 10px;
padding: 2rem 1rem;
height: 680px;
justify-content: space-between;
background-color: #fff;
}
button {
background: var(--color-accent);
color: var(--color-white);
padding: 1rem 2rem;
border: 0;
font-size: 1rem;
border-radius: 5px;
}
img {
max-width: 500px;
min-width: 500px;
width: 100%;
}
h3 {
font-size: 1.85rem;
}
@media(max-width: 768px) {
img {
max-width: 300px;
min-width: 300px;
}
div {
height: 500px;
}
}
</style>
<div>
<h3>${title}</h3>
<img src="${thumbnail}" loading="lazy" width="100%">
<button onclick="this.parentNode.parentNode.host.selectArtist()">View Artist Details</button>
</div>
`;
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
}

customElements.define('app-card', Card);
customElements.define('app-card', Card);
12 changes: 8 additions & 4 deletions src/pages/artists.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ export default class ArtistsPage extends HTMLElement {
}).join('');

this.innerHTML = `
<a href="/">&lt; Back</a>
<h1>List of Artists: ${artists.length}</h1>
${html}
<h2>SSR Page (w/ WCC)</h2>
<p>This is an example of a Greenwood SSR page route server-rendering Web Components; the same Card component used for the Fragments API demo on the home page in fact! Greenwood is also statically bundling the share template (written in HTML) so that you can still share page templates even within SSR pages.</p>
<h3>List of Artists: ${artists.length}</h3>
<div class="artists-cards-contianer">
${html}
</div>
`;
}
}
}
79 changes: 30 additions & 49 deletions src/pages/index.html
Original file line number Diff line number Diff line change
@@ -1,39 +1,17 @@
<!DOCTYPE html>
<html lang="en" prefix="og:http://ogp.me/ns#">

<html>
<head>
<title>Greenwood Demo - Vercel Adapter</title>
<link rel="shortcut icon" href="/favicon.ico"/>
<link rel="icon" href="/favicon.ico"/>

<script type="module" src="./components/card.js"></script>

<style>
main {
width: 70%;
margin: 0 auto;
text-align: center;
}

.demo-container {
width: 65%;
margin: 0 auto;
display: block;
border: 1px dotted blue;
}

h1 {
text-align: center;
}
</style>

<!-- Greeting API Setup -->
<script type="module">
const params = new URLSearchParams(globalThis.document?.location?.search);
const qs = params.has('name') ? `?name=${params.get('name')}` : '';
const data = await fetch(new URL(`/api/greeting${qs}`, import.meta.url)).then(resp => resp.json());
<script>
globalThis.addEventListener('DOMContentLoaded', () => {
globalThis.document.getElementsByTagName('form')[0].addEventListener('submit', async (e) => {
e.preventDefault();

document.getElementById('greeting').textContent = data.message;
const input = document.getElementsByTagName('input')[0].value;
const data = await fetch(new URL(`/api/greeting?name=${input}`, window.location.href)).then(resp => resp.json());

document.getElementById('greeting-output').textContent = `${data.message}! 👋`;
});
});
</script>

<!-- Fragment API Setup -->
Expand All @@ -54,20 +32,23 @@
</head>

<body>

<main>
<a href="/artists/">Artists Page</a>

<h1 id="greeting"></h1>

<hr/>

<div class="demo-container">
<h1>Demo - WCC + Fragments API</h1>
<button id="load-artists">Load More Artists</button>
<div id="load-artists-output"></div>
</div>
</main>

<article>
<h2>JSON API</h2>
<p>This is an example of a Greenwood API Route returning JSON when fetched on-submit of the form to display a message on the page. You can see it fire in the network tab as <i>/api/greeting</i></p>
<form>
<label>
Greetings Text
<input type="text" required/>
</label>
<button type="submit">Click me for a greeting!</button>
</form>
<h2 id="greeting-output"></h2>
</article>
<article>
<h2>Fragments API (w/ WCC)</h2>
<p>This is an example of a Greenwood API route returning an HTML response that is generated by server-rendering a Web Component (with Declarative Shadow DOM). This same component is loaded on the client-side too, so that when you click the <i>Artist Details</i> button, state and interactivity can still be resumed. You can see it fire in the network tab as <i>/api/fragment</i></p>
<div id="load-artists-output" class="artists-cards-contianer" aria-live="polite"></div>
<button id="load-artists">Load More Artists</button>
</article>
</body>
</html>
</html>
140 changes: 140 additions & 0 deletions src/templates/app.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<!DOCTYPE html>
<html lang="en" prefix="og:http://ogp.me/ns#">

<head>
<title>Greenwood Demo - Vercel Adapter</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="/favicon.ico"/>
<link rel="icon" href="/favicon.ico"/>

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro">
<style>
:root, :host {
--color-white: white;
--color-accent: #3c384d;
}

body {
padding: 0;
margin: 0;
border: 0;
font-family: 'Source Sans Pro', serif;
line-height: 1.4;
background: #fbfbfb;
}

header, footer {
color: var(--color-white);
background-color: rgb(25, 42, 39);
text-align: center;
height: 50px;
padding: 15px 0 0;
}

footer a {
margin: 7px 0 0 0;
text-decoration: none;
}

header a {
color: var(--color-white);
}

a {
color: var(--color-accent);
}

p {
margin: 20px auto;
width: 50%;
}

header nav ul {
margin: 0;
padding: 0;
text-align: center;
font-size: 1.5rem;
}

header nav ul li {
display: inline;
}

main {
text-align: center;
min-height: 100vh;
}

h2 {
text-align: center;
text-decoration: underline;
}

button {
background: var(--color-accent);
color: var(--color-white);
padding: 1rem 2rem;
border: 0;
font-size: 1rem;
border-radius: 5px;
}

input {
padding: 1rem;
margin: 0 10px;
font-size: 16px;
}

label {
font-size: 1.35rem;
}

article {
margin: 4rem 0;
}

.artists-cards-contianer {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
align-items: baseline;
margin: 2rem 0;
}

@media(max-width: 768px) {
button {
margin: 10px;
}
}
</style>

<script type="module" src="./components/card.js"></script>
</head>

<body>
<header>
<nav>
<ul>
<li><a href="/">Home</a> | </li>
<li><a href="/artists/">Artists</a></li>
</ul>
</nav>
</header>

<main>
<h1>Demos</h1>
<p>This is a
<a href="https://github.com/ProjectEvergreen/greenwood-demo-adapter-vercel" title="Link to demonstration repo">Greenwood demonstration repo</a>
showcasing various features deployed to and running on Vercel serverless functions.
</p>
<page-outlet></page-outlet>
</main>

<footer>
<a href="https://www.greenwoodjs.io/">Greenwood</a>
</footer>

</body>

</html>

0 comments on commit 78a56cd

Please sign in to comment.