feat: single column layout w/ fancy cards (#30)

This commit is contained in:
Ayo Ayco 2023-06-10 12:00:20 +02:00 committed by GitHub
parent b0173da4c5
commit d6e89e5f7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 165 additions and 102 deletions

View file

@ -21,11 +21,6 @@ const form = new FormGroup([
<Form
formGroups={form}
showValidationHints
submitControl={{
type: "submit",
name: "submit",
value: "Get cozy!",
}}
/>
<nav>
<a href="/"
@ -74,11 +69,4 @@ const form = new FormGroup([
:global(input[type="text"]) {
border: 2px solid brown;
}
:global(input[type="submit"]) {
width: 150px;
margin-top: 0.5em;
background-color: brown;
color: white;
font-weight: bolder;
}
</style>

View file

@ -22,53 +22,141 @@ const {postDivSelector, skipSave = false} = Astro.props;
const skipSave = document.getElementById('skipSave') as HTMLInputElement;
const postDiv = document.querySelector(postDivSelector?.value);
if (!response && !skipSave.checked) {
if (!response && !skipSave?.checked) {
console.log('skip?', skipSave?.checked)
await cache.add(url);
}
const cachedResponses = await cache.keys();
const list = document.querySelector('#post-list');
if (cachedResponses.length) {
const heading = document.querySelector('#library h2') as HTMLHeadingElement;
heading.innerText = 'Previously viewed:';
}
if(cachedResponses?.length) {
const headingEl = document.querySelector('#library h2');
if(headingEl)
headingEl.innerHTML = 'Previously Viewed';
cachedResponses
.filter(request => {
const urlObj = new URL(request.url);
return urlObj.search !== '';
})
.reverse()
.forEach(async (request) => {
const {url} = request;
const link = document.createElement('a');
cachedResponses
.filter(request => {
const urlObj = new URL(request.url);
return urlObj.search !== '';
})
.reverse()
.forEach(async (request) => {
const {url} = request;
const link = document.createElement('a');
let responseText;
let responseText;
const fullResponse = await cache.match(url)
fullResponse?.text().then(data => {
responseText = data;
const html = document.createElement('html');
html.innerHTML = responseText;
const title = html.querySelector('title');
link.innerText = (title?.innerText || url).replace('Cozy 🧸 | ', '');
});
link.href = url;
link.onclick = async (e) => {
e.preventDefault();
scroll(0,0);
const fullResponse = await cache.match(url)
fullResponse?.text().then(data => {
responseText = data;
const html = document.createElement('html');
html.innerHTML = responseText;
const newPost = html.querySelector('body')?.querySelector('#post');
if (postDiv && newPost?.innerHTML) {
postDiv.innerHTML = newPost.innerHTML
}
}
const item = document.createElement('li');
item.appendChild(link);
list?.appendChild(item);
});
const title = html.querySelector('title');
const postCard = getPostCard(html);
link.innerHTML = postCard;
});
</script>
link.href = url;
link.onclick = async (e) => {
e.preventDefault();
scroll(0,0);
const html = document.createElement('html');
html.innerHTML = responseText;
const newPost = html.querySelector('body')?.querySelector('#post');
if (postDiv && newPost?.innerHTML) {
postDiv.innerHTML = newPost.innerHTML
}
}
const item = document.createElement('li');
item.appendChild(link);
list?.appendChild(item);
});
}
function getPostCard(html: HTMLHtmlElement) {
const title
= html.querySelector('meta[property="cozy:title"]')?.getAttribute('content')
||html.querySelector('title')?.innerHTML?.replace('Cozy 🧸 | ', '');
const description = html.querySelector('meta[property="cozy:description"]')?.getAttribute('content');
const image = html.querySelector('meta[property="cozy:image"]')?.getAttribute('content');
const url = html.querySelector('meta[property="cozy:url"]')?.getAttribute('content');
const source = html.querySelector('meta[property="cozy:source"]')?.getAttribute('content');
const postCard = `
<div class="post-card">
${
image ? `
<div class="post-card__image">
<img src="${image}" alt="${title} | ${description}" />
</div>
`
: ''
}
<div class="post-card__content">
${
source ? `
<p class="post-card__site-name">${source}</p>
`
: ''
}
<h3 class="post-card__title">${title}</h3>
${
description ? `
<p class="post-card__description">${description}</p>`
: ''
}
</div>
</div>
`;
return postCard;
}
</script>
<style lang="scss">
#library {
:global(h2) {
margin-bottom: 1rem;
text-align: center;
}
}
#post-list {
:global(li) {
margin-bottom: 1rem;
list-style: none;
border: 1px solid #ccc;
box-shadow: 0 5px 2px #eee;
border-radius: 5px;
padding: 1em;
width: calc(100% + 40px);
display: block;
float: left;
margin-left: -40px;
:global(a) {
text-decoration: none;
color: #000;
:global(h3) {
text-decoration: underline;
}
:global(.post-card) {
:global(.post-card__image) {
float: left;
margin-right: 1em;
:global(img) {
width: 150px;
height: 150px;
object-fit: cover;
border-radius: 5px;
border: 1px solid #eee;
}
}
}
}
}
}
</style>

View file

@ -24,14 +24,14 @@ const datePublished =
)
}
<style lang="scss">
<style is:global lang="scss">
@counter-style publish-icons {
system: cyclic;
symbols: "️✍️" "🗓️";
suffix: " ";
}
#post {
h1.title {
font-size: xx-large;
}
@ -51,36 +51,25 @@ const datePublished =
}
}
content {
:global(p, table, ul) {
margin: 1em 0;
font-size: 20px;
}
:global(table) {
border-collapse: collapse;
:global(td, th) {
border: 1px solid #ccc;
padding: 0.5em;
}
}
:global(pre) {
white-space: pre-wrap;
}
}
}
</style>
<style is:global lang="scss">
/**
forced fix for older cached items before v0.1.5
*/
content {
p, table, ul {
p, table, ul, img {
margin: 1em 0 !important;
font-size: 20px;
}
table {
border-collapse: collapse;
td, th {
border: 1px solid #ccc;
padding: 0.5em;
}
}
pre {
white-space: pre-wrap;
}
}
</style>

View file

@ -1,10 +1,11 @@
---
import { ArticleData } from "@extractus/article-extractor";
import "./reset.css";
export interface Props {
title?: string;
meta: ArticleData
}
const appTitle = "Cozy 🧸";
const { title } = Astro.props;
const { meta } = Astro.props;
---
<!DOCTYPE html>
@ -13,7 +14,14 @@ const { title } = Astro.props;
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{appTitle} {title && `| ${title}`}</title>
<title>{appTitle} {meta.title && `| ${meta.title}`}</title>
<meta property="cozy:title" content={meta.title} />
<meta property="cozy:url" content={meta.url} />
<meta property="cozy:description" content={meta.description} />
<meta property="cozy:image" content={meta.image} />
<meta property="cozy:source" content={meta.source} />
</head>
<body>
<slot />
@ -30,28 +38,12 @@ const { title } = Astro.props;
<style>
#main-content {
padding: 1em;
max-width: 1000px;
max-width: 600px;
margin: 0 auto;
display: flex;
}
#library-wrapper {
flex: 1
}
#post-wrapper {
max-width: 600px;
flex: 2
}
@media only screen and (min-width: 0px) and (max-width: 700px) {
#main-content {
max-width: 600px;
display: block;
}
#main-content * {
margin: 1em 0 0;
}
</style>

View file

@ -30,13 +30,19 @@ if (url === '') {
article = {
title: "Welcome to Cozy 🧸",
content: "<p>Enter a URL above to get started.</p>",
url: '/'
};
skipSave = true;
}
---
<Layout title={url !== "" ? article?.title : "Your modern-day reading assistant"}>
<Layout meta={article}>
<AddressBar url={url} />
<Post slot="post" article={article} />
<Library skipSave={skipSave} slot="library" postDivSelector="#post" />
<div slot="post" id="outlet"></div>
{
url
? <Post slot="post" article={article} />
:
<Library skipSave={skipSave} slot="library" postDivSelector="#outlet" />
}
</Layout>