initial commit
@ -0,0 +1 @@
|
||||
config.ts
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"deno.enable": true,
|
||||
"deno.unstable": true,
|
||||
"deno.importMap": "./import_map.json",
|
||||
"editor.formatOnSave": true
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
Copyright 2023 Ruthenic
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -0,0 +1,14 @@
|
||||
# Voltpad
|
||||
simplistic wattpad frontend (ala invidious or nitter) written in Deno
|
||||
|
||||
### Why?
|
||||
Imho the Wattpad website is insufferable to use. The layout feels broken half the time, stories only take up the middle third of the screen (along with the rest of the site), fragmented and weird search page(s), inability to directly search by tag, the dumbass algorithm (especially on the homepage) which has never actually recommended me a story I'd like, on and on ad infinitum
|
||||
|
||||
### Setup
|
||||
1. Install Deno
|
||||
2. Copy `config.template.ts` to `config.ts`, and fill out/change the information as you see fit
|
||||
3. Run the index.tsx file `deno -A index.tsx`
|
||||
4. Congrats, you are now running Voltpad
|
||||
|
||||
### Contributing
|
||||
You probably shouldn't because the code is jank, but I mean you can
|
@ -0,0 +1,19 @@
|
||||
import sass from "https://deno.land/x/denosass@1.0.6/mod.ts";
|
||||
import { Props } from "../types.d.ts";
|
||||
import { h } from "../jsx.ts";
|
||||
|
||||
interface BaseHeaderProps extends Props {
|
||||
id?: string;
|
||||
entries: {
|
||||
name: string;
|
||||
href: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export default (props: BaseHeaderProps) => (
|
||||
<header id={props.id} class="header">
|
||||
{props.entries
|
||||
.map((entry) => <a href={entry.href}>{entry.name}</a>)
|
||||
.join("")}
|
||||
</header>
|
||||
);
|
@ -0,0 +1,22 @@
|
||||
interface Config {
|
||||
serve: {
|
||||
address: string;
|
||||
port: number;
|
||||
};
|
||||
user?: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
serve: {
|
||||
address: "localhost",
|
||||
port: 8080,
|
||||
},
|
||||
// note that you can remove the user object and it will work; stories marked as mature will be inaccessible, however.
|
||||
user: {
|
||||
username: "USERNAME_OR_EMAIL",
|
||||
password: "PASSWORD",
|
||||
},
|
||||
} as Config;
|
@ -0,0 +1,107 @@
|
||||
html {
|
||||
background-color:beige;
|
||||
font-family: "IBM Plex Sans", system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
&:link,
|
||||
&:visited,
|
||||
&:hover {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 75%;
|
||||
}
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
/* a bit of jank */
|
||||
input {
|
||||
border-radius: 0.25em;
|
||||
}
|
||||
label {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.stories {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
a {
|
||||
color: black;
|
||||
border: none;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
|
||||
&:link,
|
||||
&:visited,
|
||||
&:hover {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.story {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
margin-top: 1em;
|
||||
min-width: 75%;
|
||||
max-width: 75%;
|
||||
}
|
||||
|
||||
.pagenav {
|
||||
margin-top: 1em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.header {
|
||||
position: sticky;
|
||||
top: 0.5em;
|
||||
background-color: darkgrey;
|
||||
width: 100%;
|
||||
min-height: 2em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&#storyHeader {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
border-radius: 0.5em;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color:#0f0f0f;
|
||||
a {
|
||||
&:first-child {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
&:link,
|
||||
&:visited,
|
||||
&:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
text-align: center;
|
||||
margin-right: 0.5em;
|
||||
width:fit-content;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"fmt": {
|
||||
"options": {
|
||||
"indentWidth": 4
|
||||
}
|
||||
},
|
||||
"compilerOptions": {
|
||||
"jsxFactory": "h",
|
||||
"jsxFragmentFactory": "Fragment",
|
||||
"lib": ["dom", "deno.window"]
|
||||
}
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
{
|
||||
"version": "2",
|
||||
"remote": {
|
||||
"https://deno.land/std@0.131.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74",
|
||||
"https://deno.land/std@0.131.0/_util/os.ts": "49b92edea1e82ba295ec946de8ffd956ed123e2948d9bd1d3e901b04e4307617",
|
||||
"https://deno.land/std@0.131.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3",
|
||||
"https://deno.land/std@0.131.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09",
|
||||
"https://deno.land/std@0.131.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b",
|
||||
"https://deno.land/std@0.131.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633",
|
||||
"https://deno.land/std@0.131.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee",
|
||||
"https://deno.land/std@0.131.0/path/mod.ts": "4275129bb766f0e475ecc5246aa35689eeade419d72a48355203f31802640be7",
|
||||
"https://deno.land/std@0.131.0/path/posix.ts": "663e4a6fe30a145f56aa41a22d95114c4c5582d8b57d2d7c9ed27ad2c47636bb",
|
||||
"https://deno.land/std@0.131.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9",
|
||||
"https://deno.land/std@0.131.0/path/win32.ts": "e7bdf63e8d9982b4d8a01ef5689425c93310ece950e517476e22af10f41a136e",
|
||||
"https://deno.land/std@0.152.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74",
|
||||
"https://deno.land/std@0.152.0/_util/os.ts": "3b4c6e27febd119d36a416d7a97bd3b0251b77c88942c8f16ee5953ea13e2e49",
|
||||
"https://deno.land/std@0.152.0/async/deferred.ts": "bc18e28108252c9f67dfca2bbc4587c3cbf3aeb6e155f8c864ca8ecff992b98a",
|
||||
"https://deno.land/std@0.152.0/bytes/bytes_list.ts": "aba5e2369e77d426b10af1de0dcc4531acecec27f9b9056f4f7bfbf8ac147ab4",
|
||||
"https://deno.land/std@0.152.0/bytes/equals.ts": "3c3558c3ae85526f84510aa2b48ab2ad7bdd899e2e0f5b7a8ffc85acb3a6043a",
|
||||
"https://deno.land/std@0.152.0/bytes/mod.ts": "763f97d33051cc3f28af1a688dfe2830841192a9fea0cbaa55f927b49d49d0bf",
|
||||
"https://deno.land/std@0.152.0/crypto/timing_safe_equal.ts": "82a29b737bc8932d75d7a20c404136089d5d23629e94ba14efa98a8cc066c73e",
|
||||
"https://deno.land/std@0.152.0/encoding/base64.ts": "c57868ca7fa2fbe919f57f88a623ad34e3d970d675bdc1ff3a9d02bba7409db2",
|
||||
"https://deno.land/std@0.152.0/fmt/colors.ts": "6f9340b7fb8cc25a993a99e5efc56fe81bb5af284ff412129dd06df06f53c0b4",
|
||||
"https://deno.land/std@0.152.0/http/_negotiation/common.ts": "410e902f01cdd324e4746e8017595be4fc357d6fc4cd6044f2f808a943d7eaf7",
|
||||
"https://deno.land/std@0.152.0/http/_negotiation/encoding.ts": "f749c1d539d139af783e8a7741de5a47a98a5e3c9af82b8af512567ccf5fe632",
|
||||
"https://deno.land/std@0.152.0/http/_negotiation/language.ts": "53c306186904d2dace4c624a8822542866ad332a7f40ac90e0af1504f95c63d0",
|
||||
"https://deno.land/std@0.152.0/http/_negotiation/media_type.ts": "ecdda87286495f7ff25116858f5088856953e2f1585e593d314e0c71b826a137",
|
||||
"https://deno.land/std@0.152.0/http/http_errors.ts": "fe9b7f95f7ee0592c3306f8c7aed03ba53d55d1ef81e00041c1171b9588f46d9",
|
||||
"https://deno.land/std@0.152.0/http/http_status.ts": "897575a7d6bc2b9123f6a38ecbc0f03d95a532c5d92029315dc9f508e12526b8",
|
||||
"https://deno.land/std@0.152.0/http/negotiation.ts": "f35b1ff2ad4ff9feaa00ac234960b398172768205c8eceaef7f2eafe34716ba2",
|
||||
"https://deno.land/std@0.152.0/io/buffer.ts": "bd0c4bf53db4b4be916ca5963e454bddfd3fcd45039041ea161dbf826817822b",
|
||||
"https://deno.land/std@0.152.0/io/readers.ts": "45847ad404afd2f605eae1cff193f223462bc55eeb9ae313c2f3db28aada0fd6",
|
||||
"https://deno.land/std@0.152.0/io/types.d.ts": "0cae3a62da7a37043661746c65c021058bae020b54e50c0e774916e5d4baee43",
|
||||
"https://deno.land/std@0.152.0/media_types/_util.ts": "ce9b4fc4ba1c447dafab619055e20fd88236ca6bdd7834a21f98bd193c3fbfa1",
|
||||
"https://deno.land/std@0.152.0/media_types/mod.ts": "3829264ca0610cac40f3214f939d7733483523f82bc1041c51045d7c75fb93b8",
|
||||
"https://deno.land/std@0.152.0/media_types/vendor/mime-db.v1.52.0.ts": "724cee25fa40f1a52d3937d6b4fbbfdd7791ff55e1b7ac08d9319d5632c7f5af",
|
||||
"https://deno.land/std@0.152.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3",
|
||||
"https://deno.land/std@0.152.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09",
|
||||
"https://deno.land/std@0.152.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b",
|
||||
"https://deno.land/std@0.152.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633",
|
||||
"https://deno.land/std@0.152.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee",
|
||||
"https://deno.land/std@0.152.0/path/mod.ts": "56fec03ad0ebd61b6ab39ddb9b0ddb4c4a5c9f2f4f632e09dd37ec9ebfd722ac",
|
||||
"https://deno.land/std@0.152.0/path/posix.ts": "c1f7afe274290ea0b51da07ee205653b2964bd74909a82deb07b69a6cc383aaa",
|
||||
"https://deno.land/std@0.152.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9",
|
||||
"https://deno.land/std@0.152.0/path/win32.ts": "bd7549042e37879c68ff2f8576a25950abbfca1d696d41d82c7bca0b7e6f452c",
|
||||
"https://deno.land/std@0.152.0/streams/conversion.ts": "fc3db02026183da795fa32ac7549868e9f19c75ba029d4b4c3739af62b48517a",
|
||||
"https://deno.land/std@0.152.0/testing/_diff.ts": "029a00560b0d534bc0046f1bce4bd36b3b41ada3f2a3178c85686eb2ff5f1413",
|
||||
"https://deno.land/std@0.152.0/testing/_format.ts": "0d8dc79eab15b67cdc532826213bbe05bccfd276ca473a50a3fc7bbfb7260642",
|
||||
"https://deno.land/std@0.152.0/testing/asserts.ts": "093735c88f52bbead7f60a1f7a97a2ce4df3c2d5fab00a46956f20b4a5793ccd",
|
||||
"https://deno.land/std@0.162.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74",
|
||||
"https://deno.land/std@0.162.0/_util/os.ts": "8a33345f74990e627b9dfe2de9b040004b08ea5146c7c9e8fe9a29070d193934",
|
||||
"https://deno.land/std@0.162.0/fmt/colors.ts": "9e36a716611dcd2e4865adea9c4bec916b5c60caad4cdcdc630d4974e6bb8bd4",
|
||||
"https://deno.land/std@0.162.0/fs/_util.ts": "fdc156f897197f261a1c096dcf8ff9267ed0ff42bd5b31f55053a4763a4bae3b",
|
||||
"https://deno.land/std@0.162.0/fs/copy.ts": "73bdf24f4322648d9bc38ef983b818637ba368351d17aa03644209d3ce3eac31",
|
||||
"https://deno.land/std@0.162.0/fs/empty_dir.ts": "c15a0aaaf40f8c21cca902aa1e01a789ad0c2fd1b7e2eecf4957053c5dbf707f",
|
||||
"https://deno.land/std@0.162.0/fs/ensure_dir.ts": "76395fc1c989ca8d2de3aedfa8240eb8f5225cde20f926de957995b063135b80",
|
||||
"https://deno.land/std@0.162.0/fs/ensure_file.ts": "b8e32ea63aa21221d0219760ba3f741f682d7f7d68d0d24a3ec067c338568152",
|
||||
"https://deno.land/std@0.162.0/fs/ensure_link.ts": "5cc1c04f18487d7d1edf4c5469705f30b61390ffd24ad7db6df85e7209b32bb2",
|
||||
"https://deno.land/std@0.162.0/fs/ensure_symlink.ts": "5273557b8c50be69477aa9cb003b54ff2240a336db52a40851c97abce76b96ab",
|
||||
"https://deno.land/std@0.162.0/fs/eol.ts": "65b1e27320c3eec6fb653b27e20056ee3d015d3e91db388cfefa41616ebc7cb3",
|
||||
"https://deno.land/std@0.162.0/fs/exists.ts": "6a447912e49eb79cc640adacfbf4b0baf8e17ede6d5bed057062ce33c4fa0d68",
|
||||
"https://deno.land/std@0.162.0/fs/expand_glob.ts": "d3f62aefc7718d878904d60d91e8e6dbbf86c696d32b6cbbc333637acf7f8571",
|
||||
"https://deno.land/std@0.162.0/fs/mod.ts": "354a6f972ef4e00c4dd1f1339a8828ef0764c1c23d3c0010af3fcc025d8655b0",
|
||||
"https://deno.land/std@0.162.0/fs/move.ts": "6d7fa9da60dbc7a32dd7fdbc2ff812b745861213c8e92ba96dace0669b0c378c",
|
||||
"https://deno.land/std@0.162.0/fs/walk.ts": "d96d4e5b6a3552e8304f28a0fd0b317b812298298449044f8de4932c869388a5",
|
||||
"https://deno.land/std@0.162.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3",
|
||||
"https://deno.land/std@0.162.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09",
|
||||
"https://deno.land/std@0.162.0/path/_util.ts": "d16be2a16e1204b65f9d0dfc54a9bc472cafe5f4a190b3c8471ec2016ccd1677",
|
||||
"https://deno.land/std@0.162.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633",
|
||||
"https://deno.land/std@0.162.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee",
|
||||
"https://deno.land/std@0.162.0/path/mod.ts": "56fec03ad0ebd61b6ab39ddb9b0ddb4c4a5c9f2f4f632e09dd37ec9ebfd722ac",
|
||||
"https://deno.land/std@0.162.0/path/posix.ts": "6b63de7097e68c8663c84ccedc0fd977656eb134432d818ecd3a4e122638ac24",
|
||||
"https://deno.land/std@0.162.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9",
|
||||
"https://deno.land/std@0.162.0/path/win32.ts": "ee8826dce087d31c5c81cd414714e677eb68febc40308de87a2ce4b40e10fb8d",
|
||||
"https://deno.land/std@0.162.0/testing/_diff.ts": "a23e7fc2b4d8daa3e158fa06856bedf5334ce2a2831e8bf9e509717f455adb2c",
|
||||
"https://deno.land/std@0.162.0/testing/_format.ts": "cd11136e1797791045e639e9f0f4640d5b4166148796cad37e6ef75f7d7f3832",
|
||||
"https://deno.land/std@0.162.0/testing/asserts.ts": "1e340c589853e82e0807629ba31a43c84ebdcdeca910c4a9705715dfdb0f5ce8",
|
||||
"https://deno.land/x/another_cookiejar@v5.0.2/cookie.ts": "2be7548d01a3a9df97deb187761a843a77fd824057478919abf1e1e89ae1eb2e",
|
||||
"https://deno.land/x/another_cookiejar@v5.0.2/cookie_jar.ts": "e47d7b2c608bcd9600fd26825b600946f16ae167216cea71935049188d2fc6d1",
|
||||
"https://deno.land/x/another_cookiejar@v5.0.2/fetch_wrapper.ts": "4fbca1e77383cf7da4703798e06a1129b21120f4d01c3a4c0801674dd7b6d53b",
|
||||
"https://deno.land/x/another_cookiejar@v5.0.2/mod.ts": "eff949014965771f2cd447fe78625a1ad28b59333afa40640f02c0922534d89a",
|
||||
"https://deno.land/x/corfu@v2.0.1/mod.ts": "159efb94e08231a1f11abc6add4a15af299fd138f6469a7550cd96c628f7c10c",
|
||||
"https://deno.land/x/corfu@v2.0.1/types.ts": "07e7123258ffed42e34f44ffe45a6e7f51658f60be3b8f456bf0dd775305355d",
|
||||
"https://deno.land/x/denosass@1.0.6/mod.ts": "5e9c142055d658f3acb2b370d0b412c783ed4b27db830f387525fb7f69a7ab3d",
|
||||
"https://deno.land/x/denosass@1.0.6/src/deps.ts": "cb5fa11799e3def8b593be3b5939d2755a2c7f1f4987f3af1bc4ad90922d3715",
|
||||
"https://deno.land/x/denosass@1.0.6/src/mod.ts": "d2b63172f98238f77831995a5d6c8a06af5252ad8fbe7b9ec40b60eae86f2164",
|
||||
"https://deno.land/x/denosass@1.0.6/src/types/module.types.ts": "7a5027482ded1d2967fbe690ef8f928446c5de8811c3333f9b09ae6e8122f9ba",
|
||||
"https://deno.land/x/denosass@1.0.6/src/wasm/grass.deno.js": "a72432ce8d6b8f9c31e31c71415fdca03fe36aa22417e414bc81e2e21a8a687b",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/component.ts": "6bd3dab67754e91308df863e11e2b7945bbe0bf575b4bc529e8a9e02087eb732",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/components/helmet.ts": "59e598dc79c7b18620de175c61eb26f4aeb6905a6654cd63359208a26471541e",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/components/img.ts": "82a9f830394a7d6cd9b789b48fe1e70bc64eb151c4b410a3da74347c06acdae0",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/components/index.ts": "8855ee8302a9a19f38202d4a7ff5b17e22942600da02356bdfbc80c99c5c55f5",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/components/link.ts": "0f0b1c57dc8c466203105062335e0d9ded89a34e75d08b1bbeece198d42021cb",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/components/router.ts": "1feb8b6881641a18a3bdd937089b3f5a7b9f36948f8178a85acde7e4c9294a6d",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/components/suspense.ts": "0711b7cdcd42b0b085972eca796d3ba7c436a736e1d2ce17db7e0cd1d3b928f5",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/components/visible.ts": "f19487f7faff0bad38a5549f1efac1df351e83ee4a77ca5886412b439f4b6b53",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/context.ts": "a65018beedf3e1863b96f9d99cf2d471c231a6ae0c77877a77754a398105f9fc",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/core.ts": "d45b13ecc3a6739e22b30f48c9f021cb8373e2b462f39ac5b15389bdf3d692be",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/customElementsMode.ts": "f5446d3c3afe803a7f97a3434d3970e662f5d0635db79b0e4010e2972ff66a6e",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/fragment.ts": "9cfb0dcdcb02d5cc53f027b4b55609e4f9d6d9322b665292e572856f4b688569",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/helpers.ts": "d904aa646534f1c0cf7c05a6c8e02231f906d962acb725c964aedbcf50216d85",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/htm.ts": "d8d9cd4fb4ad4645bff3698c7eb96e7798022c5519d04e709ebde236edde156b",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/htm/build.ts": "9d6b6eb407c0db2d1213a3f9c82efc66a2bec34c89976132ff13e3e095dcaaaf",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/htm/constants.ts": "3f296f87f03bd0ba8d7673884a1f6c4c927a2774648eaa4fd3ca9e3c46c3f7b8",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/htm/index.ts": "29912b9f7a760884fce79caca82649b9772cfa3c3272e0426a4ce377b67d70d5",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/index.ts": "0f39c911a39c61cb39f9bd8a2481500126dcb1b2a826d5b4523dd47a08b6938d",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/jsx.ts": "7d5b4d4a249fba1a42f2016f54f71ca049d96ff490e098db4a19b2a9b197b952",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/lazy.ts": "f8b8a2b915daff1fb70704ffad5171c805f1e28778b5cd0f8c827780762776c4",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/mod.ts": "3dda2bc0dbee9abd01c03acf43ab55a7854952afe0450245fc2ad12eb9bd9598",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/regexDom.ts": "de82fd3110c5a367e3d4ba9b774cfef3baf995deff455edc7363551d79089c90",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/ssr.ts": "8f77228a7ed13990deba0c1a69d7d3f2902c837b62d24f5b7a019f84c96ad234",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/state.ts": "cfc6ca6eb5e65f4cd60717a0a96ce604053bacf6e0b8835afbe22327e9979a1b",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/store.ts": "653e8c53d6ed4e410c76b1a7a044aa7cc71ff00fb3af9f3a94253591b5f4dcea",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/types.ts": "fb338d7fa4422a92c442d14e073a2deb01d42b017fcd36013a1f6554e17c5449",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/version.ts": "30412f1a0cdd968633a760c456d96e83196ee72ca66cfebe1e526d66c7758ebe",
|
||||
"https://deno.land/x/nano_jsx@v0.0.34/withStyles.ts": "8aae4c8e79319fe991d49dd8ccc927c221786dfe58de640dba9d9885ce0dd4b7",
|
||||
"https://deno.land/x/oak@v11.1.0/application.ts": "0a728331822b8e27727ceec48a8499657c3163fc48fd379a8a9578a75f3cdb62",
|
||||
"https://deno.land/x/oak@v11.1.0/body.ts": "78402a4936accb80372c4944384658105604352d6783de7ff1e36b8832dd93c9",
|
||||
"https://deno.land/x/oak@v11.1.0/buf_reader.ts": "7cf96aa0ac670b75098113cf88a291a68332cc45efa8a9698f064ac5b8098a0f",
|
||||
"https://deno.land/x/oak@v11.1.0/content_disposition.ts": "8b8c3cb2fba7138cd5b7f82fc3b5ea39b33db924a824b28261659db7e164621e",
|
||||
"https://deno.land/x/oak@v11.1.0/context.ts": "014d1ce40e62a7901411425541b0d5a08018968a330595bd686f8d00222a35bb",
|
||||
"https://deno.land/x/oak@v11.1.0/cookies.ts": "d9f94b99f26c6169c6982ce12323c41a548d001bfc28f464264c22dc3dbf2181",
|
||||
"https://deno.land/x/oak@v11.1.0/deps.ts": "b897b0f2bec99cd8b402b279b7f21de955d98cbd72835b6c912be5e11c26148b",
|
||||
"https://deno.land/x/oak@v11.1.0/etag.ts": "19918f5e1964e3fe6c9fe524a88ffbf9900ce1dfe4146b187b2a86256bb6b663",
|
||||
"https://deno.land/x/oak@v11.1.0/headers.ts": "f50fb05614432bda971021633129aa2e8737e0844e0f01c27a937997b4d8dd4f",
|
||||
"https://deno.land/x/oak@v11.1.0/helpers.ts": "42212afa07a560b2958359cc19577417e89d9574d6579551a0af36ff7f00cc6e",
|
||||
"https://deno.land/x/oak@v11.1.0/http_request.ts": "0831c828816fcb58a5aa8361c6865c4151f4c8b59fabcef2e2cd235bb28170c5",
|
||||
"https://deno.land/x/oak@v11.1.0/http_server_flash.ts": "e312754acad26d3d70f243d657547e697921f67f0a2179dbec41a20a3228fd79",
|
||||
"https://deno.land/x/oak@v11.1.0/http_server_native.ts": "549dffcd2db5cbb0e44ad50cf9c54956b42a10450b1ac66e1362e32a073c8c1b",
|
||||
"https://deno.land/x/oak@v11.1.0/http_server_native_request.ts": "07910ea2ed51af6c4e69addf9015cdd8d2b5c9ee03fd4993e386834a129a9eb6",
|
||||
"https://deno.land/x/oak@v11.1.0/isMediaType.ts": "62d638abcf837ece3a8f07a4b7ca59794135cb0d4b73194c7d5837efd4161005",
|
||||
"https://deno.land/x/oak@v11.1.0/keyStack.ts": "fa0d5898fb8ba34de1c9cdcf4b2e8434952dc9931671858d33560368784a22ef",
|
||||
"https://deno.land/x/oak@v11.1.0/mediaTyper.ts": "042b853fc8e9c3f6c628dd389e03ef481552bf07242efc3f8a1af042102a6105",
|
||||
"https://deno.land/x/oak@v11.1.0/middleware.ts": "de14f045a2ddfe845d89b5d3140ff52cbcc6f3b3965391106ce04480f9786737",
|
||||
"https://deno.land/x/oak@v11.1.0/middleware/proxy.ts": "b927232f97ec18af4185d7912e45b1191e3ffe24a9c875262ad524211b1274c9",
|
||||
"https://deno.land/x/oak@v11.1.0/mod.ts": "de52855c8f626e30ba683fb265c0a0773ba2f5f117b3549b7d9c857edba58338",
|
||||
"https://deno.land/x/oak@v11.1.0/multipart.ts": "98fe9f226de8c26a16d067027b69fb1e34ad8c4055767dd157907d06cea36f9a",
|
||||
"https://deno.land/x/oak@v11.1.0/range.ts": "68a6df7ab3b868843e33f52deb94c3d4cab25cb9ef369691990c2ac15b04fafb",
|
||||
"https://deno.land/x/oak@v11.1.0/request.ts": "5852ad36389b48e0428a6f3c90854d01f10d1b15949b56001e1e75c2a00ef0f9",
|
||||
"https://deno.land/x/oak@v11.1.0/response.ts": "867d81f7eb0c65c7b8e0e0e9e145ededd5b6daa9ad922e6adc6a36a525f439a6",
|
||||
"https://deno.land/x/oak@v11.1.0/router.ts": "187522a549f6c179ff01d321882a8bfacbfb7f3e24b004ec4534a3613c7f9b0e",
|
||||
"https://deno.land/x/oak@v11.1.0/send.ts": "7ef2591792426d62add91536bb434566d4b224247ca343fdd63e486f9d4e9446",
|
||||
"https://deno.land/x/oak@v11.1.0/server_sent_event.ts": "948b0fe4cb3fe38c7db15e476eb3b7671ef20e566d130e9f701d7c0146aa47dd",
|
||||
"https://deno.land/x/oak@v11.1.0/structured_clone.ts": "ecf42598652b8082f37252cb873d6e257ad728e6fe73c6bd61f343d94501fbde",
|
||||
"https://deno.land/x/oak@v11.1.0/testing.ts": "7612656efd2975f7a2e6848609f5971922dbec46b76372c5c623202fdd7b9a85",
|
||||
"https://deno.land/x/oak@v11.1.0/types.d.ts": "41951a18c3bfdb11e40707cab75da078ba8a4907cd7d4e11d8536bc2db0dde05",
|
||||
"https://deno.land/x/oak@v11.1.0/util.ts": "3af8c4ed04c6cc2bedbe66e562a77fc59c72df31c55a902a63885861ca1639d6",
|
||||
"https://deno.land/x/path_to_regexp@v6.2.1/index.ts": "894060567837bae8fc9c5cbd4d0a05e9024672083d5883b525c031eea940e556",
|
||||
"https://deno.land/x/wattpad@v0.0.2/mod.ts": "d54c086bf37daeca54270bc88c4de87d02d583a5dda607df3c3e3de2a857a0d4",
|
||||
"https://deno.land/x/wattpad@v0.0.2/src/classes/Chapter.ts": "a45b2bdf70e04a58e05edfba6634e4089e85eda3c1551be05dcd0989648fc0a9",
|
||||
"https://deno.land/x/wattpad@v0.0.2/src/classes/Search.ts": "3a7c05c449978c822448aa80f2a29d4fccc7040ade9aa0d848b9a8341a79b3fe",
|
||||
"https://deno.land/x/wattpad@v0.0.2/src/classes/Story.ts": "b3fb3dfecb0cd533e614cab1440abf3716e02dd9485015df28bce4624e57cbcd",
|
||||
"https://deno.land/x/wattpad@v0.0.2/src/classes/TagSearch.ts": "1783267b203879b9ce862541b6770918cda10d64830a5007ab7d75233838e6b5",
|
||||
"https://deno.land/x/wattpad@v0.0.2/src/classes/Wattpad.ts": "8aca689c2f958fdecf3f7586563753fc4cddd783c5f0d7dadb8b17d5ba3bac91",
|
||||
"https://deno.land/x/wattpad@v0.0.2/src/types.d.ts": "fe933b610694544ffd9ade8a94aa555c82abaedf293faf5aa61f6ab6d1ee44f8",
|
||||
"https://deno.land/x/wattpad@v0.0.2/src/utils/http.ts": "9fc657974c7c5e91f09bb8af20197d59efab91a78ad4011080f4f0e6f442c31d",
|
||||
"https://deno.land/x/wattpad@v0.0.3/mod.ts": "dbf3bb1b3e10f5707bc6879bdd62db6e0618fd1786a5bed3374c2f7ffe1a6d2b",
|
||||
"https://deno.land/x/wattpad@v0.0.3/src/classes/Chapter.ts": "00b6097f5ffce2b44a24432fc62be324bf11a80327e2975eb115bc2e7410369c",
|
||||
"https://deno.land/x/wattpad@v0.0.3/src/classes/Search.ts": "36126f10a147231aaf27ad9626a27f7e6f42b157cd89225f74cfc4f9a3b7051a",
|
||||
"https://deno.land/x/wattpad@v0.0.3/src/classes/Story.ts": "e9c679f2201cf63a5f061cd535176d6c50569d3637c99cb2a3560e98ee923bbf",
|
||||
"https://deno.land/x/wattpad@v0.0.3/src/classes/TagSearch.ts": "fd73b16e250a29f0b14c809cead6d22ff7703d415078956126787095b0d4ebf7",
|
||||
"https://deno.land/x/wattpad@v0.0.3/src/classes/Wattpad.ts": "8aca689c2f958fdecf3f7586563753fc4cddd783c5f0d7dadb8b17d5ba3bac91",
|
||||
"https://deno.land/x/wattpad@v0.0.3/src/types.d.ts": "fe933b610694544ffd9ade8a94aa555c82abaedf293faf5aa61f6ab6d1ee44f8",
|
||||
"https://deno.land/x/wattpad@v0.0.3/src/utils/http.ts": "9fc657974c7c5e91f09bb8af20197d59efab91a78ad4011080f4f0e6f442c31d",
|
||||
"https://deno.land/x/wattpad@v0.0.4/mod.ts": "3248de35fff8b8b15bf848e9fc5469776608142bd4543177fd8b292d6e7d09c9",
|
||||
"https://deno.land/x/wattpad@v0.0.4/src/classes/Chapter.ts": "00b6097f5ffce2b44a24432fc62be324bf11a80327e2975eb115bc2e7410369c",
|
||||
"https://deno.land/x/wattpad@v0.0.4/src/classes/Search.ts": "36126f10a147231aaf27ad9626a27f7e6f42b157cd89225f74cfc4f9a3b7051a",
|
||||
"https://deno.land/x/wattpad@v0.0.4/src/classes/Story.ts": "e9c679f2201cf63a5f061cd535176d6c50569d3637c99cb2a3560e98ee923bbf",
|
||||
"https://deno.land/x/wattpad@v0.0.4/src/classes/TagSearch.ts": "fd73b16e250a29f0b14c809cead6d22ff7703d415078956126787095b0d4ebf7",
|
||||
"https://deno.land/x/wattpad@v0.0.4/src/classes/Wattpad.ts": "ce67ad71a4250232818473807da6a687f71772c9d142154a431b46b73201a11e",
|
||||
"https://deno.land/x/wattpad@v0.0.4/src/types.d.ts": "fe933b610694544ffd9ade8a94aa555c82abaedf293faf5aa61f6ab6d1ee44f8",
|
||||
"https://deno.land/x/wattpad@v0.0.4/src/utils/http.ts": "50e18486856ec16878f780af0a4cfe9850a69590de62d48f7ec5e74d602d20e7",
|
||||
"https://raw.githubusercontent.com/kt3k/callsites/v1.0.0/mod.ts": "a5fdfa7916d03459fd4830ca526d493d5f4ce0ea91619905d524c9a3a5c3cd15",
|
||||
"https://raw.githubusercontent.com/nomyTx/gas/bef3e8b8b51a9929b915b3e13df07290a37832ba/jsx.ts": "adf05a2478b48bc0c1e4e18db87c7c03d0894e3751be99571c3e63375471d5d3"
|
||||
},
|
||||
"npm": {
|
||||
"specifiers": { "@connorskees/grass": "@connorskees/grass@0.12.0" },
|
||||
"packages": {
|
||||
"@connorskees/grass@0.12.0": {
|
||||
"integrity": "sha512-nDICkb3SxivBAteLuUsosUk0EsB0qQW2hBtnkhFP0dP/yAV1zcrq4p38O12/Mw+Yt1DKTqQSyCZAoliaK/kw4g==",
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
import { h } from "https://deno.land/x/corfu@v2.0.1/mod.ts";
|
||||
|
||||
import { Application, Router } from "https://deno.land/x/oak@v11.1.0/mod.ts";
|
||||
import config from "./config.ts";
|
||||
|
||||
const app = new Application();
|
||||
//print info on listen
|
||||
app.addEventListener("listen", (event) => {
|
||||
console.log(
|
||||
`voltpad listening on http://${event.hostname.replace(
|
||||
"::1",
|
||||
"localhost"
|
||||
)}:${event.port}`
|
||||
);
|
||||
});
|
||||
|
||||
app.use(async (ctx) => {
|
||||
if (ctx.request.url.pathname === "/") ctx.request.url.pathname = "/index";
|
||||
let mod;
|
||||
try {
|
||||
mod = await import(
|
||||
"./routes" +
|
||||
ctx.request.url.pathname +
|
||||
".tsx" +
|
||||
`?update=${Date.now()}`
|
||||
);
|
||||
} catch {
|
||||
try {
|
||||
return await ctx.send({
|
||||
root: `./static`,
|
||||
index: `${ctx.request.url.pathname}`
|
||||
});
|
||||
} catch {
|
||||
mod = await import("./routes/404.tsx");
|
||||
}
|
||||
}
|
||||
let rizz;
|
||||
try {
|
||||
rizz = await mod.default(ctx.request.url.searchParams);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
mod = await import("./routes/500.tsx");
|
||||
rizz = await mod.default();
|
||||
}
|
||||
ctx.response.body = "<!DOCTYPE html>" + rizz;
|
||||
});
|
||||
|
||||
//(attempt to) set mimetype
|
||||
app.use(async (ctx, next) => {
|
||||
await next();
|
||||
if (!ctx.response.headers.get("Content-Type")) {
|
||||
switch (ctx.request.url.pathname.split(".").at(-1)) {
|
||||
case "json":
|
||||
ctx.response.headers.set("Content-Type", "application/json");
|
||||
break;
|
||||
default:
|
||||
ctx.response.headers.set("Content-Type", "text/html");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.use(async (ctx, next) => {
|
||||
await next();
|
||||
const rt = ctx.response.headers.get("X-Response-Time");
|
||||
console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`);
|
||||
});
|
||||
|
||||
await app.listen({
|
||||
hostname: config.serve.address,
|
||||
port: config.serve.port
|
||||
});
|
@ -0,0 +1,12 @@
|
||||
import { h } from "../jsx.ts";
|
||||
|
||||
import Base from "../templates/Base.tsx";
|
||||
|
||||
export default () => (
|
||||
<Base title="Home" description="The homepage." stylepath="css/index.scss">
|
||||
<div style="text-align:center;">
|
||||
<h1>404</h1>
|
||||
<p>Page not found.</p>
|
||||
</div>
|
||||
</Base>
|
||||
);
|
@ -0,0 +1,12 @@
|
||||
import { h } from "../jsx.ts";
|
||||
|
||||
import Base from "../templates/Base.tsx";
|
||||
|
||||
export default () => (
|
||||
<Base title="Home" description="The homepage." stylepath="css/index.scss">
|
||||
<div style="text-align:center;">
|
||||
<h1>500</h1>
|
||||
<p>Internal server error.</p>
|
||||
</div>
|
||||
</Base>
|
||||
);
|
@ -0,0 +1,12 @@
|
||||
import { h } from "../jsx.ts";
|
||||
|
||||
import Base from "../templates/Base.tsx";
|
||||
|
||||
export default () => (
|
||||
<Base title="Home" description="The homepage." stylepath="css/index.scss">
|
||||
<div style="text-align: center;">
|
||||
<h1>Voltpad</h1>
|
||||
<p>A blazingly fast (🚀) Wattpad frontend</p>
|
||||
</div>
|
||||
</Base>
|
||||
);
|
@ -0,0 +1,133 @@
|
||||
import { h } from "../jsx.ts";
|
||||
import watt, { watt as originalWatt } from "../wattpad.ts";
|
||||
import Base from "../templates/Base.tsx";
|
||||
|
||||
function search() {
|
||||
console.log(document.getElementById("query"));
|
||||
}
|
||||
|
||||
export default async (params: URLSearchParams) => {
|
||||
const res = [];
|
||||
if (params.get("query") && params.get("type")) {
|
||||
const search = originalWatt[
|
||||
params.get("type") === "tag" ? "tagSearch" : "search"
|
||||
]({
|
||||
tags: (params.get("query") as string).split(","),
|
||||
query: params.get("query") as string,
|
||||
isTitle: params.get("type") === "title",
|
||||
limit: 20
|
||||
});
|
||||
await search.update(Number(params.get("page") ?? 0));
|
||||
for (let i = 0; i < search.results.length; i++) {
|
||||
const rizz = await watt.getStory(search.results[i].id, false);
|
||||
res.push(
|
||||
<a href={"/story?id=" + rizz.id} class="story">
|
||||
<img src={rizz.storyJSON.cover} />
|
||||
<div>
|
||||
<h3>{rizz.name}</h3>
|
||||
<p>{rizz.storyJSON.description}</p>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Base
|
||||
title="Search"
|
||||
description="The homepage."
|
||||
stylepath="css/index.scss"
|
||||
>
|
||||
{/* TODO: impl autocomplete for tags? */}
|
||||
<form
|
||||
method="GET"
|
||||
style="display:flex;flex-direction:column;align-items:center;justify-content:center;"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
id="query"
|
||||
type="text"
|
||||
name="query"
|
||||
placeholder="Query"
|
||||
style="margin-top: 0.5em;"
|
||||
value={params.get("query") ?? ""}
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
id="normal"
|
||||
name="type"
|
||||
value="text"
|
||||
checked={
|
||||
params.get("type") === "text" || !params.get("type")
|
||||
}
|
||||
/>
|
||||
<label for="id">Text search</label>
|
||||
<input
|
||||
type="radio"
|
||||
id="title"
|
||||
name="type"
|
||||
value="title"
|
||||
checked={params.get("type") === "title"}
|
||||
/>
|
||||
<label for="title">Title search</label>
|
||||
<input
|
||||
type="radio"
|
||||
id="tag"
|
||||
name="type"
|
||||
value="tag"
|
||||
checked={params.get("type") === "tag"}
|
||||
/>
|
||||
<label for="tag">Tag search</label>
|
||||
</div>
|
||||
<input
|
||||
style="margin-top:0.25em;"
|
||||
type="submit"
|
||||
value="Submit"
|
||||
/>
|
||||
</form>
|
||||
|
||||
<div id="stories" class="stories">
|
||||
{res.join("")}
|
||||
<div class="pagenav">
|
||||
{Number(params.get("page") ?? 0) === 0 ? undefined : (
|
||||
<a
|
||||
href={(() => {
|
||||
// total and utter jank
|
||||
params.set(
|
||||
"page",
|
||||
(Number(params.get("page")) - 1).toString()
|
||||
);
|
||||
const strParams = params.toString();
|
||||
params.set(
|
||||
"page",
|
||||
(Number(params.get("page")) + 1).toString()
|
||||
);
|
||||
return "/search?" + strParams.toString();
|
||||
})()}
|
||||
>
|
||||
<
|
||||
</a>
|
||||
)}
|
||||
{params.get("query") && params.get("type") ? (
|
||||
<div> | </div>
|
||||
) : undefined}
|
||||
{res.length !== 20 &&
|
||||
(res.length as number) !== 19 ? undefined : (
|
||||
<a
|
||||
href={(() => {
|
||||
const tmpParams = params;
|
||||
tmpParams.set(
|
||||
"page",
|
||||
(Number(params.get("page")) + 1).toString()
|
||||
);
|
||||
return "/search?" + tmpParams.toString();
|
||||
})()}
|
||||
>
|
||||
>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Base>
|
||||
);
|
||||
};
|
@ -0,0 +1,100 @@
|
||||
import { h } from "../jsx.ts";
|
||||
|
||||
import Story from "../templates/Story.tsx";
|
||||
import watt from "../wattpad.ts";
|
||||
import FourOhFour from "./404.tsx";
|
||||
|
||||
export default async (params: URLSearchParams) => {
|
||||
if (!params.get("id")) return <FourOhFour />;
|
||||
|
||||
const story = await watt.getStory(params.get("id") as string);
|
||||
|
||||
// chapters
|
||||
if (params.get("chapter")) {
|
||||
await story.chapters[Number(params.get("chapter") as string)].init();
|
||||
return (
|
||||
<Story story={story} stylepath="css/index.scss">
|
||||
<div style="margin-left: 1em; margin-right: 1em;">
|
||||
{
|
||||
story.chapters[Number(params.get("chapter") as string)]
|
||||
.html
|
||||
}
|
||||
</div>
|
||||
<div class="pagenav">
|
||||
{Number(params.get("chapter") ?? 0) === 0 ? undefined : (
|
||||
<a
|
||||
href={(() => {
|
||||
// total and utter jank
|
||||
params.set(
|
||||
"chapter",
|
||||
(
|
||||
Number(params.get("chapter")) - 1
|
||||
).toString()
|
||||
);
|
||||
const strParams = params.toString();
|
||||
params.set(
|
||||
"chapter",
|
||||
(
|
||||
Number(params.get("chapter")) + 1
|
||||
).toString()
|
||||
);
|
||||
return "/story?" + strParams.toString();
|
||||
})()}
|
||||
>
|
||||
<
|
||||
</a>
|
||||
)}
|
||||
|
|
||||
{story.chapters.length <
|
||||
Number(params.get("chapter")) ? undefined : (
|
||||
<a
|
||||
href={(() => {
|
||||
const tmpParams = params;
|
||||
tmpParams.set(
|
||||
"chapter",
|
||||
(
|
||||
Number(params.get("chapter")) + 1
|
||||
).toString()
|
||||
);
|
||||
return "/story?" + tmpParams.toString();
|
||||
})()}
|
||||
>
|
||||
>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</Story>
|
||||
);
|
||||
}
|
||||
// metadata
|
||||
else {
|
||||
return (
|
||||
<Story story={story} stylepath="css/index.scss">
|
||||
<div style="display:flex;align-items:center;justify-content:center;flex-direction:column;">
|
||||
<div class="story">
|
||||
<img src={story.storyJSON.cover} />
|
||||
<div>
|
||||
<h3>{story.name}</h3>
|
||||
<p>{story.storyJSON.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;flex-wrap:wrap;align-items:center;justify-content:center;flex-direction:row;margin-top: 0.5em;text-align:center;">
|
||||
{story.tags
|
||||
.map((v) => (
|
||||
<div>
|
||||
<a
|
||||
href={`/search?query=${v}&type=tag`}
|
||||
style="background-color:darkgrey; border-radius: 0.3em; padding: 0.1em; margin-right: 0.5em;border: none;outline: none;text-decoration: none;"
|
||||
>
|
||||
#{v}
|
||||
</a>
|
||||
<div style="margin-top: 0.5em;" />
|
||||
</div>
|
||||
))
|
||||
.join("")}
|
||||
</div>
|
||||
</div>
|
||||
</Story>
|
||||
);
|
||||
}
|
||||
};
|
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 7.8 KiB |
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#2b5797</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 2.1 KiB |
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Voltpad",
|
||||
"short_name": "Voltpad",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
import sass from "https://deno.land/x/denosass@1.0.6/mod.ts";
|
||||
import { h, PropsWithChildren } from "../jsx.ts";
|
||||
|
||||
import Header from "../components/Header.tsx";
|
||||
|
||||
interface TemplateProps {
|
||||
title: string;
|
||||
description: string;
|
||||
style?: string;
|
||||
stylepath?: string;
|
||||
}
|
||||
|
||||
export default (props: PropsWithChildren<TemplateProps>) => (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0"
|
||||
/>
|
||||
|
||||
{/* favicon stuff generated with https://realfavicongenerator.net */}
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link
|
||||
rel="mask-icon"
|
||||
href="/safari-pinned-tab.svg"
|
||||
color="#5bbad5"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-title" content="Voltpad" />
|
||||
<meta name="application-name" content="Voltpad" />
|
||||
<meta name="msapplication-TileColor" content="#2b5797" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
|
||||
<title>{props.title} | Voltpad</title>
|
||||
{(() => {
|
||||
if (!props.style) props.style = "";
|
||||
if (props.stylepath)
|
||||
props.style += Deno.readTextFileSync(props.stylepath);
|
||||
else return <div></div>;
|
||||
return <style>{sass(props.style).to_string()}</style>;
|
||||
})()}
|
||||
</head>
|
||||
<Header
|
||||
entries={[
|
||||
{
|
||||
name: "Home",
|
||||
href: "/"
|
||||
},
|
||||
{
|
||||
name: "Search",
|
||||
href: "/search"
|
||||
}
|
||||
]}
|
||||
></Header>
|
||||
<div class="main">{props.children}</div>
|
||||
</html>
|
||||
);
|
@ -0,0 +1,69 @@
|
||||
import sass from "https://deno.land/x/denosass@1.0.6/mod.ts";
|
||||
import { Story } from "../wattpad.ts";
|
||||
import { h, PropsWithChildren } from "../jsx.ts";
|
||||
|
||||
import Header from "../components/Header.tsx";
|
||||
|
||||
interface StoryProps {
|
||||
story: Story;
|
||||
style?: string;
|
||||
stylepath?: string;
|
||||
}
|
||||
|
||||
export default (props: PropsWithChildren<StoryProps>) => (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0"
|
||||
/>
|
||||
|
||||
{/* favicon stuff generated with https://realfavicongenerator.net */}
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link
|
||||
rel="mask-icon"
|
||||
href="/safari-pinned-tab.svg"
|
||||
color="#5bbad5"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-title" content="Voltpad" />
|
||||
<meta name="application-name" content="Voltpad" />
|
||||
<meta name="msapplication-TileColor" content="#2b5797" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
|
||||
<title>{props.story.name}</title>
|
||||
{(() => {
|
||||
if (!props.style) props.style = "";
|
||||
if (props.stylepath)
|
||||
props.style += Deno.readTextFileSync(props.stylepath);
|
||||
else return <div></div>;
|
||||
return <style>{sass(props.style).to_string()}</style>;
|
||||
})()}
|
||||
</head>
|
||||
<Header
|
||||
id="storyHeader"
|
||||
entries={props.story.chapters.map((ch, i) => ({
|
||||
name: ch.name,
|
||||
href: `/story?id=${ch.workID}&chapter=${i}`
|
||||
}))}
|
||||
></Header>
|
||||
<div class="main">{props.children}</div>
|
||||
</html>
|
||||
);
|
@ -0,0 +1,7 @@
|
||||
export interface Props {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface PropsWithChildren extends Props {
|
||||
children: any;
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
export * from "https://deno.land/x/wattpad@v0.0.4/mod.ts";
|
||||
import Wattpad, { Story } from "https://deno.land/x/wattpad@v0.0.4/mod.ts";
|
||||
import config from "./config.ts";
|
||||
|
||||
const watt = new Wattpad();
|
||||
if (config.user) {
|
||||
await watt.authenticate(
|
||||
config.user.username,
|
||||
config.user.password,
|
||||
);
|
||||
}
|
||||
|
||||
const cache: {
|
||||
[k: string]: {
|
||||
story: Story;
|
||||
timestamp: Date;
|
||||
};
|
||||
} = {};
|
||||
|
||||
// re-init oldest story in cache every 5 minutes
|
||||
setInterval(() => {
|
||||
const oldStory = Object.values(cache).sort((a, b) =>
|
||||
// @ts-expect-error 2363; javascript is a disgrace but it makes sorting dates easy so ¯\_(ツ)_/¯
|
||||
b.timestamp - a.timestamp
|
||||
).pop(); // teehee
|
||||
if (!oldStory) return;
|
||||
cache[oldStory.story.id].timestamp = new Date();
|
||||
cache[oldStory.story.id].story.init().then(async (_) => {
|
||||
for (
|
||||
let i = 0;
|
||||
i < cache[oldStory.story.id].story.chapters.length;
|
||||
i++
|
||||
) {
|
||||
await cache[oldStory.story.id].story.chapters[i].init();
|
||||
}
|
||||
});
|
||||
}, 300000);
|
||||
|
||||
export { watt };
|
||||
|
||||
export default {
|
||||
search: watt.search,
|
||||
tagSearch: watt.tagSearch,
|
||||
async getStory(id: string, initChapters = true): Promise<Story> {
|
||||
if (!cache[id]) {
|
||||
cache[id] = {
|
||||
story: watt.getStory(id),
|
||||
timestamp: new Date(),
|
||||
};
|
||||
await cache[id].story.init();
|
||||
if (initChapters) {
|
||||
for (let i = 0; i < cache[id].story.chapters.length; i++) {
|
||||
await cache[id].story.chapters[i].init();
|
||||
}
|
||||
}
|
||||
}
|
||||
return cache[id].story;
|
||||
},
|
||||
};
|