
- global app config via serializer/deserializer - home link becomes router link if js enabled
188 lines
5.1 KiB
Text
188 lines
5.1 KiB
Text
---
|
|
import Serialize from '@ayco/astro-resume';
|
|
export interface Props {
|
|
skipSave?: boolean
|
|
}
|
|
---
|
|
<div id="library">
|
|
<span id="heading"></span>
|
|
<ul id="post-list"></ul>
|
|
</div>
|
|
|
|
<Serialize id="preferences" data={{...Astro.props}} />
|
|
|
|
<script>
|
|
import {deserialize} from '@ayco/astro-resume';
|
|
import type { Props } from './Library.astro';
|
|
import type { AppConfig } from '../pages/index.astro';
|
|
import { getPostCard, renderPost } from '../utils/library'
|
|
const cache = await caches.open('cozy-reader');
|
|
let url= new URL(window.location.href);
|
|
// only cached unencoded url param
|
|
const urlParam = url.searchParams.get('url')
|
|
if (urlParam) {
|
|
url = new URL(`${url.origin}/?url=${urlParam}`);
|
|
}
|
|
const response = await cache.match(url);
|
|
const { skipSave } = deserialize<Props>('preferences');
|
|
const { routerOutlet } = deserialize<AppConfig>('app-config');
|
|
const includesAppURL = urlParam?.includes(window.location.origin)
|
|
|
|
if (!response && !skipSave && !includesAppURL) {
|
|
await cache.add(url);
|
|
}
|
|
|
|
const cachedRequests = (await cache.keys())
|
|
.filter(request => {
|
|
const urlObj = new URL(request.url);
|
|
const urlParam = urlObj.searchParams.get('url');
|
|
|
|
return urlObj.search !== ''
|
|
&& !urlParam?.startsWith(window.location.origin)
|
|
&& urlParam !== ''
|
|
&& urlParam !== 'null';
|
|
});
|
|
|
|
if(cachedRequests?.length && routerOutlet !== null) {
|
|
const list = document.querySelector('#post-list');
|
|
const heading = document.querySelector('#library span#heading') as HTMLHeadingElement;
|
|
heading.innerHTML = 'History';
|
|
|
|
cachedRequests
|
|
.reverse()
|
|
.forEach(async (request) => {
|
|
const {url} = request;
|
|
const link = document.createElement('a');
|
|
|
|
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('meta[property="cozy:title"]')?.getAttribute('content');
|
|
if (title === 'Something is not right') {
|
|
cache.delete(url);
|
|
return; // temporary fix for deleting cached errors
|
|
}
|
|
const postCard = getPostCard(html);
|
|
link.innerHTML = postCard;
|
|
|
|
link.href = url;
|
|
link.onclick = async (e) => {
|
|
e.preventDefault();
|
|
localStorage.setItem('scrollPosition', window.scrollY.toString());
|
|
scrollTo(0,0);
|
|
renderPost(responseText, url, routerOutlet)
|
|
}
|
|
const item = document.createElement('li');
|
|
item.appendChild(link);
|
|
list?.appendChild(item);
|
|
});
|
|
});
|
|
|
|
window.addEventListener('popstate', async (data) => {
|
|
let url = data.state?.url;
|
|
let isHome = false;
|
|
|
|
if (!url) {
|
|
url = window.location.href;
|
|
isHome = true;
|
|
} else {
|
|
// replace scrollPosition
|
|
localStorage.setItem('scrollPosition', window.scrollY.toString());
|
|
}
|
|
|
|
const fullResponse = await cache.match(url)
|
|
fullResponse?.text().then(data => {
|
|
const responseText = data;
|
|
renderPost(responseText, url, routerOutlet, true);
|
|
if (isHome) {
|
|
const scrollPosition = localStorage.getItem('scrollPosition');
|
|
scrollTo(0, scrollPosition ? parseInt(scrollPosition) : 0);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
#library {
|
|
span#heading {
|
|
color: #555;
|
|
font-size: small;
|
|
text-transform: uppercase;
|
|
}
|
|
}
|
|
#post-list {
|
|
|
|
/**
|
|
`:global` is needed for elements not generated by Astro
|
|
- can be improved by CSS in JS, but... this is fine
|
|
*/
|
|
:global(li) {
|
|
list-style: none;
|
|
width: calc(100% + 40px);
|
|
margin-left: -40px;
|
|
|
|
:global(a) {
|
|
text-decoration: none;
|
|
color: #000;
|
|
|
|
:global(h3) {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
:global(.post-card) {
|
|
padding-bottom: 1rem;
|
|
|
|
:global(.post-card__image) {
|
|
float: left;
|
|
margin: 0.25rem 0.5rem 0.25rem 0;
|
|
|
|
:global(img, svg) {
|
|
width: 70px;
|
|
height: 70px;
|
|
object-fit: cover;
|
|
border-radius: 5px;
|
|
border: 1px solid #eee;
|
|
}
|
|
:global(svg) {
|
|
color: #ccc;
|
|
padding: 0.5rem;
|
|
}
|
|
}
|
|
}
|
|
:global(.post-card__content) {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
min-height: calc(70px + 0.5rem);
|
|
}
|
|
:global(.post-card__title, .post-card__description) {
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
}
|
|
:global(.post-card__meta, .post-card__description){
|
|
font-size: smaller;
|
|
color: #555;
|
|
}
|
|
:global(.post-card__meta) {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
|
|
* {
|
|
flex: 1;
|
|
}
|
|
|
|
:global(.post-card__source) {
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|