refactor: lots of improvements (#69)
This commit is contained in:
parent
f8e07c3195
commit
7c67e674e5
6 changed files with 111 additions and 109 deletions
|
@ -2,11 +2,11 @@
|
|||
import Icon from 'astro-iconify';
|
||||
|
||||
export interface Props {
|
||||
url: string;
|
||||
url: string | null;
|
||||
}
|
||||
|
||||
const { url } = Astro.props;
|
||||
const placeholder = 'Type the article URL here';
|
||||
const { url } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="address-bar">
|
||||
|
@ -14,7 +14,7 @@ const placeholder = 'Type the article URL here';
|
|||
<button aria-label="Back" class="left-buttons" type="button" id="app-back" name="app-back" onclick="history.go(-1); return false;" hidden>
|
||||
<Icon name="ic:round-arrow-back-ios" />
|
||||
</button>
|
||||
<input type="url" id="app-url" name="url" value={url} placeholder={placeholder} required />
|
||||
<input type="url" id="app-url" name="url" value={url ?? ''} placeholder={placeholder} required />
|
||||
<button aria-label="Submit" class="right-buttons" type="submit" id="submit">
|
||||
<Icon name="ri:ai-generate" />
|
||||
</button>
|
||||
|
|
|
@ -1,32 +1,30 @@
|
|||
---
|
||||
export interface Props {
|
||||
postDivSelector: string,
|
||||
routerOutlet: string,
|
||||
skipSave?: boolean
|
||||
}
|
||||
|
||||
const {postDivSelector, skipSave = false} = Astro.props;
|
||||
const {routerOutlet, skipSave = false} = Astro.props;
|
||||
---
|
||||
<div id="library">
|
||||
<span id="heading"></span>
|
||||
<ul id="post-list"></ul>
|
||||
</div>
|
||||
|
||||
<input value={postDivSelector} name="postDivSelector" id="postDivSelector" hidden />
|
||||
<input type="checkbox" id="skipSave" name="skipSave" checked={skipSave} hidden />
|
||||
<input hidden value={routerOutlet} name="postDivSelector" id="postDivSelector" />
|
||||
<input hidden checked={skipSave} type="checkbox" name="skipSave" id="skipSave" />
|
||||
|
||||
<script>
|
||||
import { getPostCard, renderPost } from '../utils/library'
|
||||
const cache = await caches.open('cozy-reader');
|
||||
const url = new URL(window.location.href);
|
||||
const response = await cache.match(url)
|
||||
const postDivSelector = document.getElementById('postDivSelector') as HTMLInputElement;
|
||||
const skipSave = document.getElementById('skipSave') as HTMLInputElement;
|
||||
const postDivSelector = document.querySelector<HTMLInputElement>('#postDivSelector');
|
||||
const skipSave = document.querySelector<HTMLInputElement>('#skipSave');
|
||||
|
||||
if (!response) {
|
||||
if (!skipSave?.checked) {
|
||||
if (!response && !skipSave?.checked) {
|
||||
await cache.add(url);
|
||||
}
|
||||
}
|
||||
|
||||
const cachedRequests = (await cache.keys())
|
||||
.filter(request => {
|
||||
|
@ -34,7 +32,7 @@ const {postDivSelector, skipSave = false} = Astro.props;
|
|||
return urlObj.search !== '' && urlObj.searchParams.get('url') !== '';
|
||||
});
|
||||
|
||||
if(cachedRequests?.length) {
|
||||
if(cachedRequests?.length && postDivSelector !== null) {
|
||||
const list = document.querySelector('#post-list');
|
||||
const heading = document.querySelector('#library span#heading') as HTMLHeadingElement;
|
||||
heading.innerHTML = 'History';
|
||||
|
@ -80,7 +78,6 @@ const {postDivSelector, skipSave = false} = Astro.props;
|
|||
if (!url) {
|
||||
url = window.location.href;
|
||||
isHome = true;
|
||||
console.log('>>> ishome', isHome);
|
||||
} else {
|
||||
// replace scrollPosition
|
||||
localStorage.setItem('scrollPosition', window.scrollY.toString());
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
---
|
||||
import { ArticleData } from "@extractus/article-extractor";
|
||||
export interface Props {
|
||||
article: ArticleData;
|
||||
article: ArticleData | null;
|
||||
}
|
||||
|
||||
const { article } = Astro.props;
|
||||
const error: ArticleData = {
|
||||
title: 'Something is not right',
|
||||
content: '<p>The article extractor did not get any information.</p>',
|
||||
}
|
||||
let { article } = Astro.props;
|
||||
article ??= error;
|
||||
const datePublished =
|
||||
article?.published && new Date(article.published).toDateString();
|
||||
---
|
||||
|
|
|
@ -3,10 +3,16 @@ import { ArticleData } from "@extractus/article-extractor";
|
|||
import "./reset.css";
|
||||
import Footer from "../components/Footer.astro";
|
||||
export interface Props {
|
||||
meta: ArticleData
|
||||
article: ArticleData | null
|
||||
}
|
||||
const { meta } = Astro.props;
|
||||
const appTitle = `Cozy 🧸${meta.title && ` | ${meta.title}`}`;
|
||||
const app: ArticleData = {
|
||||
title: "Cozy 🧸",
|
||||
description: "Remove distractions. Save your favorites. Get useful insights. Cozy is your modern-day reading assistant.",
|
||||
content: "<p>Enter a URL in the address bar to get started.</p>",
|
||||
url: '/'
|
||||
};
|
||||
const { article } = Astro.props;
|
||||
const appTitle = article?.title ? `${article.title} | Cozy 🧸` : app.title;
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
@ -18,9 +24,22 @@ const appTitle = `Cozy 🧸${meta.title && ` | ${meta.title}`}`;
|
|||
<title>{appTitle}</title>
|
||||
|
||||
{
|
||||
meta.url !== '/' ? (
|
||||
/**
|
||||
* if showing a post:
|
||||
* - don't allow search engines to index the page
|
||||
* - add cozy metadata for the app to use
|
||||
*/
|
||||
article && article?.url !== '/' ? (
|
||||
<meta name="robots" content="noindex">
|
||||
<meta name="googlebot" content="noindex">
|
||||
|
||||
<meta property="cozy:title" content={article.title} />
|
||||
<meta property="cozy:url" content={article.url} />
|
||||
<meta property="cozy:description" content={article.description} />
|
||||
<meta property="cozy:image" content={article.image} />
|
||||
<meta property="cozy:source" content={article.source} />
|
||||
<meta property="cozy:author" content={article.author} />
|
||||
<meta property="cozy:published" content={article.published} />
|
||||
) : (
|
||||
<meta property="og:title" content={appTitle} />
|
||||
<meta property="og:url" content={Astro.url.href} />
|
||||
|
@ -29,15 +48,6 @@ const appTitle = `Cozy 🧸${meta.title && ` | ${meta.title}`}`;
|
|||
<meta itemprop="description" content="Remove distractions. Save your favorites. Get useful insights. Cozy is your modern-day reading assistant." />
|
||||
)
|
||||
}
|
||||
|
||||
<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} />
|
||||
<meta property="cozy:author" content={meta.author} />
|
||||
<meta property="cozy:published" content={meta.published} />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="app-wrapper">
|
||||
|
|
|
@ -6,40 +6,23 @@ import Layout from "../layouts/Layout.astro";
|
|||
import Library from "../components/Library.astro";
|
||||
import Footer from "../components/Footer.astro";
|
||||
|
||||
const params = Astro.url.searchParams;
|
||||
const url = params.get('url') || '';
|
||||
let article: ArticleData | null;
|
||||
let skipSave;
|
||||
|
||||
const error = {
|
||||
title: "Something is not right",
|
||||
content: "<p>The article extractor did not get any result.</p>",
|
||||
}
|
||||
const url = Astro.url.searchParams.get('url');
|
||||
let article: ArticleData | null = {};
|
||||
|
||||
if (url)
|
||||
try {
|
||||
article = await extract(url);
|
||||
if (!article ) {
|
||||
article = error;
|
||||
skipSave = true;
|
||||
}
|
||||
} catch {
|
||||
article = error;
|
||||
skipSave = true;
|
||||
}
|
||||
|
||||
if (url === '') {
|
||||
article = {
|
||||
title: "Welcome to Cozy 🧸",
|
||||
content: "<p>Enter a URL above to get started.</p>",
|
||||
url: '/'
|
||||
};
|
||||
skipSave = false;
|
||||
article = null;
|
||||
}
|
||||
|
||||
const routerOutletID = "router-outlet";
|
||||
---
|
||||
<Layout meta={article}>
|
||||
<Layout article={article}>
|
||||
<AddressBar url={url} />
|
||||
<Post slot="post" article={article} />
|
||||
<Library slot="library" skipSave={skipSave} postDivSelector="#post"/>
|
||||
<div slot="post" id={routerOutletID}>
|
||||
<Post article={article} />
|
||||
</div>
|
||||
<Library slot="library" skipSave={article === null} routerOutlet={routerOutletID}/>
|
||||
<Footer slot="footer" />
|
||||
</Layout>
|
||||
|
|
|
@ -1,23 +1,5 @@
|
|||
export 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 source = html
|
||||
.querySelector('meta[property="cozy:source"]')
|
||||
?.getAttribute("content");
|
||||
const published = html
|
||||
.querySelector('meta[property="cozy:published"]')
|
||||
?.getAttribute("content");
|
||||
|
||||
const {title, description, image, source, published} = getPostMeta(html);
|
||||
const postCard = `
|
||||
<div class="post-card">
|
||||
<div class="post-card__image">
|
||||
|
@ -64,33 +46,32 @@ export function getPostCard(html: HTMLHtmlElement) {
|
|||
`;
|
||||
return postCard;
|
||||
}
|
||||
|
||||
export function renderPost(responseText, url, postDivSelector: string, preventPushState = false) {
|
||||
const postDiv = document.querySelector(postDivSelector);
|
||||
const postDiv = document.querySelector<HTMLDivElement>(`#${postDivSelector}`);
|
||||
const html = document.createElement('html');
|
||||
html.innerHTML = responseText;
|
||||
const newPost = html.querySelector('body')?.querySelector('#post');
|
||||
if (postDiv && newPost?.innerHTML) {
|
||||
postDiv.innerHTML = newPost.innerHTML
|
||||
|
||||
const appUrl = document.getElementById('app-url') as HTMLInputElement;
|
||||
const cozyUrl = html.querySelector('meta[property="cozy:url"]')?.getAttribute('content');
|
||||
const homeBtn = document.querySelector<HTMLButtonElement>('#app-home');
|
||||
const backBtn = document.querySelector<HTMLButtonElement>('#app-back');
|
||||
const submitBtn = document.querySelector<HTMLButtonElement>('#app-submit');
|
||||
|
||||
|
||||
const title = html.querySelector('meta[property="cozy:title"]')?.getAttribute('content');
|
||||
document.title = `Cozy 🧸 | ${title}` || 'Cozy 🧸';
|
||||
|
||||
if(cozyUrl !== '/') {
|
||||
appUrl.value = cozyUrl || '';
|
||||
backBtn?.removeAttribute('disabled');
|
||||
submitBtn?.removeAttribute('disabled');
|
||||
homeBtn?.removeAttribute('disabled');
|
||||
document.title = `${getCozyTitle(html)} | Cozy 🧸`;
|
||||
} else {
|
||||
appUrl.value = '';
|
||||
backBtn?.setAttribute('disabled', 'true');
|
||||
submitBtn?.setAttribute('disabled', 'true');
|
||||
homeBtn?.setAttribute('disabled', 'true');
|
||||
document.title = `Cozy 🧸`;
|
||||
}
|
||||
|
||||
if(!preventPushState) {
|
||||
|
@ -98,3 +79,29 @@ export function renderPost(responseText, url, postDivSelector: string, preventPu
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getPostMeta(html: HTMLHtmlElement) {
|
||||
const title = getCozyTitle(html);
|
||||
const description = html
|
||||
.querySelector('meta[property="cozy:description"]')
|
||||
?.getAttribute("content");
|
||||
const image = html
|
||||
.querySelector('meta[property="cozy:image"]')
|
||||
?.getAttribute("content");
|
||||
const source = html
|
||||
.querySelector('meta[property="cozy:source"]')
|
||||
?.getAttribute("content");
|
||||
const published = html
|
||||
.querySelector('meta[property="cozy:published"]')
|
||||
?.getAttribute("content");
|
||||
|
||||
return {title, description, image, source, published};
|
||||
}
|
||||
|
||||
function getCozyTitle(html: HTMLHtmlElement): string | undefined {
|
||||
return html.querySelector('meta[property="cozy:title"]')?.getAttribute("content")
|
||||
/**
|
||||
* backwards compatibility for stuff before we implemented cozy:meta tags
|
||||
*/
|
||||
?? html.querySelector("title")?.innerHTML?.replace("Cozy 🧸 | ", "");
|
||||
}
|
Loading…
Reference in a new issue