Merge pull request #54 from @DanikVitek
feat(frontend): Update to Svelte 5; Code cleanup
This commit is contained in:
@@ -6,6 +6,7 @@ venv
|
|||||||
data
|
data
|
||||||
*ipynb
|
*ipynb
|
||||||
build
|
build
|
||||||
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
.venv
|
.venv
|
||||||
.env
|
.env
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Ignore artifacts:
|
||||||
|
build
|
||||||
|
coverage
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "all",
|
||||||
|
"endOfLine": "lf",
|
||||||
|
"semi": true,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"htmlWhitespaceSensitivity": "strict",
|
||||||
|
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.svelte",
|
||||||
|
"options": {
|
||||||
|
"parser": "svelte"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tailwindStylesheet": "./src/app.css",
|
||||||
|
"tailwindConfig": "./tailwind.config.js"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "./.svelte-kit/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"checkJs": true
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "**/node_modules/*"]
|
||||||
|
}
|
||||||
Generated
+1192
-873
File diff suppressed because it is too large
Load Diff
@@ -4,26 +4,28 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview",
|
||||||
|
"format": "prettier . --write"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fontsource/fira-mono": "^4.5.10",
|
"@fontsource/fira-mono": "^4.5.10",
|
||||||
"@neoconfetti/svelte": "^1.0.0",
|
"@neoconfetti/svelte": "^1.0.0",
|
||||||
"@sveltejs/adapter-auto": "^3.0.0",
|
"@sveltejs/adapter-auto": "^3.0.0",
|
||||||
"@sveltejs/adapter-static": "^3.0.1",
|
"@sveltejs/adapter-static": "^3.0.1",
|
||||||
"@sveltejs/kit": "^2.0.0",
|
"@sveltejs/kit": "^2.20.7",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
"@tailwindcss/typography": "^0.5.10",
|
"@tailwindcss/typography": "^0.5.10",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"daisyui": "^4.4.20",
|
"daisyui": "^4.4.20",
|
||||||
"postcss": "^8.4.32",
|
"postcss": "^8.4.32",
|
||||||
"postcss-load-config": "^5.0.2",
|
"postcss-load-config": "^5.0.2",
|
||||||
"svelte": "^4.2.7",
|
"prettier": "^3.5.3",
|
||||||
|
"prettier-plugin-svelte": "^3.3.3",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
|
"svelte": "^5.28.2",
|
||||||
|
"svelte-preprocess": "^6.0.3",
|
||||||
"tailwindcss": "^3.3.6",
|
"tailwindcss": "^3.3.6",
|
||||||
"vite": "^5.0.3"
|
"vite": "^6.3.3"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module"
|
||||||
"dependencies": {
|
|
||||||
"svelte-preprocess": "^5.1.3"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
const tailwindcss = require("tailwindcss");
|
import tailwindcss from "tailwindcss";
|
||||||
const autoprefixer = require("autoprefixer");
|
import autoprefixer from "autoprefixer";
|
||||||
|
|
||||||
const config = {
|
/** @type {import('postcss-load-config').Config} */
|
||||||
|
export default {
|
||||||
plugins: [
|
plugins: [
|
||||||
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
|
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
|
||||||
tailwindcss(),
|
tailwindcss,
|
||||||
//But others, like autoprefixer, need to run after,
|
//But others, like autoprefixer, need to run after,
|
||||||
autoprefixer,
|
autoprefixer,
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
+35
-26
@@ -1,33 +1,42 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en" data-theme="nord">
|
<html lang="en" data-theme="bumblebee">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%sveltekit.assets%/favicon.svg" />
|
<link rel="icon" href="%sveltekit.assets%/favicon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
<title>Wattpad Downloader</title>
|
<title>Wattpad Downloader</title>
|
||||||
<meta name="title" content="Wattpad Downloader" />
|
<meta name="title" content="Wattpad Downloader" />
|
||||||
<meta name="description" content="Read your way, download Wattpad Books as PDFs or EPUBs in seconds. Have an Ad-Free experience with Unlimited Offline Reading. Try it now!" />
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Read your way, download Wattpad Books as PDFs or EPUBs in seconds. Have an Ad-Free experience with Unlimited Offline Reading. Try it now!"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Open Graph / Facebook -->
|
<!-- Open Graph / Facebook -->
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:url" content="https://wpd.rambhat.la/" />
|
<meta property="og:url" content="https://wpd.rambhat.la/" />
|
||||||
<meta property="og:title" content="Wattpad Downloader" />
|
<meta property="og:title" content="Wattpad Downloader" />
|
||||||
<meta property="og:description" content="Read your way, download Wattpad Books as PDFs or EPUBs in seconds. Have an Ad-Free experience with Unlimited Offline Reading. Try it now!" />
|
<meta
|
||||||
<meta property="og:image" content="https://wpd.rambhat.la/embed.png" />
|
property="og:description"
|
||||||
|
content="Read your way, download Wattpad Books as PDFs or EPUBs in seconds. Have an Ad-Free experience with Unlimited Offline Reading. Try it now!"
|
||||||
|
/>
|
||||||
|
<meta property="og:image" content="https://wpd.rambhat.la/embed.png" />
|
||||||
|
|
||||||
<!-- Twitter -->
|
<!-- Twitter -->
|
||||||
<meta property="twitter:card" content="summary_large_image" />
|
<meta property="twitter:card" content="summary_large_image" />
|
||||||
<meta property="twitter:url" content="https://wpd.rambhat.la/" />
|
<meta property="twitter:url" content="https://wpd.rambhat.la/" />
|
||||||
<meta property="twitter:title" content="Wattpad Downloader" />
|
<meta property="twitter:title" content="Wattpad Downloader" />
|
||||||
<meta property="twitter:description" content="Read your way, download Wattpad Books as PDFs or EPUBs in seconds. Have an Ad-Free experience with Unlimited Offline Reading. Try it now!" />
|
<meta
|
||||||
<meta property="twitter:image" content="https://wpd.rambhat.la/embed.png" />
|
property="twitter:description"
|
||||||
|
content="Read your way, download Wattpad Books as PDFs or EPUBs in seconds. Have an Ad-Free experience with Unlimited Offline Reading. Try it now!"
|
||||||
|
/>
|
||||||
|
<meta property="twitter:image" content="https://wpd.rambhat.la/embed.png" />
|
||||||
|
|
||||||
<!-- Meta Tags Generated with https://metatags.io -->
|
<!-- Meta Tags Generated with https://metatags.io -->
|
||||||
|
|
||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body data-sveltekit-preload-data="hover">
|
<body data-sveltekit-preload-data="hover">
|
||||||
<div style="display: contents">%sveltekit.body%</div>
|
<div style="display: contents">%sveltekit.body%</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="hero min-h-screen">
|
<div class="hero min-h-screen">
|
||||||
<div class="hero-content text-center">
|
<div class="hero-content text-center">
|
||||||
<div class="bg-base-200 p-16 max-w-lg rounded-md">
|
<div class="max-w-lg rounded-md bg-base-200 p-16">
|
||||||
<h1 class="text-5xl font-bold">There was an error.</h1>
|
<h1 class="text-5xl font-bold">There was an error.</h1>
|
||||||
<div class="py-6 join">
|
<div class="join py-6">
|
||||||
<a class="btn btn-primary btn-lg" href="/">Home</a>
|
<a class="btn btn-primary btn-lg" href="/">Home</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer
|
<footer
|
||||||
class="footer footer-center p-4 bg-base-300 text-base-content bottom-0 fixed"
|
class="footer footer-center fixed bottom-0 bg-base-300 p-4 text-base-content"
|
||||||
>
|
>
|
||||||
<aside class="text-2xl">
|
<aside class="text-2xl">
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import "../app.pcss";
|
import "../app.css";
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Props
|
||||||
|
* @property {import('svelte').Snippet} [children]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @type {Props} */
|
||||||
|
let { children } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@@ -10,13 +17,13 @@
|
|||||||
</style>
|
</style>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<slot />
|
{@render children?.()}
|
||||||
|
|
||||||
<footer
|
<footer
|
||||||
class="footer footer-center p-4 bg-base-300 text-base-content bottom-0 fixed"
|
class="footer footer-center fixed bottom-0 bg-base-300 p-4 text-base-content"
|
||||||
>
|
>
|
||||||
<aside>
|
<aside>
|
||||||
<div class="flex flex-row max-w-lg w-full">
|
<div class="flex w-full max-w-lg flex-row">
|
||||||
<a
|
<a
|
||||||
href="/donate"
|
href="/donate"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|||||||
@@ -1,103 +1,118 @@
|
|||||||
<script>
|
<script>
|
||||||
let download_images = false;
|
let downloadImages = $state(false);
|
||||||
let download_as_pdf = false; // 0 = epub, 1 = pdf
|
let downloadAsPdf = $state(false); // 0 = epub, 1 = pdf
|
||||||
let is_paid_story = false;
|
let isPaidStory = $state(false);
|
||||||
let invalid_url = false;
|
let invalidUrl = $state(false);
|
||||||
let after_download_page = false;
|
let afterDownloadPage = $state(false);
|
||||||
let credentials = {
|
let credentials = $state({
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
};
|
});
|
||||||
let download_id = "";
|
let downloadId = $state("");
|
||||||
let mode = "";
|
/** @type {"story" | "part" | ""} */
|
||||||
let input_url = "";
|
let mode = $state("");
|
||||||
|
let inputUrl = $state("");
|
||||||
|
|
||||||
let button_disabled = false;
|
let buttonDisabled = $derived(
|
||||||
$: button_disabled =
|
!inputUrl ||
|
||||||
!input_url ||
|
(isPaidStory && !(credentials.username && credentials.password)),
|
||||||
(is_paid_story && !(credentials.username && credentials.password));
|
);
|
||||||
|
|
||||||
$: url =
|
let url = $derived(
|
||||||
`/download/` +
|
`/download/` +
|
||||||
download_id +
|
downloadId +
|
||||||
`?om=1` +
|
`?om=1` +
|
||||||
(download_images ? "&download_images=true" : "") +
|
(downloadImages ? "&download_images=true" : "") +
|
||||||
(is_paid_story
|
(isPaidStory
|
||||||
? `&username=${encodeURIComponent(credentials.username)}&password=${encodeURIComponent(credentials.password)}`
|
? `&username=${encodeURIComponent(credentials.username)}&password=${encodeURIComponent(credentials.password)}`
|
||||||
: "") +
|
: "") +
|
||||||
`&mode=${mode}` +
|
`&mode=${mode}` +
|
||||||
(download_as_pdf ? "&format=pdf" : "&format=epub");
|
(downloadAsPdf ? "&format=pdf" : "&format=epub"),
|
||||||
|
);
|
||||||
|
|
||||||
$: {
|
/** @type {HTMLDialogElement} */
|
||||||
if (input_url.length) {
|
let storyURLTutorialModal;
|
||||||
input_url = input_url.toLowerCase();
|
|
||||||
|
|
||||||
invalid_url = false;
|
/** @param {string} input */
|
||||||
|
const setInputAsValid = (input) => {
|
||||||
|
invalidUrl = false;
|
||||||
|
inputUrl = input;
|
||||||
|
downloadId = input;
|
||||||
|
};
|
||||||
|
|
||||||
if (/^\d+$/.test(input_url)) {
|
/** @param {string} input */
|
||||||
// All numbers
|
const setInputAsInvalid = (input) => {
|
||||||
download_id = input_url;
|
invalidUrl = true;
|
||||||
mode = "story";
|
inputUrl = input;
|
||||||
} else if (input_url.includes("wattpad.com/")) {
|
downloadId = input;
|
||||||
// Is a string and contains contain wattpad.com/
|
};
|
||||||
|
|
||||||
if (input_url.includes("/story/")) {
|
/** @param {string} input */
|
||||||
// https://wattpad.com/story/237369078-wattpad-books-presents
|
const setInputUrl = (input) => {
|
||||||
input_url = input_url.split("-")[0].split("?")[0].split("/story/")[1]; // removes tracking fields and title
|
input = input.toLowerCase();
|
||||||
download_id = input_url;
|
|
||||||
mode = "story";
|
|
||||||
} else if (input_url.includes("/stories/")) {
|
|
||||||
// https://www.wattpad.com/api/v3/stories/237369078?fields=...
|
|
||||||
input_url = input_url.split("?")[0].split("/stories/")[1]; // removes params
|
|
||||||
download_id = input_url;
|
|
||||||
mode = "story";
|
|
||||||
} else {
|
|
||||||
// https://www.wattpad.com/939051741-wattpad-books-presents-the-qb-bad-boy-and-me
|
|
||||||
input_url = input_url
|
|
||||||
.split("-")[0]
|
|
||||||
.split("?")[0]
|
|
||||||
.split("wattpad.com/")[1]; // removes tracking fields and title
|
|
||||||
download_id = input_url;
|
|
||||||
if (/^\d+$/.test(download_id)) {
|
|
||||||
// If "wattpad.com/{download_id}" contains only numbers
|
|
||||||
mode = "part";
|
|
||||||
} else {
|
|
||||||
invalid_url = true;
|
|
||||||
input_url = "";
|
|
||||||
download_id = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
invalid_url = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
input_url = input_url.match(/\d+/g)?.join("") || "";
|
if (!input) {
|
||||||
download_id = input_url;
|
setInputAsValid("");
|
||||||
|
return;
|
||||||
// Originally, I was going to call the Wattpad API (wattpad.com/api/v3/stories/${story_id}), but Wattpad kept blocking those requests. I suspect it has something to do with the Origin header, I wasn't able to remove it.
|
|
||||||
// In the future, if this is considered, it would be cool if we could derive the Story ID from a pasted Part URL. Refer to @AaronBenDaniel's https://github.com/AaronBenDaniel/WattpadDownloader/blob/49b29b245188149f2d24c0b1c59e4c7f90f289a9/src/api/src/create_book.py#L156 (https://www.wattpad.com/api/v3/story_parts/{part_id}?fields=url).
|
|
||||||
} else {
|
|
||||||
invalid_url = false;
|
|
||||||
download_id = "";
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (/^\d+$/.test(input)) {
|
||||||
|
// All numbers
|
||||||
|
mode = "story";
|
||||||
|
setInputAsValid(input);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input.includes("wattpad.com/")) {
|
||||||
|
setInputAsInvalid(input.match(/\d+/g)?.join("") ?? "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is a string and contains wattpad.com/
|
||||||
|
|
||||||
|
if (input.includes("/story/")) {
|
||||||
|
// https://wattpad.com/story/237369078-wattpad-books-presents
|
||||||
|
mode = "story";
|
||||||
|
setInputAsValid(
|
||||||
|
input.split("-", 1)[0].split("?", 1)[0].split("/story/")[1], // removes tracking fields and title
|
||||||
|
);
|
||||||
|
} else if (input.includes("/stories/")) {
|
||||||
|
// https://www.wattpad.com/api/v3/stories/237369078?fields=...
|
||||||
|
mode = "story";
|
||||||
|
setInputAsValid(
|
||||||
|
input.split("?", 1)[0].split("/stories/")[1], // removes params
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// https://www.wattpad.com/939051741-wattpad-books-presents-the-qb-bad-boy-and-me
|
||||||
|
input = input.split("-", 1)[0].split("?", 1)[0].split("wattpad.com/")[1]; // removes tracking fields and title
|
||||||
|
if (/^\d+$/.test(input)) {
|
||||||
|
// If "wattpad.com/{downloadId}" contains only numbers
|
||||||
|
mode = "part";
|
||||||
|
setInputAsValid(input);
|
||||||
|
} else {
|
||||||
|
setInputAsInvalid("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Originally, I was going to call the Wattpad API (wattpad.com/api/v3/stories/${story_id}), but Wattpad kept blocking those requests. I suspect it has something to do with the Origin header, I wasn't able to remove it.
|
||||||
|
// In the future, if this is considered, it would be cool if we could derive the Story ID from a pasted Part URL. Refer to @AaronBenDaniel's https://github.com/AaronBenDaniel/WattpadDownloader/blob/49b29b245188149f2d24c0b1c59e4c7f90f289a9/src/api/src/create_book.py#L156 (https://www.wattpad.com/api/v3/story_parts/{part_id}?fields=url).
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="hero min-h-screen">
|
<div class="hero min-h-screen">
|
||||||
<div
|
<div
|
||||||
class="hero-content flex-col lg:flex-row-reverse bg-base-100/50 lg:p-16 py-32 rounded shadow-sm"
|
class="hero-content flex-col rounded bg-base-100/50 py-32 shadow-sm lg:flex-row-reverse lg:p-16"
|
||||||
>
|
>
|
||||||
{#if !after_download_page}
|
{#if !afterDownloadPage}
|
||||||
<div class="text-center lg:text-left lg:p-10">
|
<div class="text-center lg:p-10 lg:text-left">
|
||||||
<h1
|
<h1
|
||||||
class="font-extrabold text-transparent text-5xl bg-clip-text bg-gradient-to-r to-pink-600 via-yellow-600 from-red-700"
|
class="bg-gradient-to-r from-red-700 via-yellow-600 to-pink-600 bg-clip-text text-5xl font-extrabold text-transparent"
|
||||||
|
>Wattpad Downloader</h1
|
||||||
>
|
>
|
||||||
Wattpad Downloader
|
|
||||||
</h1>
|
|
||||||
<div
|
<div
|
||||||
role="alert"
|
role="alert"
|
||||||
class="alert bg-green-200 mt-10 break-words max-w-md"
|
class="alert mt-10 max-w-md break-words bg-green-200"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -137,11 +152,11 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<span class="text-lg">Please Donate</span>
|
<span class="text-lg">Please Donate</span>
|
||||||
</div> -->
|
</div> -->
|
||||||
<p class="pt-6 text-lg max-w-md">
|
<p class="max-w-md pt-6 text-lg"
|
||||||
Download your favourite books with a single click. Have a great new
|
>Download your favourite books with a single click. Have a great new
|
||||||
year!
|
year!</p
|
||||||
</p>
|
>
|
||||||
<ul class="pt-4 list list-inside text-xl">
|
<ul class="list list-inside pt-4 text-xl">
|
||||||
<!-- TODO: 'max-lg: hidden' to hide on screen sizes smaller than lg. I'll do this when I figure out how to make this show up _below_ the card on smaller screen sizes. -->
|
<!-- TODO: 'max-lg: hidden' to hide on screen sizes smaller than lg. I'll do this when I figure out how to make this show up _below_ the card on smaller screen sizes. -->
|
||||||
<!-- <li>12/24 - ⚡ Super-fast Downloads!</li>
|
<!-- <li>12/24 - ⚡ Super-fast Downloads!</li>
|
||||||
<li>12/24 - 📑 PDF Downloads!</li> -->
|
<li>12/24 - 📑 PDF Downloads!</li> -->
|
||||||
@@ -162,49 +177,49 @@
|
|||||||
<li>06/24 - 🖼️ Image Downloading!</li>
|
<li>06/24 - 🖼️ Image Downloading!</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="card shrink-0 w-full max-w-sm shadow-2xl bg-base-100">
|
<div class="card w-full max-w-sm shrink-0 bg-base-100 shadow-2xl">
|
||||||
<form class="card-body">
|
<form class="card-body">
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Story URL"
|
placeholder="Story URL"
|
||||||
class="input input-bordered"
|
class="input input-bordered"
|
||||||
class:input-warning={invalid_url}
|
class:input-warning={invalidUrl}
|
||||||
bind:value={input_url}
|
bind:value={() => inputUrl, setInputUrl}
|
||||||
required
|
required
|
||||||
name="input_url"
|
name="input_url"
|
||||||
/>
|
/>
|
||||||
<label class="label" for="input_url">
|
<label class="label" for="input_url">
|
||||||
{#if invalid_url}
|
{#if invalidUrl}
|
||||||
<p class=" text-red-500">
|
<p class=" text-red-500">
|
||||||
Refer to (<button
|
Refer to (<button
|
||||||
class="link font-semibold"
|
class="link font-semibold"
|
||||||
onclick="StoryURLTutorialModal.showModal()"
|
onclick={() => storyURLTutorialModal.showModal()}
|
||||||
data-umami-event="Part StoryURLTutorialModal Open"
|
data-umami-event="Part StoryURLTutorialModal Open"
|
||||||
>How to get a Story URL</button
|
>How to get a Story URL</button
|
||||||
>).
|
>).
|
||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
<button
|
<button
|
||||||
class="label-text link font-semibold"
|
class="link label-text font-semibold"
|
||||||
onclick="StoryURLTutorialModal.showModal()"
|
onclick={() => storyURLTutorialModal.showModal()}
|
||||||
data-umami-event="StoryURLTutorialModal Open"
|
data-umami-event="StoryURLTutorialModal Open"
|
||||||
>How to get a Story URL</button
|
>How to get a Story URL</button
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="cursor-pointer label">
|
<label class="label cursor-pointer">
|
||||||
<span class="label-text"
|
<span class="label-text"
|
||||||
>This is a Paid Story, and I've purchased it</span
|
>This is a Paid Story, and I've purchased it</span
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="checkbox checkbox-warning shadow-md"
|
class="checkbox-warning checkbox shadow-md"
|
||||||
bind:checked={is_paid_story}
|
bind:checked={isPaidStory}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{#if is_paid_story}
|
{#if isPaidStory}
|
||||||
<label class="input input-bordered flex items-center gap-2">
|
<label class="input input-bordered flex items-center gap-2">
|
||||||
Username
|
Username
|
||||||
<input
|
<input
|
||||||
@@ -233,16 +248,16 @@
|
|||||||
<div class="form-control mt-6">
|
<div class="form-control mt-6">
|
||||||
<a
|
<a
|
||||||
class="btn rounded-l-none"
|
class="btn rounded-l-none"
|
||||||
class:btn-primary={!download_as_pdf}
|
class:btn-primary={!downloadAsPdf}
|
||||||
class:btn-secondary={download_as_pdf}
|
class:btn-secondary={downloadAsPdf}
|
||||||
class:btn-disabled={button_disabled}
|
class:btn-disabled={buttonDisabled}
|
||||||
data-umami-event="Download"
|
data-umami-event="Download"
|
||||||
href={url}
|
href={url}
|
||||||
on:click={() => (after_download_page = true)}>Download</a
|
onclick={() => (afterDownloadPage = true)}>Download</a
|
||||||
>
|
>
|
||||||
|
|
||||||
<!-- <label class="swap w-fit label mt-2">
|
<!-- <label class="swap w-fit label mt-2">
|
||||||
<input type="checkbox" bind:checked={download_as_pdf} />
|
<input type="checkbox" bind:checked={downloadAsPdf} />
|
||||||
<div class="swap-on">
|
<div class="swap-on">
|
||||||
Downloading as <span class=" underline text-bold">PDF</span> (Click)
|
Downloading as <span class=" underline text-bold">PDF</span> (Click)
|
||||||
</div>
|
</div>
|
||||||
@@ -251,28 +266,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</label> -->
|
</label> -->
|
||||||
|
|
||||||
<label class="cursor-pointer label">
|
<label class="label cursor-pointer">
|
||||||
<span class="label-text"
|
<span class="label-text"
|
||||||
>Include Images (<strong>Slower Download</strong>)</span
|
>Include Images (<strong>Slower Download</strong>)</span
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="checkbox checkbox-warning shadow-md"
|
class="checkbox-warning checkbox shadow-md"
|
||||||
bind:checked={download_images}
|
bind:checked={downloadImages}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="text-center max-w-4xl">
|
<div class="max-w-4xl text-center">
|
||||||
<h1 class="font-bold text-3xl">
|
<h1 class="text-3xl font-bold">
|
||||||
Your download has <span
|
Your download has <span
|
||||||
class="text-transparent bg-clip-text bg-gradient-to-r to-pink-600 via-yellow-600 from-red-700"
|
class="bg-gradient-to-r from-red-700 via-yellow-600 to-pink-600 bg-clip-text text-transparent"
|
||||||
>Started</span
|
>Started</span
|
||||||
>
|
>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="py-4 space-y-2">
|
<div class="space-y-2 py-4">
|
||||||
<p class="text-2xl">
|
<p class="text-2xl">
|
||||||
If you found this site useful, please consider <a
|
If you found this site useful, please consider <a
|
||||||
href="https://github.com/TheOnlyWayUp/WattpadDownloader"
|
href="https://github.com/TheOnlyWayUp/WattpadDownloader"
|
||||||
@@ -281,7 +296,7 @@
|
|||||||
data-umami-event="Star">starring the project</a
|
data-umami-event="Star">starring the project</a
|
||||||
> to support WattpadDownloader.
|
> to support WattpadDownloader.
|
||||||
</p>
|
</p>
|
||||||
<p class="text-lg pt-2">
|
<p class="pt-2 text-lg">
|
||||||
You can also join us on <a
|
You can also join us on <a
|
||||||
href="https://discord.gg/P9RHC4KCwd"
|
href="https://discord.gg/P9RHC4KCwd"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -290,17 +305,17 @@
|
|||||||
>, where we release features early and discuss updates.
|
>, where we release features early and discuss updates.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid justify-center grid-rows-2 gap-y-10">
|
<div class="grid grid-rows-2 justify-center gap-y-10">
|
||||||
<a
|
<a
|
||||||
href="/donate"
|
href="/donate"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="btn bg-cyan-200 btn-lg mt-10 hover:bg-green-200"
|
class="btn btn-lg mt-10 bg-cyan-200 hover:bg-green-200"
|
||||||
>Buy me a Coffee! 🍵</a
|
>Buy me a Coffee! 🍵</a
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
after_download_page = false;
|
afterDownloadPage = false;
|
||||||
input_url = "";
|
inputUrl = "";
|
||||||
}}
|
}}
|
||||||
class="btn btn-outline btn-lg">Download More</button
|
class="btn btn-outline btn-lg">Download More</button
|
||||||
>
|
>
|
||||||
@@ -311,29 +326,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Open the modal using ID.showModal() method -->
|
<dialog class="modal" bind:this={storyURLTutorialModal}>
|
||||||
|
|
||||||
<dialog id="StoryURLTutorialModal" class="modal">
|
|
||||||
<div class="modal-box">
|
<div class="modal-box">
|
||||||
<form method="dialog">
|
<form method="dialog">
|
||||||
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
|
<button class="btn btn-circle btn-ghost btn-sm absolute right-2 top-2"
|
||||||
>✕</button
|
>✕</button
|
||||||
>
|
>
|
||||||
</form>
|
</form>
|
||||||
<h3 class="font-bold text-lg">Finding the Story URL</h3>
|
<h3 class="text-lg font-bold">Finding the Story URL</h3>
|
||||||
<ol class="list list-disc list-inside py-4 space-y-4">
|
<ol class="list list-inside list-disc space-y-4 py-4">
|
||||||
<li>
|
<li>
|
||||||
Copy the URL from the Website, or hit share and copy the URL on the App.
|
Copy the URL from the Website, or hit share and copy the URL on the App.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
For example,
|
For example,
|
||||||
<span class="font-mono bg-slate-100 p-1"
|
<span class="bg-slate-100 p-1 font-mono"
|
||||||
>wattpad.com/<span class="bg-amber-200 rounded-sm">story</span
|
>wattpad.com/<span class="rounded-sm bg-amber-200">story</span
|
||||||
>/237369078-wattpad-books-presents</span
|
>/237369078-wattpad-books-presents</span
|
||||||
>.
|
>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="font-mono bg-slate-100 p-1"
|
<span class="bg-slate-100 p-1 font-mono"
|
||||||
>https://www.wattpad.com/939103774-given</span
|
>https://www.wattpad.com/939103774-given</span
|
||||||
> is okay too.
|
> is okay too.
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
|
|||||||
import adapter from "@sveltejs/adapter-static";
|
import adapter from "@sveltejs/adapter-static";
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
const config = {
|
export default {
|
||||||
kit: {
|
kit: {
|
||||||
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||||
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
||||||
@@ -11,6 +11,7 @@ const config = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
preprocess: [vitePreprocess({})],
|
preprocess: [vitePreprocess({})],
|
||||||
|
vitePlugin: {
|
||||||
|
inspector: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
const daisyui = require("daisyui");
|
|
||||||
const typography = require("@tailwindcss/typography");
|
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config}*/
|
|
||||||
const config = {
|
|
||||||
content: ["./src/**/*.{html,js,svelte,ts}"],
|
|
||||||
|
|
||||||
theme: {
|
|
||||||
extend: {},
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [typography, daisyui],
|
|
||||||
|
|
||||||
daisyui: {
|
|
||||||
themes: [
|
|
||||||
"bumblebee"
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import daisyui from "daisyui";
|
||||||
|
import typography from "@tailwindcss/typography";
|
||||||
|
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||||
|
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [typography, daisyui],
|
||||||
|
|
||||||
|
daisyui: {
|
||||||
|
themes: ["bumblebee"],
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from "@sveltejs/kit/vite";
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit()]
|
plugins: [sveltekit()],
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user