Flowbite and commit feed #2
@ -1,24 +1,21 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import { AccordionItem } from 'flowbite-svelte';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
export let isOpen = false;
|
||||||
export let link;
|
export let link;
|
||||||
export let title;
|
export let title;
|
||||||
export let description;
|
export let description;
|
||||||
export let published;
|
export let published;
|
||||||
export let author;
|
|
||||||
export let guid;
|
|
||||||
const pubAgo = moment(published).fromNow();
|
const pubAgo = moment(published).fromNow();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<AccordionItem {...isOpen ? { open: true } : {}}>
|
||||||
class="block p-6 bg-white border border-gray-200 rounded-lg shadow hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700"
|
<span slot="header">{@html title} - {pubAgo}</span>
|
||||||
>
|
<div class="flex flex-col">
|
||||||
<div class="mb-2 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white">
|
{#if description}
|
||||||
{@html title}
|
<p>with the message:</p>
|
||||||
|
<code>{description}</code>
|
||||||
|
{/if}
|
||||||
|
<a class="hover:text-slate-100" href={link}>view commit</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="font-normal hover:text-slate-400">
|
</AccordionItem>
|
||||||
{@html description}
|
|
||||||
</div>
|
|
||||||
<div>commited {pubAgo} by {@html author}</div>
|
|
||||||
<a class="hover:text-slate-400 underline" href={link}>view commit</a>
|
|
||||||
<div class="text-xs text-slate-400">guid:{guid}</div>
|
|
||||||
</div>
|
|
||||||
|
@ -4,6 +4,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl mt-4 font-normal">Here are the last 5 commits:</h2>
|
<h2 class="text-xl mt-4 font-normal">Here are the 5 most recent commits</h2>
|
||||||
<RssFeed {url} />
|
<RssFeed {url} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import Spinner from './Spinner.svelte';
|
import Spinner from './Spinner.svelte';
|
||||||
import Commit from './Commit.svelte';
|
import Commit from './Commit.svelte';
|
||||||
|
import { Accordion } from 'flowbite-svelte';
|
||||||
|
|
||||||
export let url;
|
export let url;
|
||||||
|
|
||||||
let feed = null;
|
let feed = null;
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
async function fetchFeed() {
|
async function fetchFeed(url) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@ -17,14 +18,32 @@
|
|||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const xml = parser.parseFromString(text, 'application/xml');
|
const xml = parser.parseFromString(text, 'application/xml');
|
||||||
const items = Array.from(xml.querySelectorAll('item')).map((item) => ({
|
|
||||||
title: item.querySelector('title')?.textContent,
|
const items = Array.from(xml.querySelectorAll('item')).map((item) => {
|
||||||
link: item.querySelector('link')?.textContent,
|
// Parse description
|
||||||
description: item.querySelector('description')?.textContent,
|
const descriptionElement = item.querySelector('description');
|
||||||
published: item.querySelector('pubDate')?.textContent,
|
const descriptionContent = descriptionElement ? descriptionElement.textContent : '';
|
||||||
author: item.querySelector('author')?.textContent,
|
const tempDivDescription = document.createElement('div');
|
||||||
guid: item.querySelector('guid')?.textContent
|
tempDivDescription.innerHTML = descriptionContent;
|
||||||
}));
|
const firstLinkDescription = tempDivDescription.querySelector('a')
|
||||||
|
? tempDivDescription.querySelector('a').href
|
||||||
|
: '';
|
||||||
|
if (tempDivDescription.querySelector('a')) {
|
||||||
|
tempDivDescription.querySelector('a').remove();
|
||||||
|
}
|
||||||
|
const cleanedDescription = tempDivDescription.innerHTML.trim();
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: item.querySelector('title')?.textContent,
|
||||||
|
description: cleanedDescription,
|
||||||
|
commit: firstLinkDescription,
|
||||||
|
link: item.querySelector('link')?.textContent,
|
||||||
|
published: item.querySelector('pubDate')?.textContent,
|
||||||
|
author: item.querySelector('author')?.textContent,
|
||||||
|
guid: item.querySelector('guid')?.textContent
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
feed = items;
|
feed = items;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = err.message;
|
error = err.message;
|
||||||
@ -32,7 +51,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
fetchFeed();
|
fetchFeed(url);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -43,9 +62,15 @@
|
|||||||
<Spinner />
|
<Spinner />
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
{#each feed.slice(0, 5) as commit}
|
<Accordion>
|
||||||
<Commit {...commit} />
|
{#each feed.slice(0, 5) as commit, i}
|
||||||
{/each}
|
{#if i === 0}
|
||||||
|
<Commit {...commit} isOpen={true} />
|
||||||
|
{:else}
|
||||||
|
<Commit {...commit} open={false} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</Accordion>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user