Flowbite and commit feed #2

Merged
christian merged 3 commits from flowbite-svelte into main 2024-05-19 11:08:54 +00:00
7 changed files with 314 additions and 41 deletions

236
package-lock.json generated
View File

@ -10,7 +10,8 @@
"dependencies": {
"@sveltejs/adapter-vercel": "^5.3.0",
"geist": "^1.3.0",
"moment": "^2.30.1"
"moment": "^2.30.1",
"pnpm": "^9.1.1"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0",
@ -21,6 +22,8 @@
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.35.1",
"flowbite": "^2.3.0",
"flowbite-svelte": "^0.46.1",
"postcss": "^8.4.38",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
@ -53,6 +56,18 @@
"node": ">=6.0.0"
}
},
"node_modules/@babel/runtime": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz",
"integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==",
"dev": true,
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
@ -454,6 +469,31 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@floating-ui/core": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz",
"integrity": "sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==",
"dev": true,
"dependencies": {
"@floating-ui/utils": "^0.2.0"
}
},
"node_modules/@floating-ui/dom": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz",
"integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==",
"dev": true,
"dependencies": {
"@floating-ui/core": "^1.0.0",
"@floating-ui/utils": "^0.2.0"
}
},
"node_modules/@floating-ui/utils": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
"integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==",
"dev": true
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@ -816,6 +856,16 @@
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz",
"integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ=="
},
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"dev": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@rollup/pluginutils": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
@ -1185,6 +1235,12 @@
"node": ">=16"
}
},
"node_modules/@yr/monotone-cubic-spline": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz",
"integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==",
"dev": true
},
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -1287,6 +1343,21 @@
"node": ">= 8"
}
},
"node_modules/apexcharts": {
"version": "3.49.1",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.49.1.tgz",
"integrity": "sha512-MqGtlq/KQuO8j0BBsUJYlRG8VBctKwYdwuBtajHgHTmSgUU3Oai+8oYN/rKCXwXzrUlYA+GiMgotAIbXY2BCGw==",
"dev": true,
"dependencies": {
"@yr/monotone-cubic-spline": "^1.0.3",
"svg.draggable.js": "^2.2.2",
"svg.easing.js": "^2.0.0",
"svg.filter.js": "^2.0.2",
"svg.pathmorphing.js": "^0.1.3",
"svg.resize.js": "^1.4.3",
"svg.select.js": "^3.0.1"
}
},
"node_modules/aproba": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
@ -2165,6 +2236,35 @@
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
"dev": true
},
"node_modules/flowbite": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/flowbite/-/flowbite-2.3.0.tgz",
"integrity": "sha512-pm3JRo8OIJHGfFYWgaGpPv8E+UdWy0Z3gEAGufw+G/1dusaU/P1zoBLiQpf2/+bYAi+GBQtPVG86KYlV0W+AFQ==",
"dev": true,
"dependencies": {
"@popperjs/core": "^2.9.3",
"mini-svg-data-uri": "^1.4.3"
}
},
"node_modules/flowbite-svelte": {
"version": "0.46.1",
"resolved": "https://registry.npmjs.org/flowbite-svelte/-/flowbite-svelte-0.46.1.tgz",
"integrity": "sha512-GMQP4Fxn4mYu12XTNRbOHMYMklbP29sKFZUZYekryxhWak2zbSlI1ozhBtnrD2WDbFBPqZ64IcyButOkYpz+WQ==",
"dev": true,
"dependencies": {
"@floating-ui/dom": "^1.6.3",
"apexcharts": "^3.48.0",
"flowbite": "^2.3.0",
"tailwind-merge": "^2.3.0"
},
"engines": {
"node": ">=18.0.0",
"pnpm": ">=8.0.0"
},
"peerDependencies": {
"svelte": "^3.55.1 || ^4.0.0"
}
},
"node_modules/foreground-child": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@ -2754,6 +2854,15 @@
"node": ">=8.6"
}
},
"node_modules/mini-svg-data-uri": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
"integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
"dev": true,
"bin": {
"mini-svg-data-uri": "cli.js"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -3210,6 +3319,21 @@
"node": ">= 6"
}
},
"node_modules/pnpm": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/pnpm/-/pnpm-9.1.1.tgz",
"integrity": "sha512-FOkVdZwR936sB/q6TQGcGT7IY3Ip5i7Jnu+3zzw7dcZER4grfEhRQkUe46a0CAWc37e3+gNBuXXxLQ92KccRlQ==",
"bin": {
"pnpm": "bin/pnpm.cjs",
"pnpx": "bin/pnpx.cjs"
},
"engines": {
"node": ">=18.12"
},
"funding": {
"url": "https://opencollective.com/pnpm"
}
},
"node_modules/postcss": {
"version": "8.4.38",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
@ -3504,6 +3628,12 @@
"node": ">=8.10.0"
}
},
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true
},
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@ -3992,6 +4122,110 @@
"@types/estree": "^1.0.0"
}
},
"node_modules/svg.draggable.js": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
"dev": true,
"dependencies": {
"svg.js": "^2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.easing.js": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
"integrity": "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==",
"dev": true,
"dependencies": {
"svg.js": ">=2.3.x"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.filter.js": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
"integrity": "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==",
"dev": true,
"dependencies": {
"svg.js": "^2.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.js": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==",
"dev": true
},
"node_modules/svg.pathmorphing.js": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
"dev": true,
"dependencies": {
"svg.js": "^2.4.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.resize.js": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
"dev": true,
"dependencies": {
"svg.js": "^2.6.5",
"svg.select.js": "^2.1.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.resize.js/node_modules/svg.select.js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
"dev": true,
"dependencies": {
"svg.js": "^2.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.select.js": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
"dev": true,
"dependencies": {
"svg.js": "^2.6.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/tailwind-merge": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.3.0.tgz",
"integrity": "sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.24.1"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
}
},
"node_modules/tailwindcss": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",

View File

@ -18,6 +18,8 @@
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.35.1",
"flowbite": "^2.3.0",
"flowbite-svelte": "^0.46.1",
"postcss": "^8.4.38",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
@ -29,6 +31,7 @@
"dependencies": {
"@sveltejs/adapter-vercel": "^5.3.0",
"geist": "^1.3.0",
"moment": "^2.30.1"
"moment": "^2.30.1",
"pnpm": "^9.1.1"
}
}

View File

@ -1,24 +1,21 @@
<script>
import { AccordionItem } from 'flowbite-svelte';
import moment from 'moment';
export let isOpen = false;
export let link;
export let title;
export let description;
export let published;
export let author;
export let guid;
const pubAgo = moment(published).fromNow();
</script>
<div
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"
>
<div class="mb-2 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white">
{@html title}
</div>
<div class="font-normal hover:text-slate-400">
{@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>
<AccordionItem {...isOpen ? { open: true } : {}}>
<span slot="header">{@html title} - {pubAgo}</span>
<div class="flex flex-col">
{#if description}
<p>with the message:</p>
<code>{@html description}</code>
{/if}
<a class="hover:text-slate-100" href={link}>view commit for more details</a>
</div>
</AccordionItem>

View File

@ -4,6 +4,6 @@
</script>
<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} />
</div>

View File

@ -2,13 +2,14 @@
import { onMount } from 'svelte';
import Spinner from './Spinner.svelte';
import Commit from './Commit.svelte';
import { Accordion } from 'flowbite-svelte';
export let url;
let feed = null;
let error = null;
async function fetchFeed() {
async function fetchFeed(url) {
try {
const response = await fetch(url);
if (!response.ok) {
@ -17,14 +18,32 @@
const text = await response.text();
const parser = new DOMParser();
const xml = parser.parseFromString(text, 'application/xml');
const items = Array.from(xml.querySelectorAll('item')).map((item) => ({
const items = Array.from(xml.querySelectorAll('item')).map((item) => {
// Parse description
const descriptionElement = item.querySelector('description');
const descriptionContent = descriptionElement ? descriptionElement.textContent : '';
const tempDivDescription = document.createElement('div');
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,
description: item.querySelector('description')?.textContent,
published: item.querySelector('pubDate')?.textContent,
author: item.querySelector('author')?.textContent,
guid: item.querySelector('guid')?.textContent
}));
};
});
feed = items;
} catch (err) {
error = err.message;
@ -32,7 +51,7 @@
}
onMount(() => {
fetchFeed();
fetchFeed(url);
});
</script>
@ -43,9 +62,15 @@
<Spinner />
{:else}
<div class="flex flex-col gap-2">
{#each feed.slice(0, 5) as commit}
<Commit {...commit} />
<Accordion>
{#each feed.slice(0, 5) as commit, i}
{#if i === 0}
<Commit {...commit} isOpen={true} />
{:else}
<Commit {...commit} open={false} />
{/if}
{/each}
</Accordion>
</div>
{/if}
</div>

View File

@ -1,8 +1,7 @@
<script>
import { fade } from 'svelte/transition';
import RssFeed from '../../lib/RssFeed.svelte';
import RssContainer from '../../lib/RssContainer.svelte';
import { Alert } from 'flowbite-svelte';
const projectRssUrl = 'https://gitea.rannes.dev/rannes.dev/my-portfolio.rss';
</script>

View File

@ -1,14 +1,29 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{html,js,svelte,ts}'],
content: ['./src/**/*.{html,js,svelte,ts}', './node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}'],
plugins: [require('flowbite/plugin')],
darkMode: 'selector',
theme: {
extend: {
colors: {
// flowbite-svelte
primary: {
50: '#FFF5F2',
100: '#FFF1EE',
200: '#FFE4DE',
300: '#FFD5CC',
400: '#FFBCAD',
500: '#FE795D',
600: '#EF562F',
700: '#EB4F27',
800: '#CC4522',
900: '#A5371B'
}
},
fontFamily: {
"jose": ["Josefin Sans", "sans-serif"]
}
},
},
plugins: [],
darkMode: 'class',
}
}
}