mirror of
https://github.com/KevinMidboe/seasoned.git
synced 2026-06-09 06:13:14 +00:00
Feat: vite & upgraded dependencies (#100)
* On every route change, update local variables from query params * ResultSection is keyed to query to force re-render * Resolved lint warnings * replace webpack w/ vite * update all imports with alias @ and scss * vite environment variables, also typed * upgraded eslint, defined new rules & added ignore comments * resolved linting issues * moved index.html to project root * updated dockerfile w/ build stage before runtime image definition * sign drone config
This commit is contained in:
11
src/App.vue
11
src/App.vue
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div id="content">
|
||||
<!-- Header and hamburger navigation -->
|
||||
<NavigationHeader class="header" />
|
||||
|
||||
@@ -28,13 +28,13 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "src/scss/main";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/main";
|
||||
@import "scss/media-queries";
|
||||
|
||||
#app {
|
||||
#content {
|
||||
display: grid;
|
||||
grid-template-rows: var(--header-size);
|
||||
grid-template-columns: var(--header-size) 1fr;
|
||||
grid-template-columns: var(--header-size) 100%;
|
||||
|
||||
@include mobile {
|
||||
grid-template-columns: 1fr;
|
||||
@@ -58,6 +58,7 @@
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
width: calc(100% - var(--header-size));
|
||||
grid-column: 2 / 3;
|
||||
grid-row: 2;
|
||||
z-index: 5;
|
||||
|
||||
23
src/api.ts
23
src/api.ts
@@ -1,11 +1,13 @@
|
||||
/* eslint-disable n/no-unsupported-features/node-builtins */
|
||||
import { IList, IMediaCredits, IPersonCredits } from "./interfaces/IList";
|
||||
import type {
|
||||
IRequestStatusResponse,
|
||||
IRequestSubmitResponse
|
||||
} from "./interfaces/IRequestResponse";
|
||||
|
||||
const { ELASTIC, ELASTIC_INDEX, ELASTIC_APIKEY } = process.env;
|
||||
const API_HOSTNAME = window.location.origin;
|
||||
const API_HOSTNAME = import.meta.env.VITE_SEASONED_API;
|
||||
const ELASTIC_URL = import.meta.env.VITE_ELASTIC_URL;
|
||||
const ELASTIC_API_KEY = import.meta.env.VITE_ELASTIC_API_KEY;
|
||||
|
||||
// - - - TMDB - - -
|
||||
|
||||
@@ -334,7 +336,11 @@ const register = (username, password) => {
|
||||
});
|
||||
};
|
||||
|
||||
const login = (username, password, throwError = false) => {
|
||||
const login = async (
|
||||
username: string,
|
||||
password: string,
|
||||
throwError = false
|
||||
) => {
|
||||
const url = new URL("/api/v1/user/login", API_HOSTNAME);
|
||||
const options = {
|
||||
method: "POST",
|
||||
@@ -351,7 +357,7 @@ const login = (username, password, throwError = false) => {
|
||||
});
|
||||
};
|
||||
|
||||
const logout = (throwError = false) => {
|
||||
const logout = async (throwError = false) => {
|
||||
const url = new URL("/api/v1/user/logout", API_HOSTNAME);
|
||||
const options = { method: "POST" };
|
||||
|
||||
@@ -472,8 +478,9 @@ const getEmoji = async () => {
|
||||
* @param {string} query
|
||||
* @returns {object} List of movies and shows matching query
|
||||
*/
|
||||
const elasticSearchMoviesAndShows = (query: string, count = 22) => {
|
||||
const url = new URL(`${ELASTIC_INDEX}/_search`, ELASTIC);
|
||||
|
||||
const elasticSearchMoviesAndShows = (query, count = 22) => {
|
||||
const url = new URL(`${ELASTIC_URL}/_search`);
|
||||
|
||||
const body = {
|
||||
sort: [{ popularity: { order: "desc" } }, "_score"],
|
||||
@@ -521,8 +528,8 @@ const elasticSearchMoviesAndShows = (query: string, count = 22) => {
|
||||
const options = {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `ApiKey ${ELASTIC_APIKEY}`,
|
||||
"Content-Type": "application/json"
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `ApiKey ${ELASTIC_API_KEY}`
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
};
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import CastListItem from "src/components/CastListItem.vue";
|
||||
import { defineProps } from "vue";
|
||||
import CastListItem from "@/components/CastListItem.vue";
|
||||
import type {
|
||||
IMovie,
|
||||
IShow,
|
||||
|
||||
@@ -100,8 +100,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
|
||||
header {
|
||||
width: 100%;
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "src/scss/main";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
@import "scss/main";
|
||||
|
||||
header {
|
||||
width: 100%;
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
let _type: MediaTypes;
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
params.forEach((value, key) => {
|
||||
params.forEach((_, key) => {
|
||||
if (
|
||||
key !== MediaTypes.Movie &&
|
||||
key !== MediaTypes.Show &&
|
||||
@@ -90,8 +90,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.movie-popup {
|
||||
position: fixed;
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/media-queries";
|
||||
@import "src/scss/main";
|
||||
@import "scss/media-queries";
|
||||
@import "scss/main";
|
||||
|
||||
.no-results {
|
||||
width: 100%;
|
||||
|
||||
@@ -111,9 +111,9 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "src/scss/main";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
@import "scss/main";
|
||||
|
||||
.movie-item {
|
||||
padding: 15px;
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.resultSection {
|
||||
background-color: var(--background-color);
|
||||
|
||||
@@ -29,12 +29,11 @@ Searches Elasticsearch for results based on changes to `query`.
|
||||
-->
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import IconMovie from "@/icons/IconMovie.vue";
|
||||
import IconShow from "@/icons/IconShow.vue";
|
||||
import IconPerson from "@/icons/IconPerson.vue";
|
||||
import type { Ref } from "vue";
|
||||
import { ref, watch, defineProps } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import IconMovie from "../../icons/IconMovie.vue";
|
||||
import IconShow from "../../icons/IconShow.vue";
|
||||
import { elasticSearchMoviesAndShows } from "../../api";
|
||||
import { MediaTypes } from "../../interfaces/IList";
|
||||
import type {
|
||||
@@ -161,9 +160,9 @@ Searches Elasticsearch for results based on changes to `query`.
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "src/scss/main";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
@import "scss/main";
|
||||
$sizes: 22;
|
||||
|
||||
@for $i from 0 through $sizes {
|
||||
@@ -241,7 +240,9 @@ Searches Elasticsearch for results based on changes to `query`.
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
|
||||
transition: color 0.1s ease, fill 0.4s ease;
|
||||
transition:
|
||||
color 0.1s ease,
|
||||
fill 0.4s ease;
|
||||
|
||||
span {
|
||||
overflow-x: hidden;
|
||||
|
||||
@@ -61,8 +61,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.spacer {
|
||||
@include mobile-only {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.navigation-link {
|
||||
display: grid;
|
||||
@@ -47,8 +47,13 @@
|
||||
padding: 1rem 0.15rem;
|
||||
text-align: center;
|
||||
background-color: var(--background-color-secondary);
|
||||
transition: transform 0.3s ease, color 0.3s ease, stoke 0.3s ease,
|
||||
fill 0.3s ease, background-color 0.5s ease;
|
||||
transition:
|
||||
transform 0.3s ease,
|
||||
color 0.3s ease,
|
||||
stoke 0.3s ease,
|
||||
fill 0.3s ease,
|
||||
background-color 0.5s ease;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.navigation-icons {
|
||||
display: grid;
|
||||
|
||||
@@ -55,13 +55,13 @@ the `query`.
|
||||
-->
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Ref } from "vue";
|
||||
import { ref, computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import AutocompleteDropdown from "@/components/header/AutocompleteDropdown.vue";
|
||||
import IconSearch from "@/icons/IconSearch.vue";
|
||||
import IconClose from "@/icons/IconClose.vue";
|
||||
import type { Ref } from "vue";
|
||||
import AutocompleteDropdown from "./AutocompleteDropdown.vue";
|
||||
import IconSearch from "../../icons/IconSearch.vue";
|
||||
import IconClose from "../../icons/IconClose.vue";
|
||||
import type { MediaTypes } from "../../interfaces/IList";
|
||||
import { IAutocompleteResult } from "../../interfaces/IAutocompleteSearch";
|
||||
|
||||
@@ -98,13 +98,9 @@ import { IAutocompleteResult } from "../../interfaces/IAutocompleteSearch";
|
||||
query.value = decodeURIComponent(params.get("query"));
|
||||
}
|
||||
|
||||
const { ELASTIC, ELASTIC_APIKEY } = process.env;
|
||||
if (
|
||||
ELASTIC === undefined ||
|
||||
ELASTIC === "" ||
|
||||
ELASTIC_APIKEY === undefined ||
|
||||
ELASTIC_APIKEY === ""
|
||||
) {
|
||||
const ELASTIC_URL = import.meta.env.VITE_ELASTIC_URL;
|
||||
const ELASTIC_API_KEY = import.meta.env.VITE_ELASTIC_API_KEY;
|
||||
if (!ELASTIC_URL || !ELASTIC_API_KEY) {
|
||||
disabled.value = true;
|
||||
}
|
||||
|
||||
@@ -184,9 +180,9 @@ import { IAutocompleteResult } from "../../interfaces/IAutocompleteSearch";
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "src/scss/main";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
@import "scss/main";
|
||||
|
||||
.close-icon {
|
||||
position: absolute;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/media-queries";
|
||||
|
||||
li.sidebar-list-element {
|
||||
display: flex;
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
const overflow: Ref<boolean> = ref(false);
|
||||
const descriptionElement: Ref<HTMLElement> = ref(null);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
function removeElements(elems: NodeListOf<Element>) {
|
||||
elems.forEach(el => el.remove());
|
||||
}
|
||||
@@ -67,7 +66,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.movie-description {
|
||||
font-weight: 300;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.movie-detail {
|
||||
margin-bottom: 20px;
|
||||
|
||||
@@ -169,21 +169,20 @@
|
||||
import { useStore } from "vuex";
|
||||
|
||||
// import img from "@/directives/v-image";
|
||||
import IconProfile from "@/icons/IconProfile.vue";
|
||||
import IconThumbsUp from "@/icons/IconThumbsUp.vue";
|
||||
import IconThumbsDown from "@/icons/IconThumbsDown.vue";
|
||||
import IconInfo from "@/icons/IconInfo.vue";
|
||||
import IconRequest from "@/icons/IconRequest.vue";
|
||||
import IconRequested from "@/icons/IconRequested.vue";
|
||||
import IconBinoculars from "@/icons/IconBinoculars.vue";
|
||||
import IconPlay from "@/icons/IconPlay.vue";
|
||||
import TorrentList from "@/components/torrent/TruncatedTorrentResults.vue";
|
||||
import CastList from "@/components/CastList.vue";
|
||||
import Detail from "@/components/popup/Detail.vue";
|
||||
import ActionButton from "@/components/popup/ActionButton.vue";
|
||||
import Description from "@/components/popup/Description.vue";
|
||||
import LoadingPlaceholder from "@/components/ui/LoadingPlaceholder.vue";
|
||||
import type { Ref } from "vue";
|
||||
import IconProfile from "../../icons/IconProfile.vue";
|
||||
import IconThumbsUp from "../../icons/IconThumbsUp.vue";
|
||||
import IconThumbsDown from "../../icons/IconThumbsDown.vue";
|
||||
import IconInfo from "../../icons/IconInfo.vue";
|
||||
import IconRequest from "../../icons/IconRequest.vue";
|
||||
import IconRequested from "../../icons/IconRequested.vue";
|
||||
import IconBinoculars from "../../icons/IconBinoculars.vue";
|
||||
import IconPlay from "../../icons/IconPlay.vue";
|
||||
import TorrentList from "../torrent/TruncatedTorrentResults.vue";
|
||||
import CastList from "../CastList.vue";
|
||||
import Detail from "./Detail.vue";
|
||||
import ActionButton from "./ActionButton.vue";
|
||||
import Description from "./Description.vue";
|
||||
import LoadingPlaceholder from "../ui/LoadingPlaceholder.vue";
|
||||
import type {
|
||||
IMovie,
|
||||
IShow,
|
||||
@@ -342,10 +341,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/loading-placeholder";
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "src/scss/main";
|
||||
@import "scss/loading-placeholder";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
@import "scss/main";
|
||||
|
||||
header {
|
||||
$duration: 0.2s;
|
||||
|
||||
@@ -165,10 +165,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/loading-placeholder";
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "src/scss/main";
|
||||
@import "scss/loading-placeholder";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
@import "scss/main";
|
||||
|
||||
section.person {
|
||||
overflow: hidden;
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
try {
|
||||
validate();
|
||||
} catch (error) {
|
||||
console.log("not valid!"); // eslint-disable-line no-console
|
||||
console.log("not valid! error:", error); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
// const body: ResetPasswordPayload = {
|
||||
|
||||
@@ -102,9 +102,9 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "src/scss/elements";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
@import "scss/elements";
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
@@ -115,13 +115,8 @@
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: $background-color;
|
||||
}
|
||||
|
||||
.no-results {
|
||||
display: flex;
|
||||
padding-bottom: 2rem;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
@@ -155,9 +155,9 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "src/scss/elements";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
@import "scss/elements";
|
||||
|
||||
table {
|
||||
border-spacing: 0;
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { ref, defineProps, computed } from "vue";
|
||||
import TorrentSearchResults from "@/components/torrent/TorrentSearchResults.vue";
|
||||
import SeasonedButton from "@/components/ui/SeasonedButton.vue";
|
||||
import IconArrowDown from "@/icons/IconArrowDown.vue";
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.nav__hamburger {
|
||||
display: block;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "scss/variables";
|
||||
|
||||
.loader {
|
||||
display: flex;
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/loading-placeholder";
|
||||
@import "scss/loading-placeholder";
|
||||
</style>
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
|
||||
button {
|
||||
display: inline-block;
|
||||
@@ -42,7 +42,10 @@
|
||||
background: $background-color-secondary;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition: background 0.5s ease, color 0.5s ease, border-color 0.5s ease;
|
||||
transition:
|
||||
background 0.5s ease,
|
||||
color 0.5s ease,
|
||||
border-color 0.5s ease;
|
||||
|
||||
@include desktop {
|
||||
font-size: 0.8rem;
|
||||
|
||||
@@ -74,8 +74,8 @@
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.group {
|
||||
display: flex;
|
||||
|
||||
@@ -64,8 +64,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.fade-active {
|
||||
transition: opacity 0.4s;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "scss/variables";
|
||||
|
||||
$background: $background-ui;
|
||||
$background-selected: $background-color-secondary;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/*
|
||||
let setValue = function(el, binding) {
|
||||
let value = binding.value;
|
||||
let dateArray = value.split('-');
|
||||
@@ -13,3 +14,4 @@ module.exports = {
|
||||
setValue(el, binding);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
let setValue = function(el, binding) {
|
||||
let img = new Image();
|
||||
/*
|
||||
const setValue = function(el, binding) {
|
||||
const img = new Image();
|
||||
img.src = binding.value;
|
||||
|
||||
img.onload = function() {
|
||||
@@ -10,10 +11,11 @@ let setValue = function(el, binding) {
|
||||
|
||||
module.exports = {
|
||||
isLiteral: true,
|
||||
bind(el, binding){
|
||||
bind(el, binding) {
|
||||
setValue(el, binding);
|
||||
},
|
||||
update(el, binding){
|
||||
update(el, binding) {
|
||||
setValue(el, binding);
|
||||
}
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&subset=cyrillic"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<title>request.movie</title>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/favicons/apple-touch-icon.png"
|
||||
/>
|
||||
<link rel="icon" type="image/png" href="/favicons/favicon-32x32.png" />
|
||||
<link rel="manifest" href="/favicons/manifest.json" />
|
||||
<link
|
||||
rel="mask-icon"
|
||||
href="/favicons/safari-pinned-tab.svg"
|
||||
color="#01d277"
|
||||
/>
|
||||
<meta name="theme-color" content="#081c24" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="entry"></div>
|
||||
</body>
|
||||
|
||||
<script
|
||||
src="https://cdn.ravenjs.com/3.23.1/vue/raven.min.js"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
</html>
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { MediaTypes } from "./IList";
|
||||
|
||||
export interface IAutocompleteResult {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
|
||||
export enum GraphTypes {
|
||||
Plays = "plays",
|
||||
Duration = "duration"
|
||||
@@ -12,12 +10,12 @@ export enum GraphValueTypes {
|
||||
|
||||
export interface IGraphDataset {
|
||||
name: string;
|
||||
data: Array<number>;
|
||||
data: number[];
|
||||
}
|
||||
|
||||
export interface IGraphData {
|
||||
labels: Array<string>;
|
||||
series: Array<IGraphDataset>;
|
||||
labels: string[];
|
||||
series: IGraphDataset[];
|
||||
}
|
||||
|
||||
export interface IGraphResponse {
|
||||
|
||||
@@ -67,7 +67,7 @@ export interface IMovie {
|
||||
backdrop: string;
|
||||
release_date: string | Date;
|
||||
rating: number;
|
||||
genres: Array<MovieGenres>;
|
||||
genres: MovieGenres[];
|
||||
production_status: MovieProductionStatus;
|
||||
tagline: string;
|
||||
runtime: number;
|
||||
@@ -88,9 +88,9 @@ export interface IShow {
|
||||
seasons?: number;
|
||||
episodes?: number;
|
||||
popularity?: number;
|
||||
genres?: Array<ShowGenres>;
|
||||
genres?: ShowGenres[];
|
||||
production_status?: string;
|
||||
runtime?: Array<number>;
|
||||
runtime?: number[];
|
||||
exists_in_plex?: boolean;
|
||||
type: MediaTypes.Show;
|
||||
}
|
||||
@@ -135,19 +135,19 @@ export interface ICrew {
|
||||
}
|
||||
|
||||
export interface IMediaCredits {
|
||||
cast: Array<ICast>;
|
||||
crew: Array<ICrew>;
|
||||
cast: ICast[];
|
||||
crew: ICrew[];
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface IPersonCredits {
|
||||
cast: Array<IMovie | IShow>;
|
||||
crew: Array<ICrew>;
|
||||
cast: (IMovie | IShow)[];
|
||||
crew: ICrew[];
|
||||
id: number;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export type ListResults = Array<IMovie | IShow | IPerson | IRequest>;
|
||||
export type ListResults = (IMovie | IShow | IPerson | IRequest)[];
|
||||
|
||||
export interface IList {
|
||||
results: ListResults;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export default interface INavigationIcon {
|
||||
title: string;
|
||||
route: string;
|
||||
icon: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
icon: any;
|
||||
requiresAuth?: boolean;
|
||||
useStroke?: boolean;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type ITorrent from "./ITorrent";
|
||||
|
||||
export default interface IStateTorrent {
|
||||
results: Array<ITorrent>;
|
||||
results: ITorrent[];
|
||||
resultCount: number | null;
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@ export default interface ITorrent {
|
||||
seed: string;
|
||||
leech: string;
|
||||
url: string | null;
|
||||
release_type: Array<string>;
|
||||
release_type: string[];
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ import router from "./routes";
|
||||
import store from "./store";
|
||||
import Toast from "./plugins/Toast";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const App = require("./App.vue").default;
|
||||
import App from "./App.vue";
|
||||
|
||||
store.dispatch("darkmodeModule/findAndSetDarkmodeSupported");
|
||||
store.dispatch("user/initUserFromCookie");
|
||||
@@ -14,4 +13,5 @@ const app = createApp(App);
|
||||
app.use(router);
|
||||
app.use(store);
|
||||
app.use(Toast);
|
||||
app.mount("#entry");
|
||||
|
||||
app.mount("#app");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import IStateDarkmode from "../interfaces/IStateDarkmode";
|
||||
|
||||
const state: IStateDarkmode = {
|
||||
@@ -10,9 +11,7 @@ export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
getters: {
|
||||
darkmodeSupported: (state: IStateDarkmode) => {
|
||||
return state.darkmodeSupported;
|
||||
}
|
||||
darkmodeSupported: (state: IStateDarkmode) => state.darkmodeSupported
|
||||
},
|
||||
mutations: {
|
||||
SET_DARKMODE_SUPPORT: (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type IStateDocumentTitle from "../interfaces/IStateDocumentTitle";
|
||||
|
||||
const capitalize = (string: string) => {
|
||||
@@ -26,7 +27,7 @@ const state: IStateDocumentTitle = {
|
||||
title: undefined
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-shadow, no-return-assign */
|
||||
/* eslint-disable @typescript-eslint/no-shadow */
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type IStateHamburger from "../interfaces/IStateHamburger";
|
||||
|
||||
const state: IStateHamburger = {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { MediaTypes } from "../interfaces/IList";
|
||||
import type { IStatePopup, IPopupQuery } from "../interfaces/IStatePopup";
|
||||
|
||||
/* eslint-disable-next-line import/no-cycle */
|
||||
/* eslint-disable-next-line import-x/no-cycle */
|
||||
import router from "../routes";
|
||||
|
||||
const removeIncludedQueryParams = (params, key) => {
|
||||
const removeIncludedQueryParams = (params: URLSearchParams, key: string) => {
|
||||
if (params.has(key)) params.delete(key);
|
||||
return params;
|
||||
};
|
||||
|
||||
function paramsToObject(entries) {
|
||||
function paramsToObject(entries: Iterator<[string, string]>) {
|
||||
const result = {};
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const [key, value] of entries) {
|
||||
@@ -65,7 +66,7 @@ export default {
|
||||
actions: {
|
||||
open: ({ commit }, { id, type }: { id: number; type: MediaTypes }) => {
|
||||
if (!Number.isNaN(id)) {
|
||||
id = Number(id); /* eslint-disable-line no-param-reassign */
|
||||
id = Number(id);
|
||||
}
|
||||
|
||||
commit("SET_OPEN", { id, type });
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type ITorrent from "../interfaces/ITorrent";
|
||||
import type IStateTorrent from "../interfaces/IStateTorrent";
|
||||
|
||||
@@ -11,16 +12,12 @@ export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
getters: {
|
||||
results: (state: IStateTorrent) => {
|
||||
return state.results;
|
||||
},
|
||||
resultCount: (state: IStateTorrent) => {
|
||||
return state.resultCount;
|
||||
}
|
||||
results: (state: IStateTorrent) => state.results,
|
||||
resultCount: (state: IStateTorrent) => state.resultCount
|
||||
},
|
||||
|
||||
mutations: {
|
||||
SET_RESULTS: (state: IStateTorrent, results: Array<ITorrent>) => {
|
||||
SET_RESULTS: (state: IStateTorrent, results: ITorrent[]) => {
|
||||
state.results = results;
|
||||
},
|
||||
SET_RESULT_COUNT: (state: IStateTorrent, count: number) => {
|
||||
@@ -32,7 +29,7 @@ export default {
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setResults({ commit }, results: Array<ITorrent>) {
|
||||
setResults({ commit }, results: ITorrent[]) {
|
||||
commit("SET_RESULTS", results);
|
||||
},
|
||||
setResultCount({ commit }, count: number) {
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/variables.scss";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.button {
|
||||
font-size: 1.2rem;
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "scss/variables";
|
||||
|
||||
.wrapper {
|
||||
padding: 2rem;
|
||||
|
||||
@@ -118,8 +118,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.button--group {
|
||||
display: flex;
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "scss/variables";
|
||||
|
||||
section {
|
||||
padding: 1.3rem;
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.filter {
|
||||
margin-top: 0.5rem;
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.settings {
|
||||
padding: 3rem;
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "src/scss/variables";
|
||||
@import "scss/variables";
|
||||
|
||||
section {
|
||||
padding: 1.3rem;
|
||||
|
||||
@@ -94,7 +94,9 @@
|
||||
|
||||
background-color: white;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.17), 0 2px 4px 0 rgba(0, 0, 0, 0.08);
|
||||
box-shadow:
|
||||
0 4px 8px 0 rgba(0, 0, 0, 0.17),
|
||||
0 2px 4px 0 rgba(0, 0, 0, 0.08);
|
||||
padding: 0.5rem;
|
||||
margin: 1rem 2rem 1rem 0.71rem;
|
||||
// max-width: calc(100% - 3rem);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import type { RouteRecordRaw, RouteLocationNormalized } from "vue-router";
|
||||
|
||||
/* eslint-disable-next-line import/no-cycle */
|
||||
/* eslint-disable-next-line import-x/no-cycle */
|
||||
import store from "./store";
|
||||
|
||||
declare global {
|
||||
@@ -10,7 +10,7 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
name: "home",
|
||||
path: "/",
|
||||
@@ -99,7 +99,6 @@ const loggedIn = () => store.getters["user/loggedIn"];
|
||||
const hasPlexAccount = () => store.getters["user/plexUserId"] !== null;
|
||||
const hamburgerIsOpen = () => store.getters["hamburger/isOpen"];
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
router.beforeEach(
|
||||
(to: RouteLocationNormalized, from: RouteLocationNormalized, next: any) => {
|
||||
store.dispatch("documentTitle/updateTitle", to.name);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@import "src/scss/variables";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/variables";
|
||||
@import "scss/media-queries";
|
||||
|
||||
.filter {
|
||||
margin: 1rem;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "src/scss/variables";
|
||||
@import "scss/variables";
|
||||
|
||||
// Loading placeholder styling
|
||||
@mixin nth-children($points...) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "src/scss/variables";
|
||||
@import "scss/variables";
|
||||
|
||||
.noselect {
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
|
||||
@@ -8,72 +8,72 @@ $desktop-l-width: 1600px;
|
||||
$mobile-width: 768px;
|
||||
|
||||
@mixin desktop {
|
||||
@media (min-width: #{$mobile-width + 1px}) {
|
||||
@content;
|
||||
}
|
||||
@media (min-width: #{$mobile-width + 1px}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin mobile {
|
||||
@media (max-width: #{$mobile-width}) {
|
||||
@content;
|
||||
}
|
||||
@media (max-width: #{$mobile-width}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-only {
|
||||
@include mobile {
|
||||
display: none !important;
|
||||
}
|
||||
@include mobile {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-only {
|
||||
@include desktop {
|
||||
display: none !important;
|
||||
}
|
||||
@include desktop {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Media
|
||||
@mixin mobile-only {
|
||||
@media (max-width: #{$tablet-p-width - 1px}) {
|
||||
@content;
|
||||
}
|
||||
@media (max-width: #{$tablet-p-width - 1px}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@mixin mobile-ls-min {
|
||||
@media (min-width: #{$phone-xs-width}) {
|
||||
@content;
|
||||
}
|
||||
@media (min-width: #{$phone-xs-width}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@mixin tablet-only {
|
||||
@media (min-width: #{$tablet-p-width}) and (max-width: #{$desktop-width - 1px}) {
|
||||
@content;
|
||||
}
|
||||
@media (min-width: #{$tablet-p-width}) and (max-width: #{$desktop-width - 1px}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@mixin tablet-min {
|
||||
@media (min-width: #{$tablet-p-width}) {
|
||||
@content;
|
||||
}
|
||||
@media (min-width: #{$tablet-p-width}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@mixin tablet-portrait-only {
|
||||
@media (min-width: #{$tablet-p-width}) and (max-width: #{$tablet-l-width - 1px}) {
|
||||
@content;
|
||||
}
|
||||
@media (min-width: #{$tablet-p-width}) and (max-width: #{$tablet-l-width - 1px}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@mixin tablet-landscape-min {
|
||||
@media (min-width: #{$tablet-l-width}) {
|
||||
@content;
|
||||
}
|
||||
@media (min-width: #{$tablet-l-width}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@mixin desktop-min {
|
||||
@media (min-width: #{$desktop-width}) {
|
||||
@content;
|
||||
}
|
||||
@media (min-width: #{$desktop-width}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@mixin desktop-lg-min {
|
||||
@media (min-width: #{$desktop-l-width}) {
|
||||
@content;
|
||||
}
|
||||
@media (min-width: #{$desktop-l-width}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@mixin retina {
|
||||
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
|
||||
@content;
|
||||
}
|
||||
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Colors
|
||||
// @import "./media-queries";
|
||||
@import "src/scss/media-queries";
|
||||
@import "scss/media-queries";
|
||||
|
||||
:root {
|
||||
color-scheme: light;
|
||||
|
||||
@@ -6,7 +6,7 @@ import torrentModule from "./modules/torrentModule";
|
||||
import user from "./modules/user";
|
||||
import hamburger from "./modules/hamburger";
|
||||
|
||||
/* eslint-disable-next-line import/no-cycle */
|
||||
/* eslint-disable-next-line import-x/no-cycle */
|
||||
import popup from "./modules/popup";
|
||||
|
||||
const store = createStore({
|
||||
|
||||
12
src/utils.ts
12
src/utils.ts
@@ -14,9 +14,7 @@ export const parseJwt = (token: string) => {
|
||||
const jsonPayload = decodeURIComponent(
|
||||
atob(base64)
|
||||
.split("")
|
||||
.map(c => {
|
||||
return `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`;
|
||||
})
|
||||
.map(c => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`)
|
||||
.join("")
|
||||
);
|
||||
|
||||
@@ -62,10 +60,10 @@ export function focusOnNextElement(elementEvent: KeyboardEvent): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function humanMinutes(minutes) {
|
||||
export function humanMinutes(minutes: number[] | number) {
|
||||
if (minutes instanceof Array) {
|
||||
/* eslint-disable-next-line prefer-destructuring, no-param-reassign */
|
||||
minutes = minutes[0];
|
||||
/* eslint-disable-next-line no-param-reassign */
|
||||
[minutes] = minutes;
|
||||
}
|
||||
|
||||
const hours = Math.floor(minutes / 60);
|
||||
@@ -93,7 +91,7 @@ export function setUrlQueryParameter(parameter: string, value: string): void {
|
||||
|
||||
const url = `${window.location.protocol}//${window.location.hostname}${
|
||||
window.location.port ? `:${window.location.port}` : ""
|
||||
}${window.location.pathname}${params.toString().length ? `?${params}` : ""}`;
|
||||
}${ndow.location.pathname}${params.toString().length ? `?${params}` : ""}`;
|
||||
|
||||
window.history.pushState({}, "search", url);
|
||||
}
|
||||
|
||||
9
src/vite-env.d.ts
vendored
Normal file
9
src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_SEASONED_API: string;
|
||||
readonly VITE_ELASTIC_URL: string;
|
||||
readonly VITE_ELASTIC_API_KEY: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
Reference in New Issue
Block a user