changed from modal to client-side router
This commit is contained in:
parent
4fa38b5252
commit
f5001cff04
@ -5,7 +5,7 @@ meta {
|
||||
}
|
||||
|
||||
get {
|
||||
url: https://api.simkl.com/anime/40398?extended=full
|
||||
url: https://api.simkl.com/anime/862523?extended=full
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
"svelte": "^3.49.0",
|
||||
"svelte-check": "^2.8.0",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"svelte-spa-router": "^4.0.1",
|
||||
"tailwind-merge": "^2.4.0",
|
||||
"tailwindcss": "^3.4.6",
|
||||
"tslib": "^2.4.0",
|
||||
@ -24,7 +25,6 @@
|
||||
"vite": "^3.0.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ernane/svelte-star-rating": "^1.1.7",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"flowbite": "^2.4.1",
|
||||
"flowbite-svelte": "^0.46.15",
|
||||
|
@ -1,12 +1,10 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
aniListLoggedIn,
|
||||
anilistModal,
|
||||
aniListPrimary,
|
||||
aniListUser,
|
||||
aniListWatchlist,
|
||||
animePerPage,
|
||||
GetAniListSingleItemAndOpenModal,
|
||||
malLoggedIn,
|
||||
malPrimary,
|
||||
malUser,
|
||||
@ -14,10 +12,11 @@
|
||||
simklLoggedIn,
|
||||
simklUser,
|
||||
simklWatchList,
|
||||
title,
|
||||
watchListPage,
|
||||
simklPrimary,
|
||||
} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||
aniListAnime,
|
||||
GetAniListSingleItem,
|
||||
} from "./helperComponents/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import {
|
||||
CheckIfAniListLoggedIn,
|
||||
CheckIfMyAnimeListLoggedIn,
|
||||
@ -30,24 +29,20 @@
|
||||
SimklGetUserWatchlist,
|
||||
} from "../wailsjs/go/main/App";
|
||||
import {MediaListSort} from "./anilist/types/AniListTypes";
|
||||
import type {AniListCurrentUserWatchList} from "./anilist/types/AniListCurrentUserWatchListType"
|
||||
import Header from "./Header.svelte";
|
||||
import {Rating} from "flowbite-svelte";
|
||||
import {default as Modal} from "./modal/Modal.svelte"
|
||||
import ChangeDataDialogue from "./ChangeDataDialogue.svelte";
|
||||
import {onMount} from "svelte";
|
||||
import Pagination from "./Pagination.svelte";
|
||||
import Router from "svelte-spa-router"
|
||||
import Home from "./routes/Home.svelte";
|
||||
import {wrap} from "svelte-spa-router/wrap";
|
||||
import Spinner from "./helperComponents/Spinner.svelte";
|
||||
import Anime from "./routes/Anime.svelte";
|
||||
import Header from "./helperComponents/Header.svelte";
|
||||
|
||||
|
||||
let isAniListLoggedIn: boolean
|
||||
let isAniListPrimary: boolean
|
||||
let isMalPrimary: boolean
|
||||
let isSimklPrimary: boolean
|
||||
let aniListWatchListLoaded: AniListCurrentUserWatchList
|
||||
|
||||
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
|
||||
aniListPrimary.subscribe((value) => isAniListPrimary = value)
|
||||
aniListWatchlist.subscribe((value) => aniListWatchListLoaded = value)
|
||||
malPrimary.subscribe((value) => isMalPrimary = value)
|
||||
simklPrimary.subscribe(value => isSimklPrimary = value)
|
||||
|
||||
@ -56,7 +51,6 @@
|
||||
let perPage: number
|
||||
watchListPage.subscribe(value => page = value)
|
||||
animePerPage.subscribe(value => perPage = value)
|
||||
const size = "xl"
|
||||
|
||||
onMount(async () => {
|
||||
await CheckIfAniListLoggedIn().then(loggedIn => {
|
||||
@ -113,67 +107,18 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<Header/>
|
||||
|
||||
<main>
|
||||
{#if isAniListLoggedIn}
|
||||
<div class="mx-auto max-w-2xl p-4 sm:p-6 lg:max-w-7xl lg:px-8 relative items-center">
|
||||
<div id="spinner" role="status" class="fixed hidden -translate-x-1/2 -translate-y-1/2 top-2/4 left-1/2">
|
||||
<svg aria-hidden="true"
|
||||
class="inline w-16 h-16 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600"
|
||||
viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||
fill="currentColor"/>
|
||||
<path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"/>
|
||||
</svg>
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>
|
||||
<h1 class="text-left text-xl font-bold mb-4">Your AniList WatchList</h1>
|
||||
|
||||
<Pagination/>
|
||||
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
|
||||
{#each aniListWatchListLoaded.data.Page.mediaList as media}
|
||||
<div class="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg xl:aspect-h-8 xl:aspect-w-7">
|
||||
<div class="flex flex-col items-center group">
|
||||
<button on:click={() => {
|
||||
let spinner = document.querySelector("#spinner")
|
||||
spinner.classList.toggle("hidden", false)
|
||||
GetAniListSingleItemAndOpenModal(media.media.id, true).then(() => spinner.classList.toggle("hidden", true))
|
||||
}}>
|
||||
<img class="rounded-lg" src={media.media.coverImage.large} alt={
|
||||
media.media.title.english === "" ?
|
||||
media.media.title.romaji :
|
||||
media.media.title.english
|
||||
}/>
|
||||
</button>
|
||||
<Rating id="anime-rating" total={5} size={35} rating={media.score/2.0}/>
|
||||
<button class="mt-4 text-md font-semibold text-white-700"
|
||||
on:click={() => GetAniListSingleItemAndOpenModal(media.media.id, true)}>
|
||||
{
|
||||
media.media.title.english === "" ?
|
||||
media.media.title.romaji :
|
||||
media.media.title.english
|
||||
}
|
||||
</button>
|
||||
<p class="mt-1 text-lg font-medium text-white-900">{media.progress}
|
||||
/ {media.media.nextAiringEpisode.episode !== 0 ?
|
||||
media.media.nextAiringEpisode.episode - 1 : media.media.episodes}</p>
|
||||
{#if media.media.episodes > 0}
|
||||
<p class="mt-1 text-lg font-medium text-white-900">Total
|
||||
Episodes: {media.media.episodes}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<Pagination/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<Modal title={$title} bind:open={$anilistModal} {size} autoclose={false}>
|
||||
<ChangeDataDialogue/>
|
||||
</Modal>
|
||||
</main>
|
||||
<Header />
|
||||
<Router routes={{
|
||||
'/': Home,
|
||||
'/anime/:id': wrap({
|
||||
component: Anime,
|
||||
conditions: [
|
||||
async (detail) => {
|
||||
await GetAniListSingleItem(Number(detail.params.id), true)
|
||||
return Object.keys($aniListAnime).length!==0
|
||||
},
|
||||
],
|
||||
loadingComponent: Spinner
|
||||
}),
|
||||
// '*': "Not Found"
|
||||
}} />
|
||||
|
@ -1,9 +1,9 @@
|
||||
<script lang="ts">
|
||||
|
||||
import {Avatar} from "flowbite-svelte";
|
||||
import type {AniListUser} from "./anilist/types/AniListTypes";
|
||||
import type {AniListUser} from "../anilist/types/AniListTypes";
|
||||
import {aniListLoggedIn, aniListUser, malLoggedIn, simklLoggedIn, logoutOfAniList, logoutOfMAL, logoutOfSimkl} from "./GlobalVariablesAndHelperFunctions.svelte"
|
||||
import * as runtime from "../wailsjs/runtime";
|
||||
import * as runtime from "../../wailsjs/runtime";
|
||||
|
||||
let currentAniListUser: AniListUser
|
||||
let isAniListLoggedIn: boolean
|
@ -11,19 +11,18 @@
|
||||
LogoutSimkl,
|
||||
SimklGetUserWatchlist,
|
||||
SimklSearch
|
||||
} from "../wailsjs/go/main/App";
|
||||
} from "../../wailsjs/go/main/App";
|
||||
import type {
|
||||
AniListCurrentUserWatchList,
|
||||
AniListGetSingleAnime
|
||||
} from "./anilist/types/AniListCurrentUserWatchListType.js";
|
||||
} from "../anilist/types/AniListCurrentUserWatchListType.js";
|
||||
import {writable} from 'svelte/store'
|
||||
import type {SimklAnime, SimklUser, SimklWatchList} from "./simkl/types/simklTypes";
|
||||
import {type AniListUser, MediaListSort} from "./anilist/types/AniListTypes";
|
||||
import type {MALAnime, MALWatchlist, MyAnimeListUser} from "./mal/types/MALTypes";
|
||||
import type {SimklAnime, SimklUser, SimklWatchList} from "../simkl/types/simklTypes";
|
||||
import {type AniListUser, MediaListSort} from "../anilist/types/AniListTypes";
|
||||
import type {MALAnime, MALWatchlist, MyAnimeListUser} from "../mal/types/MALTypes";
|
||||
|
||||
export let aniListAnime = writable({} as AniListGetSingleAnime)
|
||||
export let title = writable("")
|
||||
export let anilistModal = writable(false);
|
||||
export let aniListLoggedIn = writable(false)
|
||||
export let simklLoggedIn = writable(false)
|
||||
export let malLoggedIn = writable(false)
|
||||
@ -38,6 +37,7 @@
|
||||
export let malWatchList = writable({} as MALWatchlist)
|
||||
export let malAnime = writable({} as MALAnime)
|
||||
export let simklAnime = writable({} as SimklAnime)
|
||||
export let loading = writable(false)
|
||||
|
||||
export let watchListPage = writable(1)
|
||||
export let animePerPage = writable(20)
|
||||
@ -60,7 +60,7 @@
|
||||
aniListAnime.subscribe(value => currentAniListAnime = value)
|
||||
|
||||
|
||||
export async function GetAniListSingleItemAndOpenModal(aniId: number, login: boolean): Promise<""> {
|
||||
export async function GetAniListSingleItem(aniId: number, login: boolean): Promise<""> {
|
||||
await GetAniListItem(aniId, login).then(aniListResult => {
|
||||
let finalResult: AniListGetSingleAnime
|
||||
finalResult = aniListResult
|
||||
@ -92,7 +92,6 @@
|
||||
simklAnime.set(value)
|
||||
})
|
||||
}
|
||||
anilistModal.set(true)
|
||||
return ""
|
||||
}
|
||||
|
@ -9,13 +9,14 @@
|
||||
malLoggedIn,
|
||||
malUser,
|
||||
simklLoggedIn,
|
||||
simklUser
|
||||
simklUser,
|
||||
} from "./GlobalVariablesAndHelperFunctions.svelte"
|
||||
import type {AniListUser} from "./anilist/types/AniListTypes";
|
||||
import type {SimklUser} from "./simkl/types/simklTypes";
|
||||
import type {MyAnimeListUser} from "./mal/types/MALTypes";
|
||||
import type {AniListUser} from "../anilist/types/AniListTypes";
|
||||
import type {SimklUser} from "../simkl/types/simklTypes";
|
||||
import type {MyAnimeListUser} from "../mal/types/MALTypes";
|
||||
import AvatarMenu from "./AvatarMenu.svelte";
|
||||
import logo from "./assets/images/AniTrackLogo.svg"
|
||||
import logo from "../assets/images/AniTrackLogo.svg"
|
||||
import {location, pop} from "svelte-spa-router";
|
||||
|
||||
let isAniListLoggedIn: boolean
|
||||
let isSimklLoggedIn: boolean
|
||||
@ -30,12 +31,20 @@
|
||||
aniListUser.subscribe((value) => currentAniListUser = value)
|
||||
simklUser.subscribe((value) => currentSimklUser = value)
|
||||
malUser.subscribe((value) => currentMALUser = value)
|
||||
|
||||
let currentLocation: any
|
||||
location.subscribe(value => currentLocation = value)
|
||||
console.log(currentLocation)
|
||||
</script>
|
||||
|
||||
<nav class="bg-white border-gray-200 dark:bg-gray-900">
|
||||
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
|
||||
<div class="flex items-center space-x-3 rtl:space-x-reverse">
|
||||
<img src={logo} class="h-8" alt="AniTrack Logo"/>
|
||||
{#if currentLocation === "/"}
|
||||
<a href="/"><img src={logo} class="h-8" alt="AniTrack Logo"/></a>
|
||||
{:else}
|
||||
<button on:click={() => pop()}><img src={logo} class="h-8" alt="AniTrack Logo"/></button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex items-center min-[950px]:order-2 space-x-3 min-[950px]:space-x-0 rtl:space-x-reverse">
|
||||
<div class="min-[950px]:block min-[950px]:mr-4">
|
@ -6,9 +6,9 @@
|
||||
watchListPage,
|
||||
} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||
|
||||
import type {AniListCurrentUserWatchList} from "./anilist/types/AniListCurrentUserWatchListType"
|
||||
import {GetAniListUserWatchingList} from "../wailsjs/go/main/App";
|
||||
import {MediaListSort} from "./anilist/types/AniListTypes";
|
||||
import type {AniListCurrentUserWatchList} from "../anilist/types/AniListCurrentUserWatchListType"
|
||||
import {GetAniListUserWatchingList} from "../../wailsjs/go/main/App";
|
||||
import {MediaListSort} from "../anilist/types/AniListTypes";
|
||||
|
||||
let aniListWatchListLoaded: AniListCurrentUserWatchList
|
||||
let page: number
|
@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
|
||||
import {AniListSearch} from "../wailsjs/go/main/App";
|
||||
import type {AniSearchList} from "./anilist/types/AniListTypes";
|
||||
import {GetAniListSingleItemAndOpenModal} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||
import {AniListSearch} from "../../wailsjs/go/main/App";
|
||||
import type {AniSearchList} from "../anilist/types/AniListTypes";
|
||||
import {GetAniListSingleItem, loading} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||
|
||||
let aniSearch = ""
|
||||
let aniListSearch: AniSearchList
|
||||
@ -55,18 +55,22 @@
|
||||
<li class="w-full">
|
||||
<div class="flex w-full items-start p-1 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white rounded-lg">
|
||||
<button on:click={() => {
|
||||
let spinner = document.querySelector("#spinner")
|
||||
spinner.classList.toggle("hidden", false)
|
||||
GetAniListSingleItemAndOpenModal(media.id, false).then(() => spinner.classList.toggle("hidden", true))
|
||||
loading.set(true)
|
||||
GetAniListSingleItem(media.id, false).then(() => {
|
||||
loading.set(false)
|
||||
searchDropdown()
|
||||
})
|
||||
}}
|
||||
>
|
||||
<img class="rounded-bl-lg rounded-tl-lg max-w-24 max-h-24" src={media.coverImage.large}
|
||||
alt="{media.title.english === '' || media.title.english === null ? media.title.romaji : media.title.english} Cover">
|
||||
</button>
|
||||
<button class="rounded-bl-lg rounded-tl-lg w-full h-24" on:click={() => {
|
||||
let spinner = document.querySelector("#spinner")
|
||||
spinner.classList.toggle("hidden", false)
|
||||
GetAniListSingleItemAndOpenModal(media.id, false).then(() => spinner.classList.toggle("hidden", true))
|
||||
loading.set(true)
|
||||
GetAniListSingleItem(media.id, false).then(() => {
|
||||
loading.set(false)
|
||||
searchDropdown()
|
||||
})
|
||||
}} >{media.title.english === '' || media.title.english === null ? media.title.romaji : media.title.english }</button>
|
||||
</div>
|
||||
</li>
|
11
frontend/src/helperComponents/Spinner.svelte
Normal file
11
frontend/src/helperComponents/Spinner.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<div id="spinner" role="status" class="fixed -translate-x-1/2 -translate-y-1/2 top-2/4 left-1/2">
|
||||
<svg aria-hidden="true"
|
||||
class="inline w-16 h-16 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600"
|
||||
viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||
fill="currentColor"/>
|
||||
<path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"/>
|
||||
</svg>
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>
|
68
frontend/src/helperComponents/WatchList.svelte
Normal file
68
frontend/src/helperComponents/WatchList.svelte
Normal file
@ -0,0 +1,68 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
aniListLoggedIn,
|
||||
aniListWatchlist,
|
||||
GetAniListSingleItem,
|
||||
loading,
|
||||
} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||
import {push} from "svelte-spa-router";
|
||||
import type {AniListCurrentUserWatchList} from "../anilist/types/AniListCurrentUserWatchListType"
|
||||
import {Rating} from "flowbite-svelte";
|
||||
import loader from '../helperFunctions/loader'
|
||||
|
||||
|
||||
let isAniListLoggedIn: boolean
|
||||
let aniListWatchListLoaded: AniListCurrentUserWatchList
|
||||
|
||||
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
|
||||
aniListWatchlist.subscribe((value) => aniListWatchListLoaded = value)
|
||||
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if isAniListLoggedIn}
|
||||
<div class="mx-auto max-w-2xl p-4 sm:p-6 lg:max-w-7xl lg:px-8 relative items-center">
|
||||
<h1 class="text-left text-xl font-bold mb-4">Your AniList WatchList</h1>
|
||||
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
|
||||
{#each aniListWatchListLoaded.data.Page.mediaList as media}
|
||||
<div use:loader={loading} class="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg xl:aspect-h-8 xl:aspect-w-7">
|
||||
<div class="flex flex-col items-center group">
|
||||
<button on:click={() => {
|
||||
push(`#/anime/${media.media.id}`)
|
||||
// loading.set(true)
|
||||
// GetAniListSingleItem(media.media.id, true).then(() => {
|
||||
// loading.set(false)
|
||||
//
|
||||
// })
|
||||
}}
|
||||
>
|
||||
<img class="rounded-lg" src={media.media.coverImage.large} alt={
|
||||
media.media.title.english === "" ?
|
||||
media.media.title.romaji :
|
||||
media.media.title.english
|
||||
}/>
|
||||
</button>
|
||||
<Rating id="anime-rating" total={5} size={35} rating={media.score/2.0}/>
|
||||
<button class="mt-4 text-md font-semibold text-white-700"
|
||||
on:click={() => GetAniListSingleItem(media.media.id, true)}>
|
||||
{
|
||||
media.media.title.english === "" ?
|
||||
media.media.title.romaji :
|
||||
media.media.title.english
|
||||
}
|
||||
</button>
|
||||
<p class="mt-1 text-lg font-medium text-white-900">{media.progress}
|
||||
/ {media.media.nextAiringEpisode.episode !== 0 ?
|
||||
media.media.nextAiringEpisode.episode - 1 : media.media.episodes}</p>
|
||||
{#if media.media.episodes > 0}
|
||||
<p class="mt-1 text-lg font-medium text-white-900">Total
|
||||
Episodes: {media.media.episodes}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
18
frontend/src/helperFunctions/loader.ts
Normal file
18
frontend/src/helperFunctions/loader.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import Spinner from '../helperComponents/Spinner.svelte';
|
||||
|
||||
export default (node: any, loading: any) => {
|
||||
let Spin: any
|
||||
loading.subscribe((loading: any) => {
|
||||
if(loading){
|
||||
Spin = new Spinner({
|
||||
target: node,
|
||||
intro: true
|
||||
})
|
||||
} else {
|
||||
if(Spin){
|
||||
Spin?.$destroy?.()
|
||||
Spin = undefined;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
<script>import { twMerge } from "tailwind-merge";
|
||||
import { Frame } from "flowbite-svelte";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import {CloseButton} from "flowbite-svelte";
|
||||
import focusTrap from "../../node_modules/flowbite-svelte/dist/utils/focusTrap.js";
|
||||
export let open = false;
|
||||
export let title = "";
|
||||
export let size = "md";
|
||||
export let color = "default";
|
||||
export let placement = "center";
|
||||
export let autoclose = false;
|
||||
export let outsideclose = false;
|
||||
export let dismissable = true;
|
||||
export let backdropClass = "fixed inset-0 z-20 bg-gray-900 bg-opacity-50 dark:bg-opacity-80";
|
||||
export let classBackdrop = void 0;
|
||||
export let dialogClass = "fixed top-0 start-0 end-0 h-modal md:inset-0 md:h-full z-30 w-full p-4 flex";
|
||||
export let classDialog = void 0;
|
||||
export let defaultClass = "relative flex flex-col mx-auto";
|
||||
export let headerClass = "flex justify-between items-center p-4 md:p-5 rounded-t-lg";
|
||||
export let classHeader = void 0;
|
||||
export let bodyClass = "p-4 md:p-5 space-y-4 flex-1 overflow-y-auto overscroll-contain";
|
||||
export let classBody = void 0;
|
||||
export let footerClass = "flex items-center p-4 md:p-5 space-x-3 rtl:space-x-reverse rounded-b-lg";
|
||||
export let classFooter = void 0;
|
||||
const dispatch = createEventDispatcher();
|
||||
$: dispatch(open ? "open" : "close");
|
||||
function prepareFocus(node) {
|
||||
const walker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT);
|
||||
let n;
|
||||
while (n = walker.nextNode()) {
|
||||
if (n instanceof HTMLElement) {
|
||||
const el = n;
|
||||
const [x, y] = isScrollable(el);
|
||||
if (x || y) el.tabIndex = 0;
|
||||
}
|
||||
}
|
||||
node.focus();
|
||||
}
|
||||
const getPlacementClasses = (placement2) => {
|
||||
switch (placement2) {
|
||||
case "top-left":
|
||||
return ["justify-start", "items-start"];
|
||||
case "top-center":
|
||||
return ["justify-center", "items-start"];
|
||||
case "top-right":
|
||||
return ["justify-end", "items-start"];
|
||||
case "center-left":
|
||||
return ["justify-start", "items-center"];
|
||||
case "center":
|
||||
return ["justify-center", "items-center"];
|
||||
case "center-right":
|
||||
return ["justify-end", "items-center"];
|
||||
case "bottom-left":
|
||||
return ["justify-start", "items-end"];
|
||||
case "bottom-center":
|
||||
return ["justify-center", "items-end"];
|
||||
case "bottom-right":
|
||||
return ["justify-end", "items-end"];
|
||||
default:
|
||||
return ["justify-center", "items-center"];
|
||||
}
|
||||
};
|
||||
const sizes = {
|
||||
xs: "max-w-md",
|
||||
sm: "max-w-lg",
|
||||
md: "max-w-2xl",
|
||||
lg: "max-w-4xl",
|
||||
xl: "max-w-6xl"
|
||||
};
|
||||
const onAutoClose = (e) => {
|
||||
const target = e.target;
|
||||
if (autoclose && target?.tagName === "BUTTON") hide(e);
|
||||
};
|
||||
const onOutsideClose = (e) => {
|
||||
const target = e.target;
|
||||
if (outsideclose && target === e.currentTarget) hide(e);
|
||||
};
|
||||
const hide = (e) => {
|
||||
e.preventDefault();
|
||||
open = false;
|
||||
};
|
||||
const isScrollable = (e) => [e.scrollWidth > e.clientWidth && ["scroll", "auto"].indexOf(getComputedStyle(e).overflowX) >= 0, e.scrollHeight > e.clientHeight && ["scroll", "auto"].indexOf(getComputedStyle(e).overflowY) >= 0];
|
||||
function handleKeys(e) {
|
||||
if (e.key === "Escape" && dismissable) return hide(e);
|
||||
}
|
||||
$: backdropCls = twMerge(backdropClass, classBackdrop);
|
||||
$: dialogCls = twMerge(dialogClass, classDialog, getPlacementClasses(placement));
|
||||
$: frameCls = twMerge(defaultClass, "w-full divide-y", $$props.class);
|
||||
$: headerCls = twMerge(headerClass, classHeader);
|
||||
$: bodyCls = twMerge(bodyClass, classBody);
|
||||
$: footerCls = twMerge(footerClass, classFooter);
|
||||
</script>
|
||||
|
||||
{#if open}
|
||||
<!-- backdrop -->
|
||||
<div class={backdropCls}></div>
|
||||
<!-- dialog -->
|
||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||
<div on:keydown={handleKeys} on:wheel|preventDefault|nonpassive use:prepareFocus use:focusTrap on:click={onAutoClose} on:mousedown={onOutsideClose} class={dialogCls} tabindex="-1" aria-modal="true" role="dialog">
|
||||
<div class="flex relative {sizes[size]} w-full max-h-full">
|
||||
<!-- Modal content -->
|
||||
<Frame rounded shadow {...$$restProps} class={frameCls} {color}>
|
||||
<!-- Modal header -->
|
||||
{#if $$slots.header || title}
|
||||
<Frame class={headerCls} {color}>
|
||||
<slot name="header">
|
||||
<h3 class="text-xl font-semibold {color === 'default' ? '' : 'text-gray-900 dark:text-white'} p-0">
|
||||
{title}
|
||||
</h3>
|
||||
</slot>
|
||||
{#if dismissable}<CloseButton name="Close modal" {color} on:click={hide} />{/if}
|
||||
</Frame>
|
||||
{/if}
|
||||
<!-- Modal body -->
|
||||
<div class={bodyCls} role="document" on:keydown|stopPropagation={handleKeys} on:wheel|stopPropagation|passive>
|
||||
{#if dismissable && !$$slots.header && !title}
|
||||
<CloseButton name="Close modal" class="absolute top-3 end-2.5" {color} on:click={hide} />
|
||||
{/if}
|
||||
<slot></slot>
|
||||
</div>
|
||||
<!-- Modal footer -->
|
||||
{#if $$slots.footer}
|
||||
<Frame class={footerCls} {color}>
|
||||
<slot name="footer"></slot>
|
||||
</Frame>
|
||||
{/if}
|
||||
</Frame>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!--
|
||||
@component
|
||||
[Go to docs](https://flowbite-svelte.com/)
|
||||
## Props
|
||||
@prop export let open: boolean = false;
|
||||
@prop export let title: string = '';
|
||||
@prop export let size: SizeType = 'md';
|
||||
@prop export let color: ComponentProps<Frame>['color'] = 'default';
|
||||
@prop export let placement: ModalPlacementType = 'center';
|
||||
@prop export let autoclose: boolean = false;
|
||||
@prop export let outsideclose: boolean = false;
|
||||
@prop export let dismissable: boolean = true;
|
||||
@prop export let backdropClass: string = 'fixed inset-0 z-40 bg-gray-900 bg-opacity-50 dark:bg-opacity-80';
|
||||
@prop export let classBackdrop: string | undefined = undefined;
|
||||
@prop export let dialogClass: string = 'fixed top-0 start-0 end-0 h-modal md:inset-0 md:h-full z-50 w-full p-4 flex';
|
||||
@prop export let classDialog: string | undefined = undefined;
|
||||
@prop export let defaultClass: string = 'relative flex flex-col mx-auto';
|
||||
@prop export let headerClass: string = 'flex justify-between items-center p-4 md:p-5 rounded-t-lg';
|
||||
@prop export let classHeader: string | undefined = undefined;
|
||||
@prop export let bodyClass: string = 'p-4 md:p-5 space-y-4 flex-1 overflow-y-auto overscroll-contain';
|
||||
@prop export let classBody: string | undefined = undefined;
|
||||
@prop export let footerClass: string = 'flex items-center p-4 md:p-5 space-x-3 rtl:space-x-reverse rounded-b-lg';
|
||||
@prop export let classFooter: string | undefined = undefined;
|
||||
-->
|
77
frontend/src/modal/Modal.svelte.d.ts
vendored
77
frontend/src/modal/Modal.svelte.d.ts
vendored
@ -1,77 +0,0 @@
|
||||
import { SvelteComponentTyped } from "svelte";
|
||||
import type { Dismissable, SizeType } from '../types';
|
||||
import type { ModalPlacementType } from '../types';
|
||||
declare const __propDef: {
|
||||
props: import("svelte/elements").HTMLAnchorAttributes & {
|
||||
tag?: string;
|
||||
color?: import("../utils/Frame.svelte").FrameColor;
|
||||
rounded?: boolean;
|
||||
border?: boolean;
|
||||
shadow?: boolean;
|
||||
node?: HTMLElement | undefined;
|
||||
use?: import("svelte/action").Action<HTMLElement, any>;
|
||||
options?: object;
|
||||
class?: string;
|
||||
role?: string;
|
||||
open?: boolean;
|
||||
transition?: (node: HTMLElement, params: any) => import("svelte/transition").TransitionConfig;
|
||||
params?: any;
|
||||
} & Dismissable & {
|
||||
open?: boolean;
|
||||
title?: string;
|
||||
size?: SizeType;
|
||||
placement?: ModalPlacementType;
|
||||
autoclose?: boolean;
|
||||
outsideclose?: boolean;
|
||||
backdropClass?: string;
|
||||
classBackdrop?: string;
|
||||
dialogClass?: string;
|
||||
classDialog?: string;
|
||||
defaultClass?: string;
|
||||
headerClass?: string;
|
||||
classHeader?: string;
|
||||
bodyClass?: string;
|
||||
classBody?: string;
|
||||
footerClass?: string;
|
||||
classFooter?: string;
|
||||
};
|
||||
events: {
|
||||
wheel: WheelEvent;
|
||||
} & {
|
||||
[evt: string]: CustomEvent<any>;
|
||||
};
|
||||
slots: {
|
||||
header: {};
|
||||
default: {};
|
||||
footer: {};
|
||||
};
|
||||
};
|
||||
export type ModalProps = typeof __propDef.props;
|
||||
export type ModalEvents = typeof __propDef.events;
|
||||
export type ModalSlots = typeof __propDef.slots;
|
||||
/**
|
||||
* [Go to docs](https://flowbite-svelte.com/)
|
||||
* ## Props
|
||||
* @prop export let open: boolean = false;
|
||||
* @prop export let title: string = '';
|
||||
* @prop export let size: SizeType = 'md';
|
||||
* @prop export let color: ComponentProps<Frame>['color'] = 'default';
|
||||
* @prop export let placement: ModalPlacementType = 'center';
|
||||
* @prop export let autoclose: boolean = false;
|
||||
* @prop export let outsideclose: boolean = false;
|
||||
* @prop export let dismissable: boolean = true;
|
||||
* @prop export let backdropClass: string = 'fixed inset-0 z-40 bg-gray-900 bg-opacity-50 dark:bg-opacity-80';
|
||||
* @prop export let classBackdrop: string | undefined = undefined;
|
||||
* @prop export let dialogClass: string = 'fixed top-0 start-0 end-0 h-modal md:inset-0 md:h-full z-50 w-full p-4 flex';
|
||||
* @prop export let classDialog: string | undefined = undefined;
|
||||
* @prop export let defaultClass: string = 'relative flex flex-col mx-auto';
|
||||
* @prop export let headerClass: string = 'flex justify-between items-center p-4 md:p-5 rounded-t-lg';
|
||||
* @prop export let classHeader: string | undefined = undefined;
|
||||
* @prop export let bodyClass: string = 'p-4 md:p-5 space-y-4 flex-1 overflow-y-auto overscroll-contain';
|
||||
* @prop export let classBody: string | undefined = undefined;
|
||||
* @prop export let footerClass: string = 'flex items-center p-4 md:p-5 space-x-3 rtl:space-x-reverse rounded-b-lg';
|
||||
* @prop export let classFooter: string | undefined = undefined;
|
||||
*/
|
||||
export default class Modal extends SvelteComponentTyped<ModalProps, ModalEvents, ModalSlots> {
|
||||
}
|
||||
export {};
|
@ -1,29 +1,29 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
anilistModal,
|
||||
aniListLoggedIn,
|
||||
simklLoggedIn,
|
||||
malLoggedIn,
|
||||
malAnime,
|
||||
simklAnime,
|
||||
aniListAnime,
|
||||
} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||
} from "../helperComponents/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import {Button} from "flowbite-svelte";
|
||||
// @ts-ignore
|
||||
import StarRatting from "@ernane/svelte-star-rating"
|
||||
import StarRatting from "../star-rating/Stars.svelte"
|
||||
import moment from 'moment'
|
||||
import { Table, TableBody, TableBodyCell, TableBodyRow, TableHead, TableHeadCell } from 'flowbite-svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import type {SimklAnime} from "./simkl/types/simklTypes";
|
||||
import type {SimklAnime} from "../simkl/types/simklTypes";
|
||||
import {
|
||||
AniListUpdateEntry, MyAnimeListUpdate,
|
||||
SimklSyncEpisodes,
|
||||
SimklSyncRating,
|
||||
SimklSyncStatus
|
||||
} from "../wailsjs/go/main/App";
|
||||
import type {MALAnime, MALUploadStatus, MyListStatus} from "./mal/types/MALTypes";
|
||||
import type {AniListUpdateVariables} from "./anilist/types/AniListTypes";
|
||||
import type {AniListGetSingleAnime} from "./anilist/types/AniListCurrentUserWatchListType";
|
||||
} from "../../wailsjs/go/main/App";
|
||||
import type {MALAnime, MALUploadStatus, MyListStatus} from "../mal/types/MALTypes";
|
||||
import type {AniListUpdateVariables} from "../anilist/types/AniListTypes";
|
||||
import type {AniListGetSingleAnime} from "../anilist/types/AniListCurrentUserWatchListType";
|
||||
import {pop} from "svelte-spa-router";
|
||||
|
||||
let isAniListLoggedIn: boolean
|
||||
let isMalLoggedIn: boolean
|
||||
@ -134,7 +134,6 @@
|
||||
const sortKey = writable('service'); // default sort key
|
||||
const sortDirection = writable(1); // default sort direction (ascending)
|
||||
const sortItems = writable(tableItems.slice()); // make a copy of the items array
|
||||
console.log(tableItems[0])
|
||||
|
||||
// Define a function to sort the items
|
||||
const sortTable = (key: any) => {
|
||||
@ -177,10 +176,6 @@
|
||||
10: "Masterpiece",
|
||||
}
|
||||
|
||||
const hide = () => {
|
||||
anilistModal.set(false)
|
||||
};
|
||||
|
||||
const title = currentAniListAnime.data.MediaList.media.title.english !== "" ?
|
||||
currentAniListAnime.data.MediaList.media.title.english :
|
||||
currentAniListAnime.data.MediaList.media.title.romaji
|
||||
@ -195,7 +190,8 @@
|
||||
},
|
||||
score: currentAniListAnime.data.MediaList.score / 2,
|
||||
showScore: false,
|
||||
name: "",
|
||||
name: "rating",
|
||||
scoreFormat: function(){ return `(${this.score.toFixed(0)}/${this.countStars})` },
|
||||
starConfig: {
|
||||
size: 32,
|
||||
fillColor: '#F9ED4F',
|
||||
@ -225,7 +221,7 @@
|
||||
let startedAtDate: string
|
||||
let completedAtDate: string
|
||||
|
||||
const changeRating = (e) => {
|
||||
const changeRating = (e: any) => {
|
||||
config.score = e.target.valueAsNumber
|
||||
values.score = e.target.valueAsNumber * 2
|
||||
}
|
||||
@ -237,7 +233,7 @@
|
||||
startedAtDate = startedAtMoment.format('YYYY-MM-DD')
|
||||
}
|
||||
|
||||
const transformStartedAtDate = (e) => {
|
||||
const transformStartedAtDate = (e: any) => {
|
||||
const re = /^([0-9]{4})-([0-9]{2})-([0-9]{2})/
|
||||
const date = re.exec(e.target.value)
|
||||
values.startedAt.year = Number(date[1])
|
||||
@ -251,7 +247,7 @@
|
||||
completedAtDate = completedAtMoment.format('YYYY-MM-DD')
|
||||
}
|
||||
|
||||
const transformCompletedAtDate = (e) => {
|
||||
const transformCompletedAtDate = (e: any) => {
|
||||
const re = /^([0-9]{4})-([0-9]{2})-([0-9]{2})/
|
||||
const date = re.exec(e.target.value)
|
||||
values.completedAt.year = Number(date[1])
|
||||
@ -410,9 +406,9 @@
|
||||
isSubmitSuccess = true
|
||||
setTimeout(() => isSubmitSuccess = false, 2000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="inapp-data">
|
||||
</script>
|
||||
<div class="container py-10">
|
||||
<div class="grid grid-cols-1 md:grid-cols-10 grid-flow-col gap-4">
|
||||
<div class="md:col-span-2 space-y-3">
|
||||
<img class="rounded-lg" src={currentAniListAnime.data.MediaList.media.coverImage.large} alt="{title} Cover Image">
|
||||
@ -591,8 +587,8 @@
|
||||
class="text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4
|
||||
focus:ring-gray-100 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-800 dark:text-white
|
||||
dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700"
|
||||
on:click={hide}>
|
||||
Cancel
|
||||
on:click={() => pop()}>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
25
frontend/src/routes/Home.svelte
Normal file
25
frontend/src/routes/Home.svelte
Normal file
@ -0,0 +1,25 @@
|
||||
<script lang="ts">
|
||||
import Pagination from "../helperComponents/Pagination.svelte";
|
||||
import WatchList from "../helperComponents/WatchList.svelte";
|
||||
import {
|
||||
aniListLoggedIn,
|
||||
aniListPrimary,
|
||||
loading,
|
||||
} from "../helperComponents/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import loader from '../helperFunctions/loader'
|
||||
|
||||
let isAniListPrimary: boolean
|
||||
let isAniListLoggedIn: boolean
|
||||
|
||||
aniListPrimary.subscribe((value) => isAniListPrimary = value)
|
||||
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
|
||||
</script>
|
||||
{#if isAniListLoggedIn && isAniListPrimary}
|
||||
<div class="container py-10">
|
||||
<Pagination />
|
||||
<WatchList />
|
||||
<Pagination />
|
||||
</div>
|
||||
{:else}
|
||||
<div use:loader={loading}></div>
|
||||
{/if}
|
63
frontend/src/star-rating/Stars.svelte
Normal file
63
frontend/src/star-rating/Stars.svelte
Normal file
@ -0,0 +1,63 @@
|
||||
<!-- Originally from @ernane/svelte-star-rating. Wanted to give credit but could not use from the library without causing program crash. -->
|
||||
|
||||
<script>
|
||||
import Star from './components/Star.svelte';
|
||||
export let config = {
|
||||
readOnly: false,
|
||||
countStars: 5,
|
||||
range: { min: 0, max: 5, step: 0.001 },
|
||||
score: 0.0,
|
||||
showScore: true,
|
||||
name: "stars",
|
||||
scoreFormat: function(){ return `(${this.score.toFixed(0)}/${this.countStars})` },
|
||||
starConfig: {
|
||||
size: 30,
|
||||
fillColor: '#F9ED4F',
|
||||
strokeColor: "#BB8511",
|
||||
unfilledColor: '#FFF',
|
||||
strokeUnfilledColor: '#000'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<section class="stars-container">
|
||||
<div class="range-stars">
|
||||
<div class="stars">
|
||||
{#each Array(config.countStars) as star, id}
|
||||
{#if Math.floor(config.score) === id}
|
||||
<Star id={config.name + id} readOnly={config.readOnly} starConfig={config.starConfig} fillPercentage={config.score - Math.floor(config.score)}/>
|
||||
{:else if Math.floor(config.score) > id}
|
||||
<Star id={config.name + id} readOnly={config.readOnly} starConfig={config.starConfig} fillPercentage={1}/>
|
||||
{:else}
|
||||
<Star id={config.name + id} readOnly={config.readOnly} starConfig={config.starConfig} fillPercentage={0}/>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<input name={config.name}
|
||||
class="slider"
|
||||
type="range"
|
||||
min={config.readOnly ? config.score : config.range.min}
|
||||
max={config.readOnly ? config.score : config.range.max}
|
||||
step="{config.range.step}" bind:value={config.score}
|
||||
on:change
|
||||
on:click
|
||||
>
|
||||
</div>
|
||||
{#if config.showScore}
|
||||
<span class="show-score" style="font-size: {config.starConfig.size/2}px;">
|
||||
{#if config.scoreFormat}
|
||||
{config.scoreFormat()}
|
||||
{:else}
|
||||
({((config.score/config.countStars)*100).toFixed(2)}%)
|
||||
{/if}
|
||||
</span>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.stars-container{ position: relative; display: flex; align-items: center; justify-content: center; gap: .5rem; }
|
||||
.range-stars{ position: relative; }
|
||||
.stars{ display: flex; align-items: center; justify-content: center; gap: .5rem; }
|
||||
.slider{ opacity: 0; cursor: pointer; position: absolute; top: 0; left: 0; right: 0; height: 100%; }
|
||||
.show-score{ user-select: none; color: #888 }
|
||||
</style>
|
21
frontend/src/star-rating/components/Star.svelte
Normal file
21
frontend/src/star-rating/components/Star.svelte
Normal file
@ -0,0 +1,21 @@
|
||||
<script>
|
||||
export let id, readOnly, fillPercentage, starConfig;
|
||||
</script>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="{starConfig.size}" viewBox="0 -10 187.673 179.503" height="{starConfig.size}" >
|
||||
{#if fillPercentage < 1 && fillPercentage > 0}
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient-{id}" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" style="stop-color:{starConfig.fillColor};stop-opacity:1" />
|
||||
<stop offset="{fillPercentage * 100}%" style="stop-color:{starConfig.fillColor};stop-opacity:1"/>
|
||||
<stop offset="{fillPercentage * 100}%" style="stop-color:{starConfig.unfilledColor};stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
{/if}
|
||||
<path
|
||||
opacity="{readOnly ? .7 : 1}"
|
||||
stroke={fillPercentage > 0 ? starConfig.strokeColor : starConfig.strokeUnfilledColor}
|
||||
fill={fillPercentage === 1 ? starConfig.fillColor : fillPercentage === 0 ? starConfig.unfilledColor : `url(#linear-gradient-${id})`}
|
||||
d="M187.183 57.47a9.955 9.955 0 00-8.587-6.86l-54.167-4.918-21.42-50.134a9.978 9.978 0 00-9.172-6.052 9.972 9.972 0 00-9.172 6.061l-21.42 50.125L9.07 50.611a9.973 9.973 0 00-8.578 6.858 9.964 9.964 0 002.917 10.596l40.944 35.908-12.073 53.184a9.97 9.97 0 003.878 10.298A9.953 9.953 0 0042 169.357a9.937 9.937 0 005.114-1.424l46.724-27.925 46.707 27.925a9.936 9.936 0 0010.964-.478 9.979 9.979 0 003.88-10.298l-12.074-53.184 40.944-35.9a9.98 9.98 0 002.925-10.604zm0 0"
|
||||
/>
|
||||
</svg>
|
@ -1,24 +1,45 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{svelte,js,ts,jsx,tsx}",
|
||||
"./node_modules/flowbite/**/*.{html,js,svelte,ts}",
|
||||
"./node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}",
|
||||
],
|
||||
plugins: [
|
||||
require('flowbite/plugin')
|
||||
],
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{svelte,js,ts,jsx,tsx}",
|
||||
"./node_modules/flowbite/**/*.{html,js,svelte,ts}",
|
||||
"./node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}",
|
||||
],
|
||||
plugins: [
|
||||
require('flowbite/plugin')
|
||||
],
|
||||
|
||||
darkMode: 'media',
|
||||
darkMode: 'media',
|
||||
|
||||
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'},
|
||||
}
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: {
|
||||
DEFAULT: '1rem',
|
||||
sm: '2rem',
|
||||
lg: '4rem',
|
||||
xl: '5rem',
|
||||
'2xl': '6rem',
|
||||
},
|
||||
},
|
||||
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'
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
0
frontend/wailsjs/runtime/package.json
Executable file → Normal file
0
frontend/wailsjs/runtime/package.json
Executable file → Normal file
0
frontend/wailsjs/runtime/runtime.d.ts
vendored
Executable file → Normal file
0
frontend/wailsjs/runtime/runtime.d.ts
vendored
Executable file → Normal file
0
frontend/wailsjs/runtime/runtime.js
Executable file → Normal file
0
frontend/wailsjs/runtime/runtime.js
Executable file → Normal file
Loading…
Reference in New Issue
Block a user