feat: single column layout w/ fancy cards (#30)
This commit is contained in:
parent
b0173da4c5
commit
d6e89e5f7d
5 changed files with 165 additions and 102 deletions
|
@ -21,11 +21,6 @@ const form = new FormGroup([
|
||||||
<Form
|
<Form
|
||||||
formGroups={form}
|
formGroups={form}
|
||||||
showValidationHints
|
showValidationHints
|
||||||
submitControl={{
|
|
||||||
type: "submit",
|
|
||||||
name: "submit",
|
|
||||||
value: "Get cozy!",
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/"
|
<a href="/"
|
||||||
|
@ -74,11 +69,4 @@ const form = new FormGroup([
|
||||||
:global(input[type="text"]) {
|
:global(input[type="text"]) {
|
||||||
border: 2px solid brown;
|
border: 2px solid brown;
|
||||||
}
|
}
|
||||||
:global(input[type="submit"]) {
|
|
||||||
width: 150px;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
background-color: brown;
|
|
||||||
color: white;
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -22,53 +22,141 @@ const {postDivSelector, skipSave = false} = Astro.props;
|
||||||
const skipSave = document.getElementById('skipSave') as HTMLInputElement;
|
const skipSave = document.getElementById('skipSave') as HTMLInputElement;
|
||||||
const postDiv = document.querySelector(postDivSelector?.value);
|
const postDiv = document.querySelector(postDivSelector?.value);
|
||||||
|
|
||||||
if (!response && !skipSave.checked) {
|
if (!response && !skipSave?.checked) {
|
||||||
|
console.log('skip?', skipSave?.checked)
|
||||||
await cache.add(url);
|
await cache.add(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cachedResponses = await cache.keys();
|
const cachedResponses = await cache.keys();
|
||||||
const list = document.querySelector('#post-list');
|
const list = document.querySelector('#post-list');
|
||||||
|
|
||||||
if (cachedResponses.length) {
|
if(cachedResponses?.length) {
|
||||||
const heading = document.querySelector('#library h2') as HTMLHeadingElement;
|
const headingEl = document.querySelector('#library h2');
|
||||||
heading.innerText = 'Previously viewed:';
|
if(headingEl)
|
||||||
}
|
headingEl.innerHTML = 'Previously Viewed';
|
||||||
|
|
||||||
cachedResponses
|
cachedResponses
|
||||||
.filter(request => {
|
.filter(request => {
|
||||||
const urlObj = new URL(request.url);
|
const urlObj = new URL(request.url);
|
||||||
return urlObj.search !== '';
|
return urlObj.search !== '';
|
||||||
})
|
})
|
||||||
.reverse()
|
.reverse()
|
||||||
.forEach(async (request) => {
|
.forEach(async (request) => {
|
||||||
const {url} = request;
|
const {url} = request;
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
|
|
||||||
let responseText;
|
let responseText;
|
||||||
|
|
||||||
const fullResponse = await cache.match(url)
|
const fullResponse = await cache.match(url)
|
||||||
fullResponse?.text().then(data => {
|
fullResponse?.text().then(data => {
|
||||||
responseText = 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 html = document.createElement('html');
|
const html = document.createElement('html');
|
||||||
html.innerHTML = responseText;
|
html.innerHTML = responseText;
|
||||||
const newPost = html.querySelector('body')?.querySelector('#post');
|
const title = html.querySelector('title');
|
||||||
if (postDiv && newPost?.innerHTML) {
|
const postCard = getPostCard(html);
|
||||||
postDiv.innerHTML = newPost.innerHTML
|
link.innerHTML = postCard;
|
||||||
}
|
});
|
||||||
}
|
|
||||||
const item = document.createElement('li');
|
|
||||||
item.appendChild(link);
|
|
||||||
list?.appendChild(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
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>
|
</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>
|
|
@ -24,14 +24,14 @@ const datePublished =
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
<style lang="scss">
|
<style is:global lang="scss">
|
||||||
|
|
||||||
@counter-style publish-icons {
|
@counter-style publish-icons {
|
||||||
system: cyclic;
|
system: cyclic;
|
||||||
symbols: "️✍️" "🗓️";
|
symbols: "️✍️" "🗓️";
|
||||||
suffix: " ";
|
suffix: " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
#post {
|
|
||||||
h1.title {
|
h1.title {
|
||||||
font-size: xx-large;
|
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 {
|
content {
|
||||||
p, table, ul {
|
p, table, ul, img {
|
||||||
margin: 1em 0 !important;
|
margin: 1em 0 !important;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
td, th {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -1,10 +1,11 @@
|
||||||
---
|
---
|
||||||
|
import { ArticleData } from "@extractus/article-extractor";
|
||||||
import "./reset.css";
|
import "./reset.css";
|
||||||
export interface Props {
|
export interface Props {
|
||||||
title?: string;
|
meta: ArticleData
|
||||||
}
|
}
|
||||||
const appTitle = "Cozy 🧸";
|
const appTitle = "Cozy 🧸";
|
||||||
const { title } = Astro.props;
|
const { meta } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
@ -13,7 +14,14 @@ const { title } = Astro.props;
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<slot />
|
<slot />
|
||||||
|
@ -30,28 +38,12 @@ const { title } = Astro.props;
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#main-content {
|
#main-content {
|
||||||
padding: 1em;
|
max-width: 600px;
|
||||||
max-width: 1000px;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
display: flex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#library-wrapper {
|
#main-content * {
|
||||||
flex: 1
|
margin: 1em 0 0;
|
||||||
}
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -30,13 +30,19 @@ if (url === '') {
|
||||||
article = {
|
article = {
|
||||||
title: "Welcome to Cozy 🧸",
|
title: "Welcome to Cozy 🧸",
|
||||||
content: "<p>Enter a URL above to get started.</p>",
|
content: "<p>Enter a URL above to get started.</p>",
|
||||||
|
url: '/'
|
||||||
};
|
};
|
||||||
skipSave = true;
|
skipSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
<Layout title={url !== "" ? article?.title : "Your modern-day reading assistant"}>
|
<Layout meta={article}>
|
||||||
<AddressBar url={url} />
|
<AddressBar url={url} />
|
||||||
<Post slot="post" article={article} />
|
<div slot="post" id="outlet"></div>
|
||||||
<Library skipSave={skipSave} slot="library" postDivSelector="#post" />
|
{
|
||||||
|
url
|
||||||
|
? <Post slot="post" article={article} />
|
||||||
|
:
|
||||||
|
<Library skipSave={skipSave} slot="library" postDivSelector="#outlet" />
|
||||||
|
}
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
Loading…
Reference in a new issue