Added tailwind svelte component framework

This commit is contained in:
Clément Le Bihan
2024-05-05 16:33:17 +02:00
parent 0ad421b10c
commit 37dacb0d79
22 changed files with 4206 additions and 2553 deletions
+3770 -2469
View File
File diff suppressed because it is too large Load Diff
+31 -24
View File
@@ -1,26 +1,33 @@
{
"name": "web",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
},
"devDependencies": {
"@iconify-json/mingcute": "^1.1.17",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"svelte": "^4.2.7",
"svelte-check": "^3.6.0",
"svelte-time": "^0.9.0",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"unplugin-icons": "^0.19.0",
"vite": "^5.0.3"
},
"type": "module"
"name": "web",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
},
"devDependencies": {
"@iconify-json/mingcute": "^1.1.17",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"autoprefixer": "^10.4.16",
"flowbite": "^2.3.0",
"flowbite-svelte": "^0.46.1",
"flowbite-svelte-icons": "1.6",
"postcss": "^8.4.32",
"postcss-load-config": "^5.0.2",
"svelte": "^4.2.7",
"svelte-check": "^3.6.0",
"svelte-time": "^0.9.0",
"tailwindcss": "^3.3.6",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"unplugin-icons": "^0.19.0",
"vite": "^5.0.3"
},
"type": "module"
}
+13
View File
@@ -0,0 +1,13 @@
const tailwindcss = require("tailwindcss");
const autoprefixer = require("autoprefixer");
const config = {
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer,
],
};
module.exports = config;
+1
View File
@@ -16,6 +16,7 @@
</body>
<style>
body {
margin-right: 10%;
font-family: 'Hanken Grotesk', sans-serif;
font-optical-sizing: auto;
font-weight: 400;
+4
View File
@@ -0,0 +1,4 @@
/* Write your global styles here, in PostCSS syntax */
@tailwind base;
@tailwind components;
@tailwind utilities;
+67
View File
@@ -0,0 +1,67 @@
<script context="module" lang="ts">
import { writable, type Writable } from 'svelte/store';
export interface TabCtxType {
activeClasses: string;
inactiveClasses: string;
selected: Writable<HTMLElement>;
}
</script>
<script lang="ts">
// import { twMerge } from 'tailwind-merge';
import { setContext } from 'svelte';
export let tabStyle: 'full' | 'pill' | 'underline' | 'none' = 'none';
export let defaultClass: string = 'flex flex-wrap space-x-2 rtl:space-x-reverse';
export let contentClass: string = 'p-4 bg-gray-50 rounded-lg dark:bg-gray-800 mt-4';
export let divider: boolean = true;
export let activeClasses: string = 'p-4 text-primary-600 bg-gray-100 rounded-t-lg dark:bg-gray-800 dark:text-primary-500';
export let inactiveClasses: string = 'p-4 text-gray-500 rounded-t-lg hover:text-gray-600 hover:bg-gray-50 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-300';
// styles
const styledActiveClasses = {
full: 'p-4 w-full group-first:rounded-s-lg group-last:rounded-e-lg text-gray-900 bg-gray-100 focus:ring-4 focus:ring-primary-300 focus:outline-none dark:bg-gray-700 dark:text-white',
pill: 'py-3 px-4 text-white bg-primary-600 rounded-lg',
underline: 'p-4 text-primary-600 border-b-2 border-primary-600 dark:text-primary-500 dark:border-primary-500',
none: ''
};
const styledInactiveClasses = {
full: 'p-4 w-full group-first:rounded-s-lg group-last:rounded-e-lg text-gray-500 dark:text-gray-400 bg-white hover:text-gray-700 hover:bg-gray-50 focus:ring-4 focus:ring-primary-300 focus:outline-none dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700',
pill: 'py-3 px-4 text-gray-500 rounded-lg hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-white',
underline: 'p-4 border-b-2 border-transparent hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 text-gray-500 dark:text-gray-400',
none: ''
};
const ctx: TabCtxType = {
activeClasses: styledActiveClasses[tabStyle] || activeClasses,
inactiveClasses: styledInactiveClasses[tabStyle] || inactiveClasses,
selected: writable<HTMLElement>()
};
$: divider = ['full', 'pill'].includes(tabStyle) ? false : divider;
setContext('ctx', ctx);
function init(node: HTMLElement) {
const destroy = ctx.selected.subscribe((x: HTMLElement) => {
if (x) node.replaceChildren(x);
});
return { destroy };
}
// $: ulClass = twMerge(defaultClass, tabStyle === 'underline' && '-mb-px', $$props.class);
</script>
<ul class={ulClass}>
<slot {tabStyle} />
</ul>
{#if divider}
<slot name="divider">
<div class="h-px bg-gray-200 dark:bg-gray-700" />
</slot>
{/if}
+51
View File
@@ -0,0 +1,51 @@
<script lang="ts">
import type { Feed } from "$lib/types";
import TagList from "$lib/posts/tag-list.svelte";
import User from "virtual:icons/mingcute/user-5-line";
export let feed: Feed;
let viewTags = false;
let hover = false;
</script>
<article>
<div>
<img src={feed.faviconUrl} alt={feed.title} />
<h3>{feed.title}</h3>
</div>
<div>
<span>{feed.url}</span>
</div>
{#if feed.submitter}
<div>
Added by
<User />
<span title={feed.submitter.email}>{feed.submitter.name}</span>
</div>
{/if}
{#if viewTags}
<TagList tags={feed.tags} />
{:else}
<button on:click={() => (viewTags = true)}>View tags</button>
{/if}
</article>
<style>
div {
display: flex;
align-items: center;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
gap: 6px;
}
article {
border-radius: 10px;
padding: 0.7rem;
}
img {
width: 40px;
height: 40px;
margin-right: 0.5rem;
}
</style>
+29
View File
@@ -0,0 +1,29 @@
<script lang="ts">
import Card from './card.svelte';
import type { Feed } from '$lib/types';
export let feeds: Feed[] = [];
</script>
<section>
<h1>All Feeds</h1>
<h1>Feeds</h1>
<ul>
{#each feeds as feed}
<li>
<Card {feed} />
</li>
{/each}
</ul>
</section>
<style>
ul {
list-style: none;
padding: 0;
display: flex;
flex-direction: column;
gap: 1rem;
}
</style>
+5 -5
View File
@@ -27,18 +27,18 @@
<h2>{post.title}</h2>
<p>{post.content}</p>
</content>
<footer>
<!-- <footer>
<TagList tags={post.feed.tags} />
</footer>
</footer> -->
</article>
<style>
article {
border-radius: 10px;
/* box-shadow: 0px 0px 12px 9px rgba(0, 0, 0, 0.28); */
/* border-radius: 10px;
box-shadow: 0px 0px 12px 9px rgba(0, 0, 0, 0.28);
border: 1px solid #e0e0e0;
padding: 0.7rem;
background-color: rgb(220, 220, 220);
background-color: rgb(220, 220, 220); */
}
.origin {
+11 -10
View File
@@ -4,15 +4,18 @@
export let posts: Post[] = [];
</script>
<h1>Posts</h1>
<div>
<h1>Posts</h1>
<ul>
{#each posts as post}
<li>
<Card {post} />
</li>
{/each}
</ul>
<ul>
{#each posts as post}
<li>
<Card {post} />
</li>
<hr>
{/each}
</ul>
</div>
<style>
ul {
@@ -20,7 +23,5 @@
padding: 0;
display: flex;
flex-direction: column;
gap: 1rem;
}
</style>
+1 -1
View File
@@ -1,7 +1,7 @@
<script lang="ts">
export let tags: string[] = [];
export let nbNonExpandedTags = tags.length;
const nbNonExpandedTags = 5;
let isExpanded = false;
$: tagsToDisplay = isExpanded ? tags : tags.slice(0, nbNonExpandedTags);
</script>
+2 -1
View File
@@ -1,2 +1,3 @@
export type { Feed } from "./types/feed.type";
export type { Post } from "./types/post.type";
export type { Post } from "./types/post.type";
export type { User } from "./types/user.type";
+5
View File
@@ -1,7 +1,12 @@
import type { User } from "./user.type";
export type Feed = {
id: string;
title: string;
url: string;
faviconUrl: string;
tags: string[];
submitterId: string;
addedDate: Date;
submitter?: User;
}
+5
View File
@@ -0,0 +1,5 @@
export type User = {
id: string;
name: string;
email: string;
}
+5
View File
@@ -0,0 +1,5 @@
<script lang="ts">
import Card from "$lib/feeds/card.svelte";
import type { Feed } from "$lib/types";
export let data;
</script>
+1
View File
@@ -0,0 +1 @@
<script>import "../app.pcss";</script><slot></slot>
+38 -23
View File
@@ -1,6 +1,36 @@
import type { Post } from "$lib/types";
import type { Post, Feed } from "$lib/types";
const data: Post[] = [
const feeds: Feed[] = [
{
id: "1",
title: "The first feed",
url: "https://example.com/feed",
faviconUrl: "https://kit.svelte.dev/favicon.png",
tags: ["tag1", "tag2"],
submitterId: "1",
addedDate: new Date(),
},
{
id: "2",
title: "Phoronix",
url: "https://www.phoronix.com",
faviconUrl: "https://www.phoronix.com/favicon.ico",
tags: ["linux", "kernel", "gnu", "gnu/linux", "gnu+linux", "gnu linux"],
submitterId: "1",
addedDate: new Date(),
},
{
id: "3",
title: "LWN.net",
url: "https://lwn.net",
faviconUrl: "https://lwn.net/favicon.ico",
tags: ["linux", "kernel", "gnu", "gnu/linux", "gnu+linux", "gnu linux"],
submitterId: "1",
addedDate: new Date(),
},
];
const posts: Post[] = [
{
id: "1",
title: "The first post",
@@ -12,13 +42,7 @@ const data: Post[] = [
isIgnored: false,
isReadLater: false,
author: "John Doe",
feed: {
id: "1",
title: "The first feed",
url: "https://example.com/feed",
faviconUrl: "https://kit.svelte.dev/favicon.png",
tags: ["tag1", "tag2"],
},
feed: feeds[0],
},
{
id: "2",
@@ -30,23 +54,14 @@ const data: Post[] = [
isBookmarked: true,
isIgnored: false,
isReadLater: false,
feed: {
id: "2",
title: "Phoronix",
url: "https://www.phoronix.com",
faviconUrl: "https://www.phoronix.com/favicon.ico",
// put 50 tags in the array linked with linux world
tags: [
"linux", "kernel", "gnu", "gnu/linux", "gnu+linux", "gnu linux",
"wine", "winehq", "wine-staging", "wine-devel", "winehq-devel", "winehq-staging",
"mesa", "mesa3d", "mesa 3d", "mesa-3d", "mesa3d-devel", "mesa3d-staging",
"NVK"
],
},
feed: feeds[1],
}
];
export function load() {
return { data };
return {
posts,
feeds
};
}
+38 -9
View File
@@ -1,19 +1,48 @@
<script>
<script lang="ts">
export let data;
import List from "$lib/posts/list.svelte";
import {
BottomNav,
BottomNavItem,
Skeleton,
ImagePlaceholder,
} from "flowbite-svelte";
import List from "$lib/posts/list.svelte";
import {
HomeSolid,
WalletSolid,
AdjustmentsVerticalOutline,
UserCircleSolid,
} from "flowbite-svelte-icons";
</script>
<main>
<h1>Welcome to SvelteKit</h1>
<p>
Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation
</p>
<List posts={data.data} />
<section>
<List posts={data.posts} />
</section>
<footer>
<BottomNav position="absolute" classInner="grid-cols-2">
<BottomNavItem btnName="Posts">
<HomeSolid
class="w-6 h-6 mb-1 text-gray-500 dark:text-gray-400 group-hover:text-primary-600 dark:group-hover:text-primary-500"
/>
</BottomNavItem>
<BottomNavItem btnName="Profile">
<UserCircleSolid
class="w-6 h-6 mb-1 text-gray-500 dark:text-gray-400 group-hover:text-primary-600 dark:group-hover:text-primary-500"
/>
</BottomNavItem>
</BottomNav>
</footer>
</main>
<style>
main {
margin-left: 10%;
display: flex;
}
.sidebar {
display: flex;
flex-direction: column-reverse;
width: 400px;
height: 100vh;
}
</style>
+62
View File
@@ -0,0 +1,62 @@
import type { Feed } from "$lib/types";
const feeds: Feed[] = [
{
id: "1",
title: "The first feed",
url: "https://example.com/feed",
faviconUrl: "https://kit.svelte.dev/favicon.png",
tags: ["tag1", "tag2"],
submitterId: "1",
addedDate: new Date(),
},
{
id: "2",
title: "Phoronix",
url: "https://www.phoronix.com",
faviconUrl: "https://www.phoronix.com/favicon.ico",
tags: ["linux", "kernel", "gnu", "gnu/linux", "gnu+linux", "gnu linux"],
submitterId: "1",
addedDate: new Date(),
},
{
id: "3",
title: "LWN.net",
url: "https://lwn.net",
faviconUrl: "https://lwn.net/favicon.ico",
tags: ["linux", "kernel", "gnu", "gnu/linux", "gnu+linux", "gnu linux"],
submitterId: "1",
addedDate: new Date(),
},
{
id: "4",
title: "Reddit",
url: "https://www.reddit.com",
faviconUrl: "https://www.reddit.com/favicon.ico",
tags: ["social", "news", "discussion"],
submitterId: "1",
addedDate: new Date(),
submitter: {
id: "1",
name: "John Doe",
email: "john.doe@gmail.com"
}
},
{
id: "5",
title: "Hacker News",
url: "https://news.ycombinator.com",
faviconUrl: "https://news.ycombinator.com/favicon.ico",
tags: ["news", "discussion"],
submitterId: "1",
addedDate: new Date(),
}
];
export function load() {
return {
feeds
};
}
+26
View File
@@ -0,0 +1,26 @@
<script lang="ts">
import Card from "$lib/feeds/card.svelte";
export let data;
</script>
<section>
<h1>All Feeds</h1>
<h1>Feeds</h1>
<ul>
{#each data.feeds as feed}
<Card {feed} />
{/each}
</ul>
</section>
<style>
ul {
list-style: none;
padding: 0;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 10px;
align-items: stretch;
justify-items: stretch;
}
</style>
+11 -11
View File
@@ -1,18 +1,18 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import adapter from "@sveltejs/adapter-auto";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: [vitePreprocess({})],
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
}
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter(),
},
};
export default config;
+30
View File
@@ -0,0 +1,30 @@
/** @type {import('tailwindcss').Config}*/
const config = {
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'
}
}
}
}
};
module.exports = config;