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';
|
import Icon from 'astro-iconify';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
url: string;
|
url: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { url } = Astro.props;
|
|
||||||
const placeholder = 'Type the article URL here';
|
const placeholder = 'Type the article URL here';
|
||||||
|
const { url } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="address-bar">
|
<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>
|
<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" />
|
<Icon name="ic:round-arrow-back-ios" />
|
||||||
</button>
|
</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">
|
<button aria-label="Submit" class="right-buttons" type="submit" id="submit">
|
||||||
<Icon name="ri:ai-generate" />
|
<Icon name="ri:ai-generate" />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,31 +1,29 @@
|
||||||
---
|
---
|
||||||
export interface Props {
|
export interface Props {
|
||||||
postDivSelector: string,
|
routerOutlet: string,
|
||||||
skipSave?: boolean
|
skipSave?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const {postDivSelector, skipSave = false} = Astro.props;
|
const {routerOutlet, skipSave = false} = Astro.props;
|
||||||
---
|
---
|
||||||
<div id="library">
|
<div id="library">
|
||||||
<span id="heading"></span>
|
<span id="heading"></span>
|
||||||
<ul id="post-list"></ul>
|
<ul id="post-list"></ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input value={postDivSelector} name="postDivSelector" id="postDivSelector" hidden />
|
<input hidden value={routerOutlet} name="postDivSelector" id="postDivSelector" />
|
||||||
<input type="checkbox" id="skipSave" name="skipSave" checked={skipSave} hidden />
|
<input hidden checked={skipSave} type="checkbox" name="skipSave" id="skipSave" />
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getPostCard, renderPost } from '../utils/library'
|
import { getPostCard, renderPost } from '../utils/library'
|
||||||
const cache = await caches.open('cozy-reader');
|
const cache = await caches.open('cozy-reader');
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
const response = await cache.match(url)
|
const response = await cache.match(url)
|
||||||
const postDivSelector = document.getElementById('postDivSelector') as HTMLInputElement;
|
const postDivSelector = document.querySelector<HTMLInputElement>('#postDivSelector');
|
||||||
const skipSave = document.getElementById('skipSave') as HTMLInputElement;
|
const skipSave = document.querySelector<HTMLInputElement>('#skipSave');
|
||||||
|
|
||||||
if (!response) {
|
if (!response && !skipSave?.checked) {
|
||||||
if (!skipSave?.checked) {
|
|
||||||
await cache.add(url);
|
await cache.add(url);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const cachedRequests = (await cache.keys())
|
const cachedRequests = (await cache.keys())
|
||||||
|
@ -34,7 +32,7 @@ const {postDivSelector, skipSave = false} = Astro.props;
|
||||||
return urlObj.search !== '' && urlObj.searchParams.get('url') !== '';
|
return urlObj.search !== '' && urlObj.searchParams.get('url') !== '';
|
||||||
});
|
});
|
||||||
|
|
||||||
if(cachedRequests?.length) {
|
if(cachedRequests?.length && postDivSelector !== null) {
|
||||||
const list = document.querySelector('#post-list');
|
const list = document.querySelector('#post-list');
|
||||||
const heading = document.querySelector('#library span#heading') as HTMLHeadingElement;
|
const heading = document.querySelector('#library span#heading') as HTMLHeadingElement;
|
||||||
heading.innerHTML = 'History';
|
heading.innerHTML = 'History';
|
||||||
|
@ -80,7 +78,6 @@ const {postDivSelector, skipSave = false} = Astro.props;
|
||||||
if (!url) {
|
if (!url) {
|
||||||
url = window.location.href;
|
url = window.location.href;
|
||||||
isHome = true;
|
isHome = true;
|
||||||
console.log('>>> ishome', isHome);
|
|
||||||
} else {
|
} else {
|
||||||
// replace scrollPosition
|
// replace scrollPosition
|
||||||
localStorage.setItem('scrollPosition', window.scrollY.toString());
|
localStorage.setItem('scrollPosition', window.scrollY.toString());
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
---
|
---
|
||||||
import { ArticleData } from "@extractus/article-extractor";
|
import { ArticleData } from "@extractus/article-extractor";
|
||||||
export interface Props {
|
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 =
|
const datePublished =
|
||||||
article?.published && new Date(article.published).toDateString();
|
article?.published && new Date(article.published).toDateString();
|
||||||
---
|
---
|
||||||
|
|
|
@ -3,10 +3,16 @@ import { ArticleData } from "@extractus/article-extractor";
|
||||||
import "./reset.css";
|
import "./reset.css";
|
||||||
import Footer from "../components/Footer.astro";
|
import Footer from "../components/Footer.astro";
|
||||||
export interface Props {
|
export interface Props {
|
||||||
meta: ArticleData
|
article: ArticleData | null
|
||||||
}
|
}
|
||||||
const { meta } = Astro.props;
|
const app: ArticleData = {
|
||||||
const appTitle = `Cozy 🧸${meta.title && ` | ${meta.title}`}`;
|
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>
|
<!DOCTYPE html>
|
||||||
|
@ -18,9 +24,22 @@ const appTitle = `Cozy 🧸${meta.title && ` | ${meta.title}`}`;
|
||||||
<title>{appTitle}</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="robots" content="noindex">
|
||||||
<meta name="googlebot" 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:title" content={appTitle} />
|
||||||
<meta property="og:url" content={Astro.url.href} />
|
<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 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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app-wrapper">
|
<div id="app-wrapper">
|
||||||
|
|
|
@ -6,40 +6,23 @@ import Layout from "../layouts/Layout.astro";
|
||||||
import Library from "../components/Library.astro";
|
import Library from "../components/Library.astro";
|
||||||
import Footer from "../components/Footer.astro";
|
import Footer from "../components/Footer.astro";
|
||||||
|
|
||||||
const params = Astro.url.searchParams;
|
const url = Astro.url.searchParams.get('url');
|
||||||
const url = params.get('url') || '';
|
let article: ArticleData | null = {};
|
||||||
let article: ArticleData | null;
|
|
||||||
let skipSave;
|
|
||||||
|
|
||||||
const error = {
|
if (url)
|
||||||
title: "Something is not right",
|
try {
|
||||||
content: "<p>The article extractor did not get any result.</p>",
|
article = await extract(url);
|
||||||
}
|
} catch {
|
||||||
|
article = null;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const routerOutletID = "router-outlet";
|
||||||
---
|
---
|
||||||
<Layout meta={article}>
|
<Layout article={article}>
|
||||||
<AddressBar url={url} />
|
<AddressBar url={url} />
|
||||||
<Post slot="post" article={article} />
|
<div slot="post" id={routerOutletID}>
|
||||||
<Library slot="library" skipSave={skipSave} postDivSelector="#post"/>
|
<Post article={article} />
|
||||||
|
</div>
|
||||||
|
<Library slot="library" skipSave={article === null} routerOutlet={routerOutletID}/>
|
||||||
<Footer slot="footer" />
|
<Footer slot="footer" />
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -1,23 +1,5 @@
|
||||||
export function getPostCard(html: HTMLHtmlElement) {
|
export function getPostCard(html: HTMLHtmlElement) {
|
||||||
const title =
|
const {title, description, image, source, published} = getPostMeta(html);
|
||||||
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 postCard = `
|
const postCard = `
|
||||||
<div class="post-card">
|
<div class="post-card">
|
||||||
<div class="post-card__image">
|
<div class="post-card__image">
|
||||||
|
@ -64,37 +46,62 @@ export function getPostCard(html: HTMLHtmlElement) {
|
||||||
`;
|
`;
|
||||||
return postCard;
|
return postCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderPost(responseText, url, postDivSelector: string, preventPushState = false) {
|
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');
|
const html = document.createElement('html');
|
||||||
html.innerHTML = responseText;
|
html.innerHTML = responseText;
|
||||||
const newPost = html.querySelector('body')?.querySelector('#post');
|
const newPost = html.querySelector('body')?.querySelector('#post');
|
||||||
if (postDiv && newPost?.innerHTML) {
|
if (postDiv && newPost?.innerHTML) {
|
||||||
postDiv.innerHTML = 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 appUrl = document.getElementById('app-url') as HTMLInputElement;
|
||||||
const title = html.querySelector('meta[property="cozy:title"]')?.getAttribute('content');
|
const cozyUrl = html.querySelector('meta[property="cozy:url"]')?.getAttribute('content');
|
||||||
document.title = `Cozy 🧸 | ${title}` || 'Cozy 🧸';
|
const homeBtn = document.querySelector<HTMLButtonElement>('#app-home');
|
||||||
|
const backBtn = document.querySelector<HTMLButtonElement>('#app-back');
|
||||||
if(cozyUrl !== '/') {
|
const submitBtn = document.querySelector<HTMLButtonElement>('#app-submit');
|
||||||
appUrl.value = cozyUrl || '';
|
if(cozyUrl !== '/') {
|
||||||
backBtn?.removeAttribute('disabled');
|
appUrl.value = cozyUrl || '';
|
||||||
submitBtn?.removeAttribute('disabled');
|
backBtn?.removeAttribute('disabled');
|
||||||
homeBtn?.removeAttribute('disabled');
|
submitBtn?.removeAttribute('disabled');
|
||||||
} else {
|
homeBtn?.removeAttribute('disabled');
|
||||||
appUrl.value = '';
|
document.title = `${getCozyTitle(html)} | Cozy 🧸`;
|
||||||
backBtn?.setAttribute('disabled', 'true');
|
} else {
|
||||||
submitBtn?.setAttribute('disabled', 'true');
|
appUrl.value = '';
|
||||||
homeBtn?.setAttribute('disabled', 'true');
|
backBtn?.setAttribute('disabled', 'true');
|
||||||
}
|
submitBtn?.setAttribute('disabled', 'true');
|
||||||
|
homeBtn?.setAttribute('disabled', 'true');
|
||||||
if(!preventPushState) {
|
document.title = `Cozy 🧸`;
|
||||||
window.history.pushState({url}, '', url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!preventPushState) {
|
||||||
|
window.history.pushState({url}, '', url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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