diff --git a/src/App.svelte b/src/App.svelte index 3b32fcb..e0ee380 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -11,16 +11,10 @@ import SeriesPage from './lib/components/SeriesPage/SeriesPage.svelte'; import Sidebar from './lib/components/Sidebar/Sidebar.svelte'; import LoginPage from './lib/pages/LoginPage.svelte'; - import { getReiverrApiClient } from './lib/apis/reiverr/reiverr-api'; import { appState } from './lib/stores/app-state.store'; import MoviePage from './lib/pages/MoviePage.svelte'; import ModalStack from './lib/components/Modal/ModalStack.svelte'; - - getReiverrApiClient() - .GET('/user', {}) - .then((res) => res.data) - .then((user) => appState.setUser(user || null)) - .catch(() => appState.setUser(null)); + import PageNotFound from './lib/pages/PageNotFound.svelte'; appState.subscribe((s) => console.log('appState', s)); @@ -58,7 +52,7 @@ -
404
+
diff --git a/src/app.css b/src/app.css index 7f12a61..096a237 100644 --- a/src/app.css +++ b/src/app.css @@ -50,6 +50,14 @@ html[data-useragent*="Tizen"] .selectable { border-width: 2px; } +.selected { + @apply outline-none outline-0 border-2 border-highlight-foreground; +} + +.unselected { + @apply outline-none outline-0 border-2 border-transparent; +} + .peer-selectable { @apply peer-focus-visible:outline outline-2 outline-[#f0cd6dc2] outline-offset-2; } diff --git a/src/lib/apis/reiverr/reiverr-api.ts b/src/lib/apis/reiverr/reiverr-api.ts index b3f5557..fd051e7 100644 --- a/src/lib/apis/reiverr/reiverr-api.ts +++ b/src/lib/apis/reiverr/reiverr-api.ts @@ -1,12 +1,15 @@ import createClient from 'openapi-fetch'; -import type { paths } from './reiverr.generated'; +import type { components, paths } from './reiverr.generated'; import { get } from 'svelte/store'; import { appState } from '../../stores/app-state.store'; import type { Api } from '../api.interface'; +export type ReiverrUser = components['schemas']['UserDto']; + export class ReiverrApi implements Api { - getClient(basePath?: string) { - const token = get(appState).token; + getClient(basePath?: string, _token?: string) { + const token = _token || get(appState).token; + console.log('token', token); return createClient({ baseUrl: (basePath || get(appState).serverBaseUrl) + '/api', @@ -17,6 +20,20 @@ export class ReiverrApi implements Api { }) }); } + + async getUser() { + const res = await this.getClient()?.GET('/user', {}); + return res.data; + } + + authenticate(name: string, password: string) { + return this.getClient().POST('/auth', { + body: { + name, + password + } + }); + } } export const reiverrApi = new ReiverrApi(); diff --git a/src/lib/components/Button.svelte b/src/lib/components/Button.svelte index 723959f..a1ed465 100644 --- a/src/lib/components/Button.svelte +++ b/src/lib/components/Button.svelte @@ -16,7 +16,7 @@ { 'bg-highlight-foreground text-stone-900': $hasFoucus, 'hover:bg-highlight-foreground hover:text-stone-900': true, - 'bg-stone-800/90': !$hasFoucus, + 'bg-highlight-background': !$hasFoucus, 'cursor-pointer': !inactive, 'cursor-not-allowed pointer-events-none opacity-40': inactive }, @@ -34,7 +34,9 @@ {/if} - +
+ +
{#if $$slots['icon-after']}
diff --git a/src/lib/components/TextField.svelte b/src/lib/components/TextField.svelte new file mode 100644 index 0000000..5a28fbe --- /dev/null +++ b/src/lib/components/TextField.svelte @@ -0,0 +1,46 @@ + + + { + if (!PLATFORM_TV) { + e.detail.options.setFocusedElement = input; + } + }} + on:clickOrSelect={() => input?.focus()} + class={classNames('flex flex-col', $$restProps.class)} + let:hasFocus +> + + + diff --git a/src/lib/pages/LoginPage.svelte b/src/lib/pages/LoginPage.svelte index a8a7982..f8c10f5 100644 --- a/src/lib/pages/LoginPage.svelte +++ b/src/lib/pages/LoginPage.svelte @@ -1,24 +1,17 @@ - + +

Login to Reiverr

+ + appState.setBaseUrl(e.detail)} + class="mt-4 w-full" + > + Server + + + Name + Name + + + {#if error}
{error}
{/if} - -
- Server: - input0?.focus()}> - appState.setBaseUrl(e?.target?.value)} - bind:this={input0} - /> - -
- -
- Name: - input1?.focus()}> - - -
- -
- Password: - input2?.focus()}> - - -
- Submit
diff --git a/src/lib/pages/ManagePage.svelte b/src/lib/pages/ManagePage.svelte index 1478264..c9e6b1e 100644 --- a/src/lib/pages/ManagePage.svelte +++ b/src/lib/pages/ManagePage.svelte @@ -1,18 +1,10 @@ - - Log Out - {window.navigator.userAgent} + + User agent: {window.navigator.userAgent} + diff --git a/src/lib/pages/PageNotFound.svelte b/src/lib/pages/PageNotFound.svelte new file mode 100644 index 0000000..1925dcd --- /dev/null +++ b/src/lib/pages/PageNotFound.svelte @@ -0,0 +1,17 @@ + + + +
404 {$location.pathname}
+
diff --git a/src/lib/selectable.ts b/src/lib/selectable.ts index 7b7438a..aaa434a 100644 --- a/src/lib/selectable.ts +++ b/src/lib/selectable.ts @@ -13,7 +13,7 @@ export type NavigationActions = { }; type FocusEventOptions = { - setFocusedElement: boolean; + setFocusedElement: boolean | HTMLElement; propagate: boolean; onFocus?: ( superOnFocus: FocusHandler, @@ -146,7 +146,11 @@ export class Selectable { propagateFocusUpdates(_options, this); if (_options.setFocusedElement) { - this.htmlElement.focus({ preventScroll: true }); + if (_options.setFocusedElement === true) { + this.htmlElement.focus({ preventScroll: true }); + } else { + _options.setFocusedElement.focus({ preventScroll: true }); + } Selectable.focusedObject.set(this); } } diff --git a/src/lib/stores/app-state.store.ts b/src/lib/stores/app-state.store.ts index fabe2cf..85becc0 100644 --- a/src/lib/stores/app-state.store.ts +++ b/src/lib/stores/app-state.store.ts @@ -1,23 +1,22 @@ import { derived, writable } from 'svelte/store'; -import type { components } from '../apis/reiverr/reiverr.generated'; import { createLocalStorageStore } from './localstorage.store'; - -export type User = components['schemas']['UserDto']; +import { getReiverrApiClient, type ReiverrUser } from '../apis/reiverr/reiverr-api'; interface AuthenticationStoreData { token?: string; serverBaseUrl?: string; } +const authenticationStore = createLocalStorageStore( + 'authentication-token', + { + token: undefined, + serverBaseUrl: window?.location?.origin + } +); function createAppState() { - const userStore = writable(undefined); - const authenticationStore = createLocalStorageStore( - 'authentication-token', - { - token: undefined, - serverBaseUrl: window?.location?.origin - } - ); + const userStore = writable(undefined); + const combinedStore = derived([userStore, authenticationStore], ([$user, $auth]) => { return { user: $user, @@ -34,17 +33,33 @@ function createAppState() { authenticationStore.update((p) => ({ ...p, token })); } - function setUser(user: User | null) { + function setUser(user: ReiverrUser | null) { userStore.set(user); } + function logOut() { + setUser(null); + setToken(undefined); + } + return { subscribe: combinedStore.subscribe, setBaseUrl, setToken, - setUser + setUser, + logOut }; } export const appState = createAppState(); export const appStateUser = derived(appState, ($state) => $state.user); + +authenticationStore.subscribe((auth) => { + if (auth.token) { + getReiverrApiClient(auth.serverBaseUrl, auth.token) + ?.GET('/user', {}) + .then((user) => appState.setUser(user || null)); + } else { + appState.setUser(null); + } +}); diff --git a/tailwind.config.js b/tailwind.config.js index d2b189e..830ea56 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -11,7 +11,8 @@ export default { darken: '#07050166', lighten: '#fde68a20', // 'highlight-foreground': '#E7E5E4' - 'highlight-foreground': '#ffe6abcc' + 'highlight-foreground': '#ffe6abcc', + 'highlight-background': '#2925247F' }, keyframes: { timer: {