Compare commits
15 Commits
53b7368daf
...
aaf0f421f2
Author | SHA1 | Date | |
---|---|---|---|
aaf0f421f2 | |||
49e461d0ff | |||
6c4fdabb79 | |||
77289052e9 | |||
1dcf7ba5bd | |||
46e2a9156f | |||
1e90f68e70 | |||
8fc2b8b508 | |||
ce52ae20f5 | |||
94c0f97e95 | |||
79ed79c25e | |||
091ca82f69 | |||
eeb4a62f26 | |||
a0b00de615 | |||
6e9c2cf46e |
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -90,6 +91,15 @@ func (a *App) GetAniListItem(aniId int, login bool) AniListGetSingleAnime {
|
|||||||
timeUntilAiring
|
timeUntilAiring
|
||||||
episode
|
episode
|
||||||
}
|
}
|
||||||
|
tags{
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
rank
|
||||||
|
isMediaSpoiler
|
||||||
|
isAdult
|
||||||
|
}
|
||||||
|
isAdult
|
||||||
}
|
}
|
||||||
status
|
status
|
||||||
startedAt{
|
startedAt{
|
||||||
@ -180,6 +190,15 @@ func (a *App) AniListSearch(query string) any {
|
|||||||
timeUntilAiring
|
timeUntilAiring
|
||||||
episode
|
episode
|
||||||
}
|
}
|
||||||
|
tags{
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
rank
|
||||||
|
isMediaSpoiler
|
||||||
|
isAdult
|
||||||
|
}
|
||||||
|
isAdult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,6 +275,15 @@ func (a *App) GetAniListUserWatchingList(page int, perPage int, sort string) Ani
|
|||||||
timeUntilAiring
|
timeUntilAiring
|
||||||
episode
|
episode
|
||||||
}
|
}
|
||||||
|
tags{
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
rank
|
||||||
|
isMediaSpoiler
|
||||||
|
isAdult
|
||||||
|
}
|
||||||
|
isAdult
|
||||||
}
|
}
|
||||||
status
|
status
|
||||||
startedAt {
|
startedAt {
|
||||||
@ -330,7 +358,7 @@ func (a *App) GetAniListUserWatchingList(page int, perPage int, sort string) Ani
|
|||||||
|
|
||||||
func (a *App) AniListUpdateEntry(
|
func (a *App) AniListUpdateEntry(
|
||||||
mediaId int,
|
mediaId int,
|
||||||
progress string,
|
progress int,
|
||||||
status string,
|
status string,
|
||||||
score float64,
|
score float64,
|
||||||
repeat int,
|
repeat int,
|
||||||
@ -354,7 +382,7 @@ func (a *App) AniListUpdateEntry(
|
|||||||
}
|
}
|
||||||
type Variables struct {
|
type Variables struct {
|
||||||
MediaId int `json:"mediaId"`
|
MediaId int `json:"mediaId"`
|
||||||
Progress string `json:"progress"`
|
Progress int `json:"progress"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Score float64 `json:"score"`
|
Score float64 `json:"score"`
|
||||||
Repeat int `json:"repeat"`
|
Repeat int `json:"repeat"`
|
||||||
@ -363,10 +391,10 @@ func (a *App) AniListUpdateEntry(
|
|||||||
CompletedAt CompletedAt `json:"completedAt"`
|
CompletedAt CompletedAt `json:"completedAt"`
|
||||||
}
|
}
|
||||||
body := struct {
|
body := struct {
|
||||||
Mutation string `json:"mutation"`
|
Query string `json:"query"`
|
||||||
Variables Variables `json:"variables"`
|
Variables Variables `json:"variables"`
|
||||||
}{
|
}{
|
||||||
Mutation: `
|
Query: `
|
||||||
mutation(
|
mutation(
|
||||||
$mediaId:Int,
|
$mediaId:Int,
|
||||||
$progress:Int,
|
$progress:Int,
|
||||||
@ -427,6 +455,8 @@ func (a *App) AniListUpdateEntry(
|
|||||||
|
|
||||||
returnedBody, _ := AniListQuery(body, true)
|
returnedBody, _ := AniListQuery(body, true)
|
||||||
|
|
||||||
|
fmt.Println(string(returnedBody))
|
||||||
|
|
||||||
var post interface{}
|
var post interface{}
|
||||||
err := json.Unmarshal(returnedBody, &post)
|
err := json.Unmarshal(returnedBody, &post)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
143
AniListTypes.go
143
AniListTypes.go
@ -68,6 +68,15 @@ type MediaList struct {
|
|||||||
TimeUntilAiring int `json:"timeUntilAiring"`
|
TimeUntilAiring int `json:"timeUntilAiring"`
|
||||||
Episode int `json:"episode"`
|
Episode int `json:"episode"`
|
||||||
} `json:"nextAiringEpisode"`
|
} `json:"nextAiringEpisode"`
|
||||||
|
Tags []struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Rank int `json:"rank"`
|
||||||
|
IsMediaSpoiler bool `json:"isMediaSpoiler"`
|
||||||
|
IsAdult bool `json:"isAdult"`
|
||||||
|
} `json:"tags"`
|
||||||
|
IsAdult bool `json:"isAdult"`
|
||||||
} `json:"media"`
|
} `json:"media"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
StartedAt struct {
|
StartedAt struct {
|
||||||
@ -80,10 +89,10 @@ type MediaList struct {
|
|||||||
Month int `json:"month"`
|
Month int `json:"month"`
|
||||||
Day int `json:"day"`
|
Day int `json:"day"`
|
||||||
} `json:"completedAt"`
|
} `json:"completedAt"`
|
||||||
Notes string `json:"notes"`
|
Notes string `json:"notes"`
|
||||||
Progress int `json:"progress"`
|
Progress int `json:"progress"`
|
||||||
Score int `json:"score"`
|
Score float64 `json:"score"`
|
||||||
Repeat int `json:"repeat"`
|
Repeat int `json:"repeat"`
|
||||||
User struct {
|
User struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -103,66 +112,66 @@ type MediaList struct {
|
|||||||
} `json:"user"`
|
} `json:"user"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var MediaListSort = struct {
|
//var MediaListSort = struct {
|
||||||
MediaId string
|
// MediaId string
|
||||||
MediaIdDesc string
|
// MediaIdDesc string
|
||||||
Score string
|
// Score string
|
||||||
ScoreDesc string
|
// ScoreDesc string
|
||||||
Status string
|
// Status string
|
||||||
StatusDesc string
|
// StatusDesc string
|
||||||
Progress string
|
// Progress string
|
||||||
ProgressDesc string
|
// ProgressDesc string
|
||||||
ProgressVolumes string
|
// ProgressVolumes string
|
||||||
ProgressVolumesDesc string
|
// ProgressVolumesDesc string
|
||||||
Repeat string
|
// Repeat string
|
||||||
RepeatDesc string
|
// RepeatDesc string
|
||||||
Priority string
|
// Priority string
|
||||||
PriorityDesc string
|
// PriorityDesc string
|
||||||
StartedOn string
|
// StartedOn string
|
||||||
StartedOnDesc string
|
// StartedOnDesc string
|
||||||
FinishedOn string
|
// FinishedOn string
|
||||||
FinishedOnDesc string
|
// FinishedOnDesc string
|
||||||
AddedTime string
|
// AddedTime string
|
||||||
AddedTimeDesc string
|
// AddedTimeDesc string
|
||||||
UpdatedTime string
|
// UpdatedTime string
|
||||||
UpdatedTimeDesc string
|
// UpdatedTimeDesc string
|
||||||
MediaTitleRomaji string
|
// MediaTitleRomaji string
|
||||||
MediaTitleRomajiDesc string
|
// MediaTitleRomajiDesc string
|
||||||
MediaTitleEnglish string
|
// MediaTitleEnglish string
|
||||||
MediaTitleEnglishDesc string
|
// MediaTitleEnglishDesc string
|
||||||
MediaTitleNative string
|
// MediaTitleNative string
|
||||||
MediaTitleNativeDesc string
|
// MediaTitleNativeDesc string
|
||||||
MediaPopularity string
|
// MediaPopularity string
|
||||||
MediaPopularityDesc string
|
// MediaPopularityDesc string
|
||||||
}{
|
//}{
|
||||||
MediaId: "MEDIA_ID",
|
// MediaId: "MEDIA_ID",
|
||||||
MediaIdDesc: "MEDIA_ID_DESC",
|
// MediaIdDesc: "MEDIA_ID_DESC",
|
||||||
Score: "SCORE",
|
// Score: "SCORE",
|
||||||
ScoreDesc: "SCORE_DESC",
|
// ScoreDesc: "SCORE_DESC",
|
||||||
Status: "STATUS",
|
// Status: "STATUS",
|
||||||
StatusDesc: "STATUS_DESC",
|
// StatusDesc: "STATUS_DESC",
|
||||||
Progress: "PROGRESS",
|
// Progress: "PROGRESS",
|
||||||
ProgressDesc: "PROGRESS_DESC",
|
// ProgressDesc: "PROGRESS_DESC",
|
||||||
ProgressVolumes: "PROGRESS_VOLUMES",
|
// ProgressVolumes: "PROGRESS_VOLUMES",
|
||||||
ProgressVolumesDesc: "PROGRESS_VOLUMES_DESC",
|
// ProgressVolumesDesc: "PROGRESS_VOLUMES_DESC",
|
||||||
Repeat: "REPEAT",
|
// Repeat: "REPEAT",
|
||||||
RepeatDesc: "REPEAT_DESC",
|
// RepeatDesc: "REPEAT_DESC",
|
||||||
Priority: "PRIORITY",
|
// Priority: "PRIORITY",
|
||||||
PriorityDesc: "PRIORITY_DESC",
|
// PriorityDesc: "PRIORITY_DESC",
|
||||||
StartedOn: "STARTED_ON",
|
// StartedOn: "STARTED_ON",
|
||||||
StartedOnDesc: "STARTED_ON_DESC",
|
// StartedOnDesc: "STARTED_ON_DESC",
|
||||||
FinishedOn: "FINISHED_ON",
|
// FinishedOn: "FINISHED_ON",
|
||||||
FinishedOnDesc: "FINISHED_ON_DESC",
|
// FinishedOnDesc: "FINISHED_ON_DESC",
|
||||||
AddedTime: "ADDED_TIME",
|
// AddedTime: "ADDED_TIME",
|
||||||
AddedTimeDesc: "ADDED_TIME_DESC",
|
// AddedTimeDesc: "ADDED_TIME_DESC",
|
||||||
UpdatedTime: "UPDATED_TIME",
|
// UpdatedTime: "UPDATED_TIME",
|
||||||
UpdatedTimeDesc: "UPDATED_TIME_DESC",
|
// UpdatedTimeDesc: "UPDATED_TIME_DESC",
|
||||||
MediaTitleRomaji: "MEDIA_TITLE_ROMAJI",
|
// MediaTitleRomaji: "MEDIA_TITLE_ROMAJI",
|
||||||
MediaTitleRomajiDesc: "MEDIA_TITLE_ROMAJI_DESC",
|
// MediaTitleRomajiDesc: "MEDIA_TITLE_ROMAJI_DESC",
|
||||||
MediaTitleEnglish: "MEDIA_TITLE_ENGLISH",
|
// MediaTitleEnglish: "MEDIA_TITLE_ENGLISH",
|
||||||
MediaTitleEnglishDesc: "MEDIA_TITLE_ENGLISH_DESC",
|
// MediaTitleEnglishDesc: "MEDIA_TITLE_ENGLISH_DESC",
|
||||||
MediaTitleNative: "MEDIA_TITLE_NATIVE",
|
// MediaTitleNative: "MEDIA_TITLE_NATIVE",
|
||||||
MediaTitleNativeDesc: "MEDIA_TITLE_NATIVE_DESC",
|
// MediaTitleNativeDesc: "MEDIA_TITLE_NATIVE_DESC",
|
||||||
MediaPopularity: "MEDIA_POPULARITY",
|
// MediaPopularity: "MEDIA_POPULARITY",
|
||||||
MediaPopularityDesc: "MEDIA_POPULARITY_DESC",
|
// MediaPopularityDesc: "MEDIA_POPULARITY_DESC",
|
||||||
}
|
//}
|
||||||
|
@ -28,14 +28,14 @@ type SimklUser struct {
|
|||||||
|
|
||||||
type SimklWatchList struct {
|
type SimklWatchList struct {
|
||||||
Anime []struct {
|
Anime []struct {
|
||||||
LastWatchedAt string `json:"last_watched_at" ts_type:"last_watched_at"`
|
LastWatchedAt string `json:"last_watched_at" ts_type:"last_watched_at"`
|
||||||
Status string `json:"status" ts_type:"status"`
|
Status string `json:"status" ts_type:"status"`
|
||||||
UserRating int `json:"user_rating" ts_type:"user_rating"`
|
UserRating float64 `json:"user_rating" ts_type:"user_rating"`
|
||||||
LastWatched string `json:"last_watched" ts_type:"last_watched"`
|
LastWatched string `json:"last_watched" ts_type:"last_watched"`
|
||||||
NextToWatch string `json:"next_to_watch" ts_type:"next_to_watch"`
|
NextToWatch string `json:"next_to_watch" ts_type:"next_to_watch"`
|
||||||
WatchedEpisodesCount int `json:"watched_episodes_count" ts_type:"watched_episodes_count"`
|
WatchedEpisodesCount int `json:"watched_episodes_count" ts_type:"watched_episodes_count"`
|
||||||
TotalEpisodesCount int `json:"total_episodes_count" ts_type:"total_episodes_count"`
|
TotalEpisodesCount int `json:"total_episodes_count" ts_type:"total_episodes_count"`
|
||||||
NotAiredEpisodesCount int `json:"not_aired_episodes_count" ts_type:"not_aired_episodes_count"`
|
NotAiredEpisodesCount int `json:"not_aired_episodes_count" ts_type:"not_aired_episodes_count"`
|
||||||
Show struct {
|
Show struct {
|
||||||
Title string `json:"title" ts_type:"title"`
|
Title string `json:"title" ts_type:"title"`
|
||||||
Poster string `json:"poster" ts_type:"poster"`
|
Poster string `json:"poster" ts_type:"poster"`
|
||||||
|
@ -157,8 +157,6 @@ func getSimklAuthorizationToken(content string) SimklJWT {
|
|||||||
func (a *App) GetSimklLoggedInUser() SimklUser {
|
func (a *App) GetSimklLoggedInUser() SimklUser {
|
||||||
a.SimklLogin()
|
a.SimklLogin()
|
||||||
|
|
||||||
fmt.Println("Token: ", simklJwt.AccessToken)
|
|
||||||
|
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
|
|
||||||
req, _ := http.NewRequest("POST", "https://api.simkl.com/users/settings", nil)
|
req, _ := http.NewRequest("POST", "https://api.simkl.com/users/settings", nil)
|
||||||
|
@ -24,6 +24,14 @@ body:graphql {
|
|||||||
media {
|
media {
|
||||||
id
|
id
|
||||||
idMal
|
idMal
|
||||||
|
tags{
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
rank
|
||||||
|
isMediaSpoiler
|
||||||
|
isAdult
|
||||||
|
}
|
||||||
title {
|
title {
|
||||||
romaji
|
romaji
|
||||||
english
|
english
|
||||||
@ -42,6 +50,7 @@ body:graphql {
|
|||||||
timeUntilAiring
|
timeUntilAiring
|
||||||
episode
|
episode
|
||||||
}
|
}
|
||||||
|
isAdult
|
||||||
}
|
}
|
||||||
status
|
status
|
||||||
startedAt {
|
startedAt {
|
||||||
|
@ -6,5 +6,6 @@ vars {
|
|||||||
}
|
}
|
||||||
vars:secret [
|
vars:secret [
|
||||||
code,
|
code,
|
||||||
SIMKL_AUTH_TOKEN
|
SIMKL_AUTH_TOKEN,
|
||||||
|
ANILIST_ACCESS_TOKEN
|
||||||
]
|
]
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
"@ernane/svelte-star-rating": "^1.1.7",
|
"@ernane/svelte-star-rating": "^1.1.7",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"flowbite": "^2.4.1",
|
"flowbite": "^2.4.1",
|
||||||
"flowbite-svelte": "^0.46.15"
|
"flowbite-svelte": "^0.46.15",
|
||||||
|
"moment": "^2.30.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,39 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {anilistModal, GetAniListSingleItemAndOpenModal, title} from "./GetAniListSingleItemAndOpenModal.svelte";
|
import {
|
||||||
|
anilistModal,
|
||||||
|
GetAniListSingleItemAndOpenModal,
|
||||||
|
title,
|
||||||
|
simklWatchList,
|
||||||
|
aniListLoggedIn,
|
||||||
|
simklLoggedIn
|
||||||
|
} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||||
import {
|
import {
|
||||||
CheckIfAniListLoggedIn,
|
CheckIfAniListLoggedIn,
|
||||||
CheckIfSimklLoggedIn,
|
CheckIfSimklLoggedIn,
|
||||||
GetAniListLoggedInUser,
|
GetAniListLoggedInUser,
|
||||||
GetAniListUserWatchingList,
|
GetAniListUserWatchingList,
|
||||||
GetSimklLoggedInUser, SimklGetUserWatchlist,
|
GetSimklLoggedInUser,
|
||||||
|
SimklGetUserWatchlist,
|
||||||
} from "../wailsjs/go/main/App";
|
} from "../wailsjs/go/main/App";
|
||||||
import {type AniListUser, MediaListSort} from "./anilist/types/AniListTypes";
|
import {type AniListUser, MediaListSort} from "./anilist/types/AniListTypes";
|
||||||
import type {AniListCurrentUserWatchList} from "./anilist/types/AniListCurrentUserWatchListType"
|
import type {AniListCurrentUserWatchList} from "./anilist/types/AniListCurrentUserWatchListType"
|
||||||
import Header from "./Header.svelte";
|
import Header from "./Header.svelte";
|
||||||
import StarRatting from '@ernane/svelte-star-rating'
|
import {Button, Rating} from "flowbite-svelte";
|
||||||
import {Button, Modal} from "flowbite-svelte";
|
import {default as Modal} from "./modal/Modal.svelte"
|
||||||
|
|
||||||
import ChangeDataDialogue from "./ChangeDataDialogue.svelte";
|
import ChangeDataDialogue from "./ChangeDataDialogue.svelte";
|
||||||
import {onMount} from "svelte";
|
import {onMount} from "svelte";
|
||||||
import type {SimklUser, SimklWatchList} from "./simkl/types/simklTypes";
|
import type {SimklUser} from "./simkl/types/simklTypes";
|
||||||
import {writable} from "svelte/store";
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
readOnly: false,
|
|
||||||
countStars: 5,
|
|
||||||
range: {
|
|
||||||
min: 0,
|
|
||||||
max: 5,
|
|
||||||
step: 0.5
|
|
||||||
},
|
|
||||||
score: 0.0,
|
|
||||||
showScore: true,
|
|
||||||
scoreFormat: function () {
|
|
||||||
return `(${this.score.toFixed(1)}/${this.countStars})`
|
|
||||||
},
|
|
||||||
name: "",
|
|
||||||
starConfig: {
|
|
||||||
size: 20,
|
|
||||||
fillColor: '#F9ED4F',
|
|
||||||
strokeColor: "#e2c714",
|
|
||||||
unfilledColor: '#FFF',
|
|
||||||
strokeUnfilledColor: '#000'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let aniListLoggedIn = false
|
|
||||||
let aniListPrimary = true
|
let aniListPrimary = true
|
||||||
let simklUser: SimklUser
|
let simklUser: SimklUser
|
||||||
let simklLoggedIn = false
|
|
||||||
let aniListUser: AniListUser
|
let aniListUser: AniListUser
|
||||||
let aniListWatchlist: AniListCurrentUserWatchList
|
let aniListWatchlist: AniListCurrentUserWatchList
|
||||||
export let simklWatchList = writable({} as SimklWatchList)
|
let isAniListLoggedIn: boolean
|
||||||
|
let isSimklLoggedIn: boolean
|
||||||
|
|
||||||
|
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
|
||||||
|
simklLoggedIn.subscribe((value) => isSimklLoggedIn = value)
|
||||||
|
|
||||||
let page = 1
|
let page = 1
|
||||||
let perPage = 20
|
let perPage = 20
|
||||||
const size = "xl"
|
const size = "xl"
|
||||||
@ -60,10 +46,10 @@
|
|||||||
if (aniListPrimary) {
|
if (aniListPrimary) {
|
||||||
GetAniListUserWatchingList(page, perPage, MediaListSort.UpdatedTimeDesc).then((result) => {
|
GetAniListUserWatchingList(page, perPage, MediaListSort.UpdatedTimeDesc).then((result) => {
|
||||||
aniListWatchlist = result
|
aniListWatchlist = result
|
||||||
aniListLoggedIn = true
|
aniListLoggedIn.set(true)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
aniListLoggedIn = result
|
aniListLoggedIn.set(result)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -75,7 +61,7 @@
|
|||||||
simklUser = result
|
simklUser = result
|
||||||
SimklGetUserWatchlist().then(result => {
|
SimklGetUserWatchlist().then(result => {
|
||||||
simklWatchList.set(result)
|
simklWatchList.set(result)
|
||||||
simklLoggedIn = result
|
simklLoggedIn.set(result)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -85,38 +71,38 @@
|
|||||||
function loginToSimkl(): void {
|
function loginToSimkl(): void {
|
||||||
GetSimklLoggedInUser().then(result => {
|
GetSimklLoggedInUser().then(result => {
|
||||||
simklUser = result
|
simklUser = result
|
||||||
simklLoggedIn = true
|
simklLoggedIn.set(true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function loginToAniList(): void {
|
function loginToAniList(): void {
|
||||||
GetAniListLoggedInUser().then(result => {
|
GetAniListLoggedInUser().then(result => {
|
||||||
aniListUser = result
|
aniListUser = result
|
||||||
aniListLoggedIn = true
|
aniListLoggedIn.set(true)
|
||||||
if (aniListPrimary) {
|
if (aniListPrimary) {
|
||||||
GetAniListUserWatchingList(page, perPage, MediaListSort.UpdatedTimeDesc).then(result => aniListWatchlist = result)
|
GetAniListUserWatchingList(page, perPage, MediaListSort.UpdatedTimeDesc).then(result => aniListWatchlist = result)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function anilistGetUserWatchlist(): void {
|
// function anilistGetUserWatchlist(): void {
|
||||||
GetAniListUserWatchingList(page, perPage, MediaListSort.UpdatedTimeDesc).then((result) => {
|
// GetAniListUserWatchingList(page, perPage, MediaListSort.UpdatedTimeDesc).then((result) => {
|
||||||
aniListWatchlist = result
|
// aniListWatchlist = result
|
||||||
aniListLoggedIn = true
|
// aniListLoggedIn.set(true)
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
let count = 1;
|
// let count = 1;
|
||||||
|
//
|
||||||
const decrement = () => {
|
// const decrement = () => {
|
||||||
if (count > 0) {
|
// if (count > 0) {
|
||||||
count--
|
// count--
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
const increment = () => {
|
// const increment = () => {
|
||||||
count++
|
// count++
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@ -124,88 +110,56 @@
|
|||||||
<Header/>
|
<Header/>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
{#if aniListLoggedIn}
|
{#if isAniListLoggedIn}
|
||||||
<div>You are logged into AniList, {aniListWatchlist.data.Page.mediaList[0].user.name}!</div>
|
<div>You are logged into AniList, {aniListUser.data.Viewer.name}!</div>
|
||||||
{:else}
|
{:else}
|
||||||
<button class="btn" on:click={loginToAniList}>Login to AniList</button>
|
<button class="btn" on:click={loginToAniList}>Login to AniList</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if simklLoggedIn}
|
{#if isSimklLoggedIn}
|
||||||
<div>You are logged into Simkl, {simklUser.user.name}</div>
|
<div>You are logged into Simkl, {simklUser.user.name}</div>
|
||||||
{:else}
|
{:else}
|
||||||
<Button class="btn" on:click={loginToSimkl}>Login to Simkl</Button>
|
<Button class="btn" on:click={loginToSimkl}>Login to Simkl</Button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if aniListLoggedIn}
|
{#if isAniListLoggedIn}
|
||||||
<div class="mx-auto max-w-2xl px-4 py-16 sm:px-6 sm:py-24 lg:max-w-7xl lg:px-8">
|
<div class="mx-auto max-w-2xl p-4 sm:p-6 lg:max-w-7xl lg:px-8">
|
||||||
<h1>Your Watching List</h1>
|
<h1 class="text-left text-xl font-bold mb-4">Your Watching List</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">
|
<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 aniListWatchlist.data.Page.mediaList as media}
|
{#each aniListWatchlist.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="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg xl:aspect-h-8 xl:aspect-w-7">
|
||||||
<button on:click={() => GetAniListSingleItemAndOpenModal(media.media.id, true)} class="group">
|
<div class="flex flex-col items-center group">
|
||||||
<div class="flex flex-col items-center">
|
<button on:click={() => GetAniListSingleItemAndOpenModal(media.media.id, true)}>
|
||||||
<img class="rounded-lg" src={media.media.coverImage.large} alt={
|
<img class="rounded-lg" src={media.media.coverImage.large} alt={
|
||||||
media.media.title.english === "" ?
|
media.media.title.english === "" ?
|
||||||
media.media.title.romaji :
|
media.media.title.romaji :
|
||||||
media.media.title.english
|
media.media.title.english
|
||||||
}/>
|
}/>
|
||||||
{config.score = media.score / 2.0}
|
</button>
|
||||||
<StarRatting {config}/>
|
<Rating id="anime-rating" total={5} size={35} rating={media.score/2.0} />
|
||||||
<h3 class="mt-4 text-sm text-white-700">{
|
<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.english === "" ?
|
||||||
media.media.title.romaji :
|
media.media.title.romaji :
|
||||||
media.media.title.english
|
media.media.title.english
|
||||||
}</h3>
|
}
|
||||||
<p class="mt-1 text-lg font-medium text-white-900">{media.progress}
|
</button>
|
||||||
/ {media.media.nextAiringEpisode.episode !== 0 ?
|
<p class="mt-1 text-lg font-medium text-white-900">{media.progress}
|
||||||
media.media.nextAiringEpisode.episode - 1 : media.media.episodes}</p>
|
/ {media.media.nextAiringEpisode.episode !== 0 ?
|
||||||
{#if media.media.episodes > 0}
|
media.media.nextAiringEpisode.episode - 1 : media.media.episodes}</p>
|
||||||
<p class="mt-1 text-lg font-medium text-white-900">Total
|
{#if media.media.episodes > 0}
|
||||||
Episodes: {media.media.episodes}</p>
|
<p class="mt-1 text-lg font-medium text-white-900">Total
|
||||||
{/if}
|
Episodes: {media.media.episodes}</p>
|
||||||
</div>
|
{/if}
|
||||||
</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="flex items-center justify-center">
|
|
||||||
<button on:click={decrement}
|
|
||||||
class="flex justify-center items-center w-10 h-10 rounded-full text-white focus:outline-none bg-gray-400 hover:bg-gray-500">
|
|
||||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<input bind:value={count} class="text-2xl font-bold mx-4"/>
|
|
||||||
<button on:click={increment}
|
|
||||||
class="flex justify-center items-center w-10 h-10 rounded-full text-white focus:outline-none bg-indigo-500 hover:bg-indigo-600">
|
|
||||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v12M6 12h12"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="relative max-w-sm">-->
|
|
||||||
<!-- <div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">-->
|
|
||||||
<!-- <svg class="w-4 h-4 text-gray-500 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">-->
|
|
||||||
<!-- <path d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"/>-->
|
|
||||||
<!-- </svg>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <input-->
|
|
||||||
<!-- datepicker-->
|
|
||||||
<!-- datepicker-buttons-->
|
|
||||||
<!-- datepicker-autoselect-today-->
|
|
||||||
<!-- datepicker-autohide-->
|
|
||||||
<!-- datepicker-title="Started At"-->
|
|
||||||
<!-- id="startedAt"-->
|
|
||||||
<!-- type="text"-->
|
|
||||||
<!-- class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500-->
|
|
||||||
<!-- focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600-->
|
|
||||||
<!-- dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"-->
|
|
||||||
<!-- placeholder="Select date">-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<Modal title={$title} bind:open={$anilistModal} {size} autoclose={false}>
|
<Modal title={$title} bind:open={$anilistModal} {size} autoclose={false}>
|
||||||
<ChangeDataDialogue/>
|
<ChangeDataDialogue/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -1,7 +1,90 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {anime} from "./GetAniListSingleItemAndOpenModal.svelte";
|
import {
|
||||||
|
anilistModal,
|
||||||
|
simklWatchList,
|
||||||
|
aniListLoggedIn,
|
||||||
|
simklLoggedIn
|
||||||
|
} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||||
|
import {aniListAnime} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||||
import {Button} from "flowbite-svelte";
|
import {Button} from "flowbite-svelte";
|
||||||
|
// @ts-ignore
|
||||||
import StarRatting from "@ernane/svelte-star-rating"
|
import StarRatting from "@ernane/svelte-star-rating"
|
||||||
|
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 { get } from 'svelte/store';
|
||||||
|
import {AniListUpdateEntry} from "../wailsjs/go/main/App";
|
||||||
|
|
||||||
|
const simklWatch = get(simklWatchList);
|
||||||
|
let isAniListLoggedIn: boolean
|
||||||
|
let isSimklLoggedIn: boolean
|
||||||
|
|
||||||
|
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
|
||||||
|
simklLoggedIn.subscribe((value) => isSimklLoggedIn = value)
|
||||||
|
|
||||||
|
const simklAnime: SimklAnime | undefined = simklWatch.anime.filter((x) => Number(x.show.ids.mal) === aniListAnime.data.MediaList.media.idMal)[0]
|
||||||
|
|
||||||
|
let items = [];
|
||||||
|
|
||||||
|
if(isAniListLoggedIn) {
|
||||||
|
items.push({
|
||||||
|
id: aniListAnime.data.MediaList.id,
|
||||||
|
service: "AniList",
|
||||||
|
progress: aniListAnime.data.MediaList.progress,
|
||||||
|
status: aniListAnime.data.MediaList.status,
|
||||||
|
startedAt: `${aniListAnime.data.MediaList.startedAt.month}-${aniListAnime.data.MediaList.startedAt.day}-${aniListAnime.data.MediaList.startedAt.year}`,
|
||||||
|
completedAt: `${aniListAnime.data.MediaList.completedAt.month}-${aniListAnime.data.MediaList.completedAt.day}-${aniListAnime.data.MediaList.completedAt.year}`,
|
||||||
|
score: aniListAnime.data.MediaList.score,
|
||||||
|
repeat: aniListAnime.data.MediaList.repeat,
|
||||||
|
notes: aniListAnime.data.MediaList.notes
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isSimklLoggedIn && simklAnime !== undefined) {
|
||||||
|
items.push({
|
||||||
|
id: simklAnime.show.ids.simkl,
|
||||||
|
service: "Simkl",
|
||||||
|
progress: simklAnime.watched_episodes_count,
|
||||||
|
status: simklAnime.status,
|
||||||
|
startedAt: "",
|
||||||
|
completedAt: "",
|
||||||
|
score: simklAnime.user_rating,
|
||||||
|
repeat: 0,
|
||||||
|
notes: ""
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortKey = writable('service'); // default sort key
|
||||||
|
const sortDirection = writable(1); // default sort direction (ascending)
|
||||||
|
const sortItems = writable(items.slice()); // make a copy of the items array
|
||||||
|
|
||||||
|
// Define a function to sort the items
|
||||||
|
const sortTable = (key: any) => {
|
||||||
|
// If the same key is clicked, reverse the sort direction
|
||||||
|
if ($sortKey === key) {
|
||||||
|
sortDirection.update((val) => -val);
|
||||||
|
} else {
|
||||||
|
sortKey.set(key);
|
||||||
|
sortDirection.set(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$: {
|
||||||
|
const key = $sortKey;
|
||||||
|
const direction = $sortDirection;
|
||||||
|
const sorted = [...$sortItems].sort((a, b) => {
|
||||||
|
const aVal = a[key];
|
||||||
|
const bVal = b[key];
|
||||||
|
if (aVal < bVal) {
|
||||||
|
return -direction;
|
||||||
|
} else if (aVal > bVal) {
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
sortItems.set(sorted);
|
||||||
|
}
|
||||||
|
|
||||||
const ratingInWords = {
|
const ratingInWords = {
|
||||||
0: "Not Reviewed",
|
0: "Not Reviewed",
|
||||||
@ -17,9 +100,14 @@
|
|||||||
10: "Masterpiece",
|
10: "Masterpiece",
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = anime.data.MediaList.media.title.english !== "" ?
|
const hide = (e) => {
|
||||||
anime.data.MediaList.media.title.english :
|
e.preventDefault();
|
||||||
anime.data.MediaList.media.title.romaji
|
anilistModal.set(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
const title = aniListAnime.data.MediaList.media.title.english !== "" ?
|
||||||
|
aniListAnime.data.MediaList.media.title.english :
|
||||||
|
aniListAnime.data.MediaList.media.title.romaji
|
||||||
|
|
||||||
let config = {
|
let config = {
|
||||||
readOnly: false,
|
readOnly: false,
|
||||||
@ -29,7 +117,7 @@
|
|||||||
max: 5,
|
max: 5,
|
||||||
step: 0.5
|
step: 0.5
|
||||||
},
|
},
|
||||||
score: anime.data.MediaList.score / 2,
|
score: aniListAnime.data.MediaList.score / 2,
|
||||||
showScore: false,
|
showScore: false,
|
||||||
scoreFormat: function () {
|
scoreFormat: function () {
|
||||||
return `(${this.score.toFixed(1)}/${this.countStars})`
|
return `(${this.score.toFixed(1)}/${this.countStars})`
|
||||||
@ -45,42 +133,37 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let values = {
|
let values = {
|
||||||
progress: anime.data.MediaList.progress,
|
progress: aniListAnime.data.MediaList.progress,
|
||||||
status: anime.data.MediaList.status,
|
status: aniListAnime.data.MediaList.status,
|
||||||
startedAt: {
|
startedAt: {
|
||||||
year: anime.data.MediaList.startedAt.year,
|
year: aniListAnime.data.MediaList.startedAt.year,
|
||||||
month: anime.data.MediaList.startedAt.month,
|
month: aniListAnime.data.MediaList.startedAt.month,
|
||||||
day: anime.data.MediaList.startedAt.day
|
day: aniListAnime.data.MediaList.startedAt.day
|
||||||
},
|
},
|
||||||
completedAt: {
|
completedAt: {
|
||||||
year: anime.data.MediaList.completedAt.year,
|
year: aniListAnime.data.MediaList.completedAt.year,
|
||||||
month: anime.data.MediaList.completedAt.month,
|
month: aniListAnime.data.MediaList.completedAt.month,
|
||||||
day: anime.data.MediaList.completedAt.day
|
day: aniListAnime.data.MediaList.completedAt.day
|
||||||
},
|
},
|
||||||
repeat: anime.data.MediaList.repeat,
|
repeat: aniListAnime.data.MediaList.repeat,
|
||||||
score: anime.data.MediaList.score,
|
score: aniListAnime.data.MediaList.score,
|
||||||
notes: anime.data.MediaList.notes
|
notes: aniListAnime.data.MediaList.notes
|
||||||
}
|
}
|
||||||
|
let startedAtDate: string
|
||||||
|
let completedAtDate: string
|
||||||
|
|
||||||
const changeRating = (e) => {
|
const changeRating = (e) => {
|
||||||
config.score = e.target.valueAsNumber
|
config.score = e.target.valueAsNumber
|
||||||
values.score = e.target.valueAsNumber * 2
|
values.score = e.target.valueAsNumber * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = 1;
|
|
||||||
|
|
||||||
const decrement = () => {
|
if (values.startedAt.year > 0) {
|
||||||
if (count > 0) {
|
let startedAtISODate = new Date(values.startedAt.year, values.startedAt.month - 1, values.startedAt.day)
|
||||||
count--
|
let startedAtMoment = moment(startedAtISODate)
|
||||||
}
|
startedAtDate = startedAtMoment.format('YYYY-MM-DD')
|
||||||
}
|
}
|
||||||
|
|
||||||
const increment = () => {
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
|
|
||||||
let startedAtDate = `${values.startedAt.year}-${values.startedAt.month}-${values.startedAt.day}`
|
|
||||||
|
|
||||||
const transformStartedAtDate = (e) => {
|
const transformStartedAtDate = (e) => {
|
||||||
const re = /^([0-9]{4})-([0-9]{2})-([0-9]{2})/
|
const re = /^([0-9]{4})-([0-9]{2})-([0-9]{2})/
|
||||||
const date = re.exec(e.target.value)
|
const date = re.exec(e.target.value)
|
||||||
@ -89,31 +172,62 @@
|
|||||||
values.startedAt.day = Number(date[3])
|
values.startedAt.day = Number(date[3])
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(startedAtDate)
|
if (values.completedAt.year > 0) {
|
||||||
|
let completedAtISODate = new Date(values.completedAt.year, values.completedAt.month - 1, values.completedAt.day)
|
||||||
|
let completedAtMoment = moment(completedAtISODate)
|
||||||
|
completedAtDate = completedAtMoment.format('YYYY-MM-DD')
|
||||||
|
}
|
||||||
|
|
||||||
|
const transformCompletedAtDate = (e) => {
|
||||||
|
const re = /^([0-9]{4})-([0-9]{2})-([0-9]{2})/
|
||||||
|
const date = re.exec(e.target.value)
|
||||||
|
values.completedAt.year = Number(date[1])
|
||||||
|
values.completedAt.month = Number(date[2])
|
||||||
|
values.completedAt.day = Number(date[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitData = async () => {
|
||||||
|
await AniListUpdateEntry(
|
||||||
|
aniListAnime.data.MediaList.mediaId,
|
||||||
|
values.progress,
|
||||||
|
values.status,
|
||||||
|
values.score,
|
||||||
|
values.repeat,
|
||||||
|
values.notes,
|
||||||
|
values.startedAt.year,
|
||||||
|
values.startedAt.month,
|
||||||
|
values.startedAt.day,
|
||||||
|
values.completedAt.year,
|
||||||
|
values.completedAt.month,
|
||||||
|
values.completedAt.day
|
||||||
|
).then((value) => {
|
||||||
|
console.log(value)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div id="inapp-data">
|
||||||
<div class="grid grid-rows-2 grid-cols-10 grid-flow-col gap-4 mt-10">
|
<div class="grid grid-cols-1 md:grid-cols-10 grid-flow-col gap-4">
|
||||||
<div class="row-span-2 col-span-2 space-y-3">
|
<div class="md:col-span-2 space-y-3">
|
||||||
<img class="rounded-lg" src={anime.data.MediaList.media.coverImage.large} alt="{title} Cover Image">
|
<img class="rounded-lg" src={aniListAnime.data.MediaList.media.coverImage.large} alt="{title} Cover Image">
|
||||||
<StarRatting bind:config on:change={changeRating}/>
|
<StarRatting bind:config on:change={changeRating}/>
|
||||||
<p>Rating: {config.score * 2}</p>
|
<p>Rating: {config.score * 2}</p>
|
||||||
<p>{ratingInWords[config.score * 2]}</p>
|
<p>{ratingInWords[config.score * 2]}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-8 z-30">
|
<div class="md:col-span-8 ">
|
||||||
<div class="flex flex-row p-10 justify-center gap-x-56">
|
<div class="flex flex-col md:flex-row md:pl-10 md:pr-10 pt-5 pb-5 justify-center md:gap-x-24 lg:gap-x-56">
|
||||||
|
<div>
|
||||||
|
<label for="episodes" class="text-left block mb-2 text-sm font-medium text-gray-900 dark:text-white">Episode
|
||||||
<div class="mr-4">
|
Progress</label>
|
||||||
<label for="episodes" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Episode Progress</label>
|
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
name="episodes"
|
name="episodes"
|
||||||
min="0"
|
min="0"
|
||||||
id="episodes"
|
id="episodes"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400
|
focus:border-primary-600 block w-24 p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400
|
||||||
dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
||||||
bind:value={values.progress}
|
bind:value={values.progress}
|
||||||
required>
|
required>
|
||||||
@ -121,13 +235,13 @@
|
|||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="status" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Select
|
<label for="status"
|
||||||
your
|
class="text-left block mb-2 text-sm font-medium text-gray-900 dark:text-white">Status</label>
|
||||||
country</label>
|
|
||||||
<select id="status"
|
<select id="status"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500
|
||||||
focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400
|
focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400
|
||||||
dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
|
bind:value={values.status}
|
||||||
>
|
>
|
||||||
|
|
||||||
<option>CURRENT</option>
|
<option>CURRENT</option>
|
||||||
@ -139,58 +253,141 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row p-10 justify-center">
|
<div class="flex flex-col md:flex-row md:pl-10 md:pr-10 pt-5 pb-5 justify-center md:gap-x-16 lg:gap-x-36">
|
||||||
|
|
||||||
<div class="relative z-40 max-w-sm">
|
<div>
|
||||||
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
|
||||||
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
<label for="startedAt" class="text-left block mb-2 text-sm font-medium text-gray-900 dark:text-white">Date
|
||||||
<path d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"/>
|
Started</label>
|
||||||
</svg>
|
<div class="relative max-w-sm">
|
||||||
</div>
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
||||||
<!-- <input-->
|
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400" aria-hidden="true"
|
||||||
<!-- datepicker-->
|
xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<!-- datepicker-buttons-->
|
<path d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"/>
|
||||||
<!-- datepicker-autoselect-today-->
|
</svg>
|
||||||
<!-- datepicker-autohide-->
|
</div>
|
||||||
<!-- datepicker-title="Started At"-->
|
<input
|
||||||
<!-- id="startedAt"-->
|
id="startedAt"
|
||||||
<!-- type="text"-->
|
type="date"
|
||||||
<!-- name="startedAt"-->
|
name="startedAt"
|
||||||
<!-- class="z-50 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500-->
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500
|
||||||
<!-- focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600-->
|
|
||||||
<!-- dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"-->
|
|
||||||
<!-- value={`${values.startedAt.year}-${values.startedAt.month}-${values.startedAt.day}`}-->
|
|
||||||
<!-- on:change={transformStartedAtDate}-->
|
|
||||||
<!-- >-->
|
|
||||||
<input
|
|
||||||
id="startedAt"
|
|
||||||
type="date"
|
|
||||||
name="startedAt"
|
|
||||||
class="z-50 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500
|
|
||||||
focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600
|
focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
value={startedAtDate}
|
value={startedAtDate}
|
||||||
on:change={transformStartedAtDate}
|
placeholder="Date Started"
|
||||||
>
|
on:change={transformStartedAtDate}
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<label for="completedAt" class="text-left block mb-2 text-sm font-medium text-gray-900 dark:text-white">Date
|
||||||
|
Completed</label>
|
||||||
|
<div class="relative max-w-sm">
|
||||||
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
||||||
|
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400" aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
id="completedAt"
|
||||||
|
type="date"
|
||||||
|
name="completedAt"
|
||||||
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500
|
||||||
|
focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600
|
||||||
|
dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
|
value={completedAtDate}
|
||||||
|
placeholder="Date Completed"
|
||||||
|
on:change={transformCompletedAtDate}
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="repeat"
|
||||||
|
class="text-left block mb-2 text-sm font-medium text-gray-900 dark:text-white">Rewatched</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
name="repeat"
|
||||||
|
min="0"
|
||||||
|
id="repeat"
|
||||||
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
||||||
|
focus:border-primary-600 block w-24 p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400
|
||||||
|
dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
||||||
|
bind:value={values.repeat}
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col md:flex-row md:pl-10 md:pr-10 pt-5 pb-5 justify-center">
|
||||||
|
<div class="w-full">
|
||||||
|
<label for="notes" class="text-left block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your
|
||||||
|
notes</label>
|
||||||
|
<textarea id="notes" rows="3"
|
||||||
|
class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
|
placeholder="Write your thoughts here..."
|
||||||
|
bind:value={values.notes}></textarea>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="bg-white rounded-lg shadow m-4 dark:bg-gray-800">
|
<div id="external-data">
|
||||||
|
<div id="anilist-data" class="flex flex-col md:flex-row md:pl-10 md:pr-10 pt-5 pb-5 justify-center md:gap-x-16 lg:gap-x-36 group">
|
||||||
|
<h2 class="text-left mb-1 text-base font-semibold text-gray-900 dark:text-white">AniList</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Table hoverable={true}>
|
||||||
|
<TableHead>
|
||||||
|
<TableHeadCell class="cursor-pointer" on:click={() => sortTable('id')}>ID</TableHeadCell>
|
||||||
|
<TableHeadCell class="cursor-pointer" on:click={() => sortTable('service')}>Service</TableHeadCell>
|
||||||
|
<TableHeadCell class="cursor-pointer" on:click={() => sortTable('progress')}>Episode Progress</TableHeadCell>
|
||||||
|
<TableHeadCell class="cursor-pointer" on:click={() => sortTable('status')}>Status</TableHeadCell>
|
||||||
|
<TableHeadCell class="cursor-pointer" on:click={() => sortTable('startedAt')}>Date Started</TableHeadCell>
|
||||||
|
<TableHeadCell class="cursor-pointer" on:click={() => sortTable('completedAt')}>Date Completed</TableHeadCell>
|
||||||
|
<TableHeadCell class="cursor-pointer" on:click={() => sortTable('score')}>Rating</TableHeadCell>
|
||||||
|
<TableHeadCell class="cursor-pointer" on:click={() => sortTable('repeat')}>Rewatches</TableHeadCell>
|
||||||
|
<TableHeadCell>Notes</TableHeadCell>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody tableBodyClass="divide-y">
|
||||||
|
{#each $sortItems as item}
|
||||||
|
<TableBodyRow>
|
||||||
|
<TableBodyCell class="overflow-x-auto">{item.id}</TableBodyCell>
|
||||||
|
<TableBodyCell class="overflow-x-auto">{item.service}</TableBodyCell>
|
||||||
|
<TableBodyCell class="overflow-x-auto">{item.progress}</TableBodyCell>
|
||||||
|
<TableBodyCell class="overflow-x-auto">{item.status}</TableBodyCell>
|
||||||
|
<TableBodyCell class="overflow-x-auto">{item.startedAt}</TableBodyCell>
|
||||||
|
<TableBodyCell class="overflow-x-auto">{item.completedAt}</TableBodyCell>
|
||||||
|
<TableBodyCell class="overflow-x-auto">{item.score}</TableBodyCell>
|
||||||
|
<TableBodyCell class="overflow-x-auto">{item.repeat}</TableBodyCell>
|
||||||
|
<TableBodyCell class="overflow-x-auto">{item.notes}</TableBodyCell>
|
||||||
|
</TableBodyRow>
|
||||||
|
{/each}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="bg-white rounded-lg shadow max-w-4-4 dark:bg-gray-800">
|
||||||
<div class="w-full mx-auto max-w-screen-xl p-4 md:flex md:items-center md:justify-end">
|
<div class="w-full mx-auto max-w-screen-xl p-4 md:flex md:items-center md:justify-end">
|
||||||
<Button
|
<Button
|
||||||
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium
|
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium
|
||||||
rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none
|
rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none
|
||||||
dark:focus:ring-blue-800"
|
dark:focus:ring-blue-800"
|
||||||
on:click={() => alert('Handle "success"')}>Sync Changes
|
on:click={submitData}>Sync Changes
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
class="text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4
|
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
|
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">
|
dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700"
|
||||||
|
on:click={hide}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 class="text-2xl">
|
||||||
|
Summary
|
||||||
|
</h3>
|
||||||
|
<p>{@html aniListAnime.data.MediaList.media.description}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
@ -2,17 +2,21 @@
|
|||||||
import {GetAniListItem} from "../wailsjs/go/main/App";
|
import {GetAniListItem} from "../wailsjs/go/main/App";
|
||||||
import type {AniListGetSingleAnime} from "./anilist/types/AniListCurrentUserWatchListType.js";
|
import type {AniListGetSingleAnime} from "./anilist/types/AniListCurrentUserWatchListType.js";
|
||||||
import {writable} from 'svelte/store'
|
import {writable} from 'svelte/store'
|
||||||
|
import type {SimklWatchList} from "./simkl/types/simklTypes";
|
||||||
|
|
||||||
export let anime: AniListGetSingleAnime
|
export let aniListAnime: AniListGetSingleAnime
|
||||||
export let title = writable("")
|
export let title = writable("")
|
||||||
export let anilistModal = writable(false);
|
export let anilistModal = writable(false);
|
||||||
|
export let aniListLoggedIn = writable(false)
|
||||||
|
export let simklLoggedIn = writable(false)
|
||||||
|
export let simklWatchList = writable({} as SimklWatchList)
|
||||||
|
|
||||||
export function GetAniListSingleItemAndOpenModal(aniId: number, login: boolean): void {
|
export function GetAniListSingleItemAndOpenModal(aniId: number, login: boolean): void {
|
||||||
GetAniListItem(aniId, login).then(result => {
|
GetAniListItem(aniId, login).then(result => {
|
||||||
anime = result
|
aniListAnime = result
|
||||||
title.set(anime.data.MediaList.media.title.english === "" ?
|
title.set(aniListAnime.data.MediaList.media.title.english === "" ?
|
||||||
anime.data.MediaList.media.title.romaji :
|
aniListAnime.data.MediaList.media.title.romaji :
|
||||||
anime.data.MediaList.media.title.english)
|
aniListAnime.data.MediaList.media.title.english)
|
||||||
anilistModal.set(true)
|
anilistModal.set(true)
|
||||||
})
|
})
|
||||||
}
|
}
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import {AniListSearch} from "../wailsjs/go/main/App";
|
import {AniListSearch} from "../wailsjs/go/main/App";
|
||||||
import type {AniSearchList} from "./anilist/types/AniListTypes";
|
import type {AniSearchList} from "./anilist/types/AniListTypes";
|
||||||
import {GetAniListSingleItemAndOpenModal} from "./GetAniListSingleItemAndOpenModal.svelte";
|
import {GetAniListSingleItemAndOpenModal} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||||
|
|
||||||
let aniSearch = ""
|
let aniSearch = ""
|
||||||
let aniListSearch: AniSearchList
|
let aniListSearch: AniSearchList
|
||||||
@ -51,14 +51,18 @@
|
|||||||
aria-labelledby="aniListSearchButton">
|
aria-labelledby="aniListSearchButton">
|
||||||
{#each aniListSearch.data.Page.media as media}
|
{#each aniListSearch.data.Page.media as media}
|
||||||
<li class="w-full">
|
<li class="w-full">
|
||||||
<button on:click={() => {
|
<div class="flex w-full items-start p-1 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white rounded-lg">
|
||||||
GetAniListSingleItemAndOpenModal(media.id, false)
|
<button on:click={() => {
|
||||||
}}
|
GetAniListSingleItemAndOpenModal(media.id, false)
|
||||||
class="flex w-full items-start p-1 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white rounded-lg">
|
}}
|
||||||
<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">
|
<img class="rounded-bl-lg rounded-tl-lg max-w-24 max-h-24" src={media.coverImage.large}
|
||||||
<p class="bg-gray-800 text-left w-full h-24 p-2 rounded-tr-lg rounded-br-lg">{media.title.english === '' || media.title.english === null ? media.title.romaji : media.title.english }</p>
|
alt="{media.title.english === '' || media.title.english === null ? media.title.romaji : media.title.english} Cover">
|
||||||
</button>
|
</button>
|
||||||
|
<button class="rounded-bl-lg rounded-tl-lg w-full h-24" on:click={() => {
|
||||||
|
GetAniListSingleItemAndOpenModal(media.id, false)
|
||||||
|
}} >{media.title.english === '' || media.title.english === null ? media.title.romaji : media.title.english }</button>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
|
155
frontend/src/modal/Modal.svelte
Normal file
155
frontend/src/modal/Modal.svelte
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<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
Normal file
77
frontend/src/modal/Modal.svelte.d.ts
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
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 {};
|
@ -19,41 +19,43 @@ export type SimklUser = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type SimklWatchList = {
|
export type SimklWatchList = {
|
||||||
anime: [{
|
anime: [SimklAnime]
|
||||||
last_watched_at: string,
|
}
|
||||||
status: string
|
|
||||||
user_rating: number,
|
export type SimklAnime = {
|
||||||
last_watched: string,
|
last_watched_at: string,
|
||||||
next_to_watch: string,
|
status: string
|
||||||
watched_episodes_count: number,
|
user_rating: number,
|
||||||
total_episodes_count: number,
|
last_watched: string,
|
||||||
not_aired_episodes_count: number,
|
next_to_watch: string,
|
||||||
show: {
|
watched_episodes_count: number,
|
||||||
title: string,
|
total_episodes_count: number,
|
||||||
poster: string,
|
not_aired_episodes_count: number,
|
||||||
ids: {
|
show: {
|
||||||
simkl: number,
|
title: string,
|
||||||
slug: string,
|
poster: string,
|
||||||
offjp: string,
|
ids: {
|
||||||
tw: string,
|
simkl: number,
|
||||||
ann: string,
|
slug: string,
|
||||||
mal: string,
|
offjp: string,
|
||||||
wikien: string,
|
tw: string,
|
||||||
wikijp: string,
|
ann: string,
|
||||||
allcin: string,
|
mal: string,
|
||||||
imdb: string,
|
wikien: string,
|
||||||
offen: string,
|
wikijp: string,
|
||||||
crunchyroll: string,
|
allcin: string,
|
||||||
tvdbslug: string,
|
imdb: string,
|
||||||
anilist: string,
|
offen: string,
|
||||||
animeplanet: string,
|
crunchyroll: string,
|
||||||
anisearch: string,
|
tvdbslug: string,
|
||||||
kitsu: string,
|
anilist: string,
|
||||||
livechart: string,
|
animeplanet: string,
|
||||||
traktslug: string,
|
anisearch: string,
|
||||||
anidb: string,
|
kitsu: string,
|
||||||
}
|
livechart: string,
|
||||||
},
|
traktslug: string,
|
||||||
anime_type: string
|
anidb: string,
|
||||||
}]
|
}
|
||||||
|
},
|
||||||
|
anime_type: string
|
||||||
}
|
}
|
2
frontend/wailsjs/go/main/App.d.ts
vendored
2
frontend/wailsjs/go/main/App.d.ts
vendored
@ -6,7 +6,7 @@ export function AniListLogin():Promise<void>;
|
|||||||
|
|
||||||
export function AniListSearch(arg1:string):Promise<any>;
|
export function AniListSearch(arg1:string):Promise<any>;
|
||||||
|
|
||||||
export function AniListUpdateEntry(arg1:number,arg2:string,arg3:string,arg4:number,arg5:number,arg6:string,arg7:number,arg8:number,arg9:number,arg10:number,arg11:number,arg12:number):Promise<any>;
|
export function AniListUpdateEntry(arg1:number,arg2:number,arg3:string,arg4:number,arg5:number,arg6:string,arg7:number,arg8:number,arg9:number,arg10:number,arg11:number,arg12:number):Promise<any>;
|
||||||
|
|
||||||
export function CheckIfAniListLoggedIn():Promise<boolean>;
|
export function CheckIfAniListLoggedIn():Promise<boolean>;
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ export namespace main {
|
|||||||
id: number;
|
id: number;
|
||||||
mediaId: number;
|
mediaId: number;
|
||||||
userId: number;
|
userId: number;
|
||||||
// Go type: struct { ID int "json:\"id\""; IDMal int "json:\"idMal\""; Title struct { Romaji string "json:\"romaji\""; English string "json:\"english\""; Native string "json:\"native\"" } "json:\"title\""; Description string "json:\"description\""; CoverImage struct { Large string "json:\"large\"" } "json:\"coverImage\""; Season string "json:\"season\""; SeasonYear int "json:\"seasonYear\""; Status string "json:\"status\""; Episodes int "json:\"episodes\""; NextAiringEpisode struct { AiringAt int "json:\"airingAt\""; TimeUntilAiring int "json:\"timeUntilAiring\""; Episode int "json:\"episode\"" } "json:\"nextAiringEpisode\"" }
|
// Go type: struct { ID int "json:\"id\""; IDMal int "json:\"idMal\""; Title struct { Romaji string "json:\"romaji\""; English string "json:\"english\""; Native string "json:\"native\"" } "json:\"title\""; Description string "json:\"description\""; CoverImage struct { Large string "json:\"large\"" } "json:\"coverImage\""; Season string "json:\"season\""; SeasonYear int "json:\"seasonYear\""; Status string "json:\"status\""; Episodes int "json:\"episodes\""; NextAiringEpisode struct { AiringAt int "json:\"airingAt\""; TimeUntilAiring int "json:\"timeUntilAiring\""; Episode int "json:\"episode\"" } "json:\"nextAiringEpisode\""; Tags []struct { Id int "json:\"id\""; Name string "json:\"name\""; Description string "json:\"description\""; Rank int "json:\"rank\""; IsMediaSpoiler bool "json:\"isMediaSpoiler\""; IsAdult bool "json:\"isAdult\"" } "json:\"tags\""; IsAdult bool "json:\"isAdult\"" }
|
||||||
media: any;
|
media: any;
|
||||||
status: string;
|
status: string;
|
||||||
// Go type: struct { Year int "json:\"year\""; Month int "json:\"month\""; Day int "json:\"day\"" }
|
// Go type: struct { Year int "json:\"year\""; Month int "json:\"month\""; Day int "json:\"day\"" }
|
||||||
|
Loading…
Reference in New Issue
Block a user