mirror of
https://github.com/MadeBaruna/paimon-moe.git
synced 2024-12-03 13:36:55 +01:00
Migrate to SvelteKit
Close #158 commitb759884dce
Author: Made Baruna <made.setia@gmail.com> Date: Thu Jul 21 21:57:38 2022 +0700 Add update popup commit00f8b192af
Author: Made Baruna <made.setia@gmail.com> Date: Thu Jul 21 20:09:18 2022 +0700 Add service worker commit1cd1e40c77
Author: Made Baruna <made.setia@gmail.com> Date: Thu Jul 21 11:38:37 2022 +0700 Update firebase config commitedc036f62f
Author: Made Baruna <made.setia@gmail.com> Date: Wed Jul 20 23:33:38 2022 +0700 Separate build getter commite780ab18bf
Author: Made Baruna <made.setia@gmail.com> Date: Wed Jul 20 22:16:28 2022 +0700 Update readme commit7f0890acba
Author: Made Baruna <made.setia@gmail.com> Date: Wed Jul 20 22:07:25 2022 +0700 Fix createEnv commit1df04e369f
Author: Made Baruna <made.setia@gmail.com> Date: Wed Jul 20 22:03:12 2022 +0700 Migrate to svelte-kit
This commit is contained in:
parent
b06d4d5514
commit
593938c36d
103 changed files with 2761 additions and 5020 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,4 +3,6 @@
|
|||
/src/node_modules/@sapper/
|
||||
yarn-error.log
|
||||
/__sapper__/
|
||||
.svelte-kit
|
||||
/build
|
||||
.env
|
1
.npmrc
Normal file
1
.npmrc
Normal file
|
@ -0,0 +1 @@
|
|||
auto-install-peers=true
|
13
.prettierignore
Normal file
13
.prettierignore
Normal file
|
@ -0,0 +1,13 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
7
.prettierrc
Normal file
7
.prettierrc
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"printWidth": 120
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
module.exports = {
|
||||
trailingComma: 'all',
|
||||
tabWidth: 2,
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
printWidth: 120,
|
||||
};
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
Your best Genshin Impact companion! Paimon.moe helps you plan what to farm with ascension calculator and database. It also tracks your progress with a todo list and a wish counter.
|
||||
|
||||
Created with [Sapper](https://sapper.svelte.dev/) + [Tailwind CSS](https://tailwindcss.com/)
|
||||
Created with [SvelteKit](https://kit.svelte.dev/) + [Tailwind CSS](https://tailwindcss.com/)
|
||||
|
||||
# Development
|
||||
|
||||
```
|
||||
# install dependencies
|
||||
yarn
|
||||
pnpm i
|
||||
|
||||
# you need the api to run wish importer and wish tally
|
||||
git clone https://github.com/MadeBaruna/paimon-moe-api
|
||||
|
@ -20,10 +20,10 @@ docker-compose up -d
|
|||
# run in dev mode
|
||||
cp .env.example .env
|
||||
vi .env
|
||||
yarn dev
|
||||
pnpm dev
|
||||
|
||||
# export as production static site
|
||||
yarn export
|
||||
pnpm build
|
||||
```
|
||||
|
||||
# License
|
||||
|
|
54
package.json
54
package.json
|
@ -1,50 +1,34 @@
|
|||
{
|
||||
"type": "module",
|
||||
"name": "paimon-moe",
|
||||
"description": "A collection of tools to help playing Genshin Impact",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "NODE_OPTIONS=--max_old_space_size=4096 sapper dev",
|
||||
"build": "sapper build --legacy",
|
||||
"export": "NODE_OPTIONS=--max_old_space_size=4096 sapper export --legacy && cp __sapper__/build/firebase-messaging-sw.js __sapper__/export",
|
||||
"start": "node __sapper__/build"
|
||||
},
|
||||
"dependencies": {
|
||||
"compression": "^1.7.1",
|
||||
"exceljs": "^4.2.1",
|
||||
"localforage": "^1.9.0",
|
||||
"polka": "next",
|
||||
"prettier": "^2.2.1",
|
||||
"sirv": "^1.0.0"
|
||||
"dev": "vite dev --port 3000",
|
||||
"build": "NODE_OPTIONS=--max_old_space_size=4096 vite build",
|
||||
"preview": "vite preview",
|
||||
"start": "node build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
||||
"@babel/plugin-transform-runtime": "^7.0.0",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@mdi/js": "^5.9.55",
|
||||
"@rollup/plugin-babel": "^5.0.0",
|
||||
"@rollup/plugin-commonjs": "^16.0.0",
|
||||
"@rollup/plugin-dynamic-import-vars": "^1.1.1",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^10.0.0",
|
||||
"@rollup/plugin-replace": "^2.3.4",
|
||||
"@rollup/plugin-url": "^5.0.0",
|
||||
"autoprefixer": "^10.0.1",
|
||||
"@sveltejs/adapter-static": "1.0.0-next.37",
|
||||
"@sveltejs/kit": "^1.0.0-next.379",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"chart.js": "^2.9.4",
|
||||
"dayjs": "^1.9.4",
|
||||
"dotenv": "^8.2.0",
|
||||
"postcss": "^8.2.10",
|
||||
"postcss-load-config": "^3.0.0",
|
||||
"postcss-nested": "^5.0.1",
|
||||
"rollup": "^2.3.4",
|
||||
"rollup-plugin-svelte": "^7.0.0",
|
||||
"rollup-plugin-terser": "^7.0.0",
|
||||
"sapper": "^0.28.0",
|
||||
"exceljs": "^4.3.0",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-nested": "^5.0.6",
|
||||
"prettier": "^2.7.1",
|
||||
"prettier-plugin-svelte": "^2.7.0",
|
||||
"svelte": "^3.17.3",
|
||||
"svelte-i18n": "^3.3.6",
|
||||
"svelte-preprocess": "^4.5.1",
|
||||
"svelte-i18n": "^3.4.0",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"svelte-simple-modal": "^0.6.1",
|
||||
"tailwindcss": "^1.9.5"
|
||||
"tailwindcss": "^3.1.6",
|
||||
"vite": "^3.0.2"
|
||||
}
|
||||
}
|
||||
|
|
1687
pnpm-lock.yaml
Normal file
1687
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
3
postcss.config.cjs
Normal file
3
postcss.config.cjs
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
plugins: [require('postcss-nested'), require('tailwindcss'), require('autoprefixer')],
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = {
|
||||
plugins: [require('tailwindcss'), require('postcss-nested'), require('autoprefixer')],
|
||||
};
|
172
rollup.config.js
172
rollup.config.js
|
@ -1,172 +0,0 @@
|
|||
import path from 'path';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import replace from '@rollup/plugin-replace';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import url from '@rollup/plugin-url';
|
||||
import svelte from 'rollup-plugin-svelte';
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import json from '@rollup/plugin-json';
|
||||
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';
|
||||
|
||||
import config from 'sapper/config/rollup.js';
|
||||
import { config as envConfig } from 'dotenv';
|
||||
|
||||
import pkg from './package.json';
|
||||
|
||||
const mode = process.env.NODE_ENV;
|
||||
const dev = mode === 'development';
|
||||
const legacy = !!process.env.SAPPER_LEGACY_BUILD;
|
||||
const preprocess = require('./svelte.config').preprocess;
|
||||
|
||||
const onwarn = (warning, onwarn) =>
|
||||
(warning.code === 'MISSING_EXPORT' && /'preload'/.test(warning.message)) ||
|
||||
(warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) ||
|
||||
onwarn(warning);
|
||||
|
||||
const envData = {};
|
||||
Object.entries(envConfig().parsed).forEach(([key, val]) => {
|
||||
envData[`__paimon.env.${key}`] = `'${val}'`;
|
||||
});
|
||||
|
||||
export default {
|
||||
client: {
|
||||
input: config.client.input(),
|
||||
output: {
|
||||
...config.client.output(),
|
||||
sourcemap: dev ? 'inline' : true,
|
||||
},
|
||||
plugins: [
|
||||
replace({
|
||||
'process.browser': true,
|
||||
'process.env.NODE_ENV': JSON.stringify(mode),
|
||||
...envData,
|
||||
}),
|
||||
svelte({
|
||||
compilerOptions: {
|
||||
dev,
|
||||
hydratable: true,
|
||||
},
|
||||
emitCss: true,
|
||||
preprocess,
|
||||
}),
|
||||
url({
|
||||
sourceDir: path.resolve(__dirname, 'src/node_modules/images'),
|
||||
publicPath: '/client/',
|
||||
}),
|
||||
resolve({
|
||||
browser: true,
|
||||
dedupe: ['svelte'],
|
||||
}),
|
||||
commonjs(),
|
||||
json(),
|
||||
dynamicImportVars({
|
||||
include: [
|
||||
'**/*.svelte',
|
||||
'**/*.json',
|
||||
],
|
||||
}),
|
||||
|
||||
legacy &&
|
||||
babel({
|
||||
extensions: ['.js', '.mjs', '.html', '.svelte'],
|
||||
babelHelpers: 'runtime',
|
||||
exclude: ['node_modules/@babel/**'],
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: '> 0.25%, not dead',
|
||||
},
|
||||
],
|
||||
],
|
||||
plugins: [
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
[
|
||||
'@babel/plugin-transform-runtime',
|
||||
{
|
||||
useESModules: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
}),
|
||||
|
||||
!dev &&
|
||||
terser({
|
||||
module: true,
|
||||
}),
|
||||
],
|
||||
|
||||
preserveEntrySignatures: false,
|
||||
onwarn,
|
||||
},
|
||||
|
||||
server: {
|
||||
input: config.server.input(),
|
||||
output: config.server.output(),
|
||||
plugins: [
|
||||
replace({
|
||||
'process.browser': false,
|
||||
'process.env.NODE_ENV': JSON.stringify(mode),
|
||||
...envData,
|
||||
}),
|
||||
svelte({
|
||||
compilerOptions: {
|
||||
generate: 'ssr',
|
||||
hydratable: true,
|
||||
dev,
|
||||
},
|
||||
preprocess,
|
||||
}),
|
||||
url({
|
||||
sourceDir: path.resolve(__dirname, 'src/node_modules/images'),
|
||||
publicPath: '/client/',
|
||||
emitFiles: false, // already emitted by client build
|
||||
}),
|
||||
resolve({
|
||||
dedupe: ['svelte'],
|
||||
}),
|
||||
commonjs(),
|
||||
json(),
|
||||
dynamicImportVars({
|
||||
include: [
|
||||
'**/*.svelte',
|
||||
'**/*.json',
|
||||
],
|
||||
}),
|
||||
],
|
||||
external: Object.keys(pkg.dependencies).concat(require('module').builtinModules),
|
||||
|
||||
preserveEntrySignatures: 'strict',
|
||||
onwarn,
|
||||
},
|
||||
|
||||
serviceworker: {
|
||||
input: config.serviceworker.input().replace('service-worker', 'firebase-messaging-sw'),
|
||||
output: {
|
||||
...config.serviceworker.output(),
|
||||
file: config.serviceworker.output().file.replace('service-worker', 'firebase-messaging-sw'),
|
||||
},
|
||||
plugins: [replace(envData), resolve(), commonjs(), !dev && terser()],
|
||||
|
||||
preserveEntrySignatures: false,
|
||||
onwarn,
|
||||
},
|
||||
|
||||
// serviceworker: {
|
||||
// input: config.serviceworker.input(),
|
||||
// output: config.serviceworker.output(),
|
||||
// plugins: [
|
||||
// resolve(),
|
||||
// replace({
|
||||
// 'process.browser': true,
|
||||
// 'process.env.NODE_ENV': JSON.stringify(mode),
|
||||
// }),
|
||||
// commonjs(),
|
||||
// !dev && terser(),
|
||||
// ],
|
||||
|
||||
// preserveEntrySignatures: false,
|
||||
// onwarn,
|
||||
// },
|
||||
};
|
|
@ -1,14 +1,14 @@
|
|||
const fs = require('fs');
|
||||
import fs from 'fs';
|
||||
|
||||
let envString = '';
|
||||
envString += `GOOGLE_DRIVE_CLIENT_ID=${process.env.GOOGLE_DRIVE_CLIENT_ID}\n`;
|
||||
envString += `GOOGLE_DRIVE_API_KEY=${process.env.GOOGLE_DRIVE_API_KEY}\n`;
|
||||
envString += `API_HOST=${process.env.API_HOST}\n`;
|
||||
envString += `FIREBASE_API_KEY=${process.env.FIREBASE_API_KEY}\n`
|
||||
envString += `FIREBASE_AUTH_DOMAIN=${process.env.FIREBASE_AUTH_DOMAIN}\n`
|
||||
envString += `FIREBASE_PROJECT_ID=${process.env.FIREBASE_PROJECT_ID}\n`
|
||||
envString += `FIREBASE_STORAGE_BUCKET=${process.env.FIREBASE_STORAGE_BUCKET}\n`
|
||||
envString += `FIREBASE_MESSAGING_SENDER_ID=${process.env.FIREBASE_MESSAGING_SENDER_ID}\n`
|
||||
envString += `FIREBASE_APP_ID=${process.env.FIREBASE_APP_ID}\n`
|
||||
envString += `VITE_GOOGLE_DRIVE_CLIENT_ID=${process.env.GOOGLE_DRIVE_CLIENT_ID}\n`;
|
||||
envString += `VITE_GOOGLE_DRIVE_API_KEY=${process.env.GOOGLE_DRIVE_API_KEY}\n`;
|
||||
envString += `VITE_API_HOST=${process.env.API_HOST}\n`;
|
||||
envString += `VITE_FIREBASE_API_KEY=${process.env.FIREBASE_API_KEY}\n`;
|
||||
envString += `VITE_FIREBASE_AUTH_DOMAIN=${process.env.FIREBASE_AUTH_DOMAIN}\n`;
|
||||
envString += `VITE_FIREBASE_PROJECT_ID=${process.env.FIREBASE_PROJECT_ID}\n`;
|
||||
envString += `VITE_FIREBASE_STORAGE_BUCKET=${process.env.FIREBASE_STORAGE_BUCKET}\n`;
|
||||
envString += `VITE_FIREBASE_MESSAGING_SENDER_ID=${process.env.FIREBASE_MESSAGING_SENDER_ID}\n`;
|
||||
envString += `VITE_FIREBASE_APP_ID=${process.env.FIREBASE_APP_ID}\n`;
|
||||
|
||||
fs.writeFileSync('.env', envString);
|
||||
|
|
3
src/app.css
Normal file
3
src/app.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
|
@ -8,14 +8,12 @@
|
|||
<meta property="og:type" content="website" />
|
||||
<meta property="og:image" content="https://paimon.moe/paimon-og.png" />
|
||||
|
||||
%sapper.base%
|
||||
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Catamaran:wght@600;700;900&family=Poppins:wght@400;500;600&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="manifest" href="manifest.json" crossorigin="use-credentials" />
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
|
||||
<!-- <script src="https://js.sentry-cdn.com/446c4cef71a54aafb71b698555500b7d.min.js" crossorigin="anonymous"></script> -->
|
||||
<script async defer data-domain="paimon.moe" src="https://plausible.paimon.moe/js/paimonmoe.js"></script>
|
||||
|
@ -26,26 +24,14 @@
|
|||
<script src="https://www.gstatic.com/firebasejs/8.3.2/firebase-app.js"></script>
|
||||
<script src="https://www.gstatic.com/firebasejs/8.3.2/firebase-messaging.js"></script>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
html {
|
||||
height: 100%;
|
||||
background: #25294a;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Sapper creates a <script> tag containing `src/client.js`
|
||||
and anything else it needs to hydrate the app and
|
||||
initialise the router -->
|
||||
%sapper.scripts%
|
||||
|
||||
<!-- Sapper generates a <style> tag containing critical CSS
|
||||
for the current page. CSS for the rest of the app is
|
||||
lazily loaded when it precaches secondary pages -->
|
||||
%sapper.styles%
|
||||
|
||||
<!-- This contains the contents of the <svelte:head> component, if
|
||||
the current page has one -->
|
||||
%sapper.head%
|
||||
%sveltekit.head%
|
||||
|
||||
<script>
|
||||
window.AdSlots = window.AdSlots || { cmd: [], disableScripts: ['gpt'] };
|
||||
|
@ -54,8 +40,6 @@
|
|||
<script async src="https://kumo.network-n.com/dist/app.js?n=2" site="paimonmoe"></script>
|
||||
</head>
|
||||
<body class="font-body h-full bg-background-secondary">
|
||||
<!-- The application will be rendered inside this element,
|
||||
because `src/client.js` references it -->
|
||||
<div id="sapper" class="flex flex-col h-full">%sapper.html%</div>
|
||||
<div id="sapper" class="flex flex-col h-full">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,20 +0,0 @@
|
|||
import * as sapper from '@sapper/app';
|
||||
import localforage from 'localforage';
|
||||
|
||||
import { startClient } from './i18n.js';
|
||||
|
||||
console.log('localforage config');
|
||||
localforage.config({
|
||||
driver: [localforage.INDEXEDDB, localforage.LOCALSTORAGE],
|
||||
name: 'paimonmoe',
|
||||
version: 1.0,
|
||||
description: 'paimonmoe local storage',
|
||||
});
|
||||
|
||||
window.localforage = localforage;
|
||||
|
||||
startClient();
|
||||
|
||||
sapper.start({
|
||||
target: document.querySelector('#sapper'),
|
||||
});
|
|
@ -2,7 +2,7 @@
|
|||
export let type;
|
||||
export let variant;
|
||||
export let id;
|
||||
export let style;
|
||||
export let style = '';
|
||||
|
||||
let _class = '';
|
||||
export { _class as class };
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.hovered {
|
||||
@apply text-white !important;
|
||||
@apply bg-primary;
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
</script>
|
||||
|
||||
<label
|
||||
class="checkbox-wrapper flex flex-1 pl-4 items-center rounded-2xl h-14 {disabled ? 'cursor-not-allowed' : 'cursor-pointer'} {inverted
|
||||
? 'bg-item'
|
||||
: 'bg-background'} {className}"
|
||||
class="checkbox-wrapper flex flex-1 pl-4 items-center rounded-2xl h-14 {disabled
|
||||
? 'cursor-not-allowed'
|
||||
: 'cursor-pointer'} {inverted ? 'bg-item' : 'bg-background'} {className}"
|
||||
style="--bg: {inverted ? '#202442' : '#2D325A'};"
|
||||
>
|
||||
<span class="flex-1 text-white"><slot /></span>
|
||||
|
@ -21,7 +21,7 @@
|
|||
</svg>
|
||||
</label>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.checkbox {
|
||||
fill: none;
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
const { open: openModal, close: closeModal } = getContext('simple-modal');
|
||||
|
||||
const CLIENT_ID = __paimon.env.GOOGLE_DRIVE_CLIENT_ID;
|
||||
const API_KEY = __paimon.env.GOOGLE_DRIVE_API_KEY;
|
||||
const CLIENT_ID = import.meta.env.VITE_GOOGLE_DRIVE_CLIENT_ID;
|
||||
const API_KEY = import.meta.env.VITE_GOOGLE_DRIVE_API_KEY;
|
||||
const DISCOVERY_DOCS = ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'];
|
||||
const SCOPES = 'https://www.googleapis.com/auth/drive.appdata';
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.header::after {
|
||||
content: '';
|
||||
top: -40px;
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
{/if}
|
||||
{#if spin !== false}
|
||||
{#if inverse}
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
@keyframes spin-inverse {
|
||||
to {
|
||||
transform: rotate(-360deg);
|
||||
|
@ -60,7 +60,7 @@
|
|||
}
|
||||
</style>
|
||||
{:else}
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
|
@ -76,7 +76,7 @@
|
|||
{/if}
|
||||
</svg>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
|
|
|
@ -81,27 +81,6 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<!--
|
||||
$w: var(--col-width); // minmax(Min(20em, 100%), 1fr);
|
||||
$s: var(--grid-gap); // .5em;
|
||||
-->
|
||||
<style>
|
||||
:global(.__grid--masonry) {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, var(--col-width));
|
||||
grid-template-rows: masonry;
|
||||
justify-content: center;
|
||||
grid-gap: var(--grid-gap);
|
||||
padding: var(--grid-gap);
|
||||
}
|
||||
:global(.__grid--masonry > *) {
|
||||
align-self: start;
|
||||
}
|
||||
:global(.__grid--masonry.__stretch-first > *:first-child) {
|
||||
grid-column: 1/ -1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--
|
||||
An almost direct copy and paste of: https://css-tricks.com/a-lightweight-masonry-solution
|
||||
Usage:
|
||||
|
@ -124,6 +103,28 @@ $s: var(--grid-gap); // .5em;
|
|||
<div
|
||||
bind:this={masonryElement}
|
||||
class={`__grid--masonry ${stretchFirst ? '__stretch-first' : ''}`}
|
||||
style={`--grid-gap: ${gridGap}; --col-width: ${colWidth};`}>
|
||||
style={`--grid-gap: ${gridGap}; --col-width: ${colWidth};`}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<!--
|
||||
$w: var(--col-width); // minmax(Min(20em, 100%), 1fr);
|
||||
$s: var(--grid-gap); // .5em;
|
||||
-->
|
||||
<style lang="postcss">
|
||||
:global(.__grid--masonry) {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, var(--col-width));
|
||||
grid-template-rows: masonry;
|
||||
justify-content: center;
|
||||
grid-gap: var(--grid-gap);
|
||||
padding: var(--grid-gap);
|
||||
}
|
||||
:global(.__grid--masonry > *) {
|
||||
align-self: start;
|
||||
}
|
||||
:global(.__grid--masonry.__stretch-first > *:first-child) {
|
||||
grid-column: 1/ -1;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -145,7 +145,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.hovered {
|
||||
@apply text-white !important;
|
||||
@apply bg-primary;
|
||||
|
|
51
src/components/ServiceWorker.svelte
Normal file
51
src/components/ServiceWorker.svelte
Normal file
|
@ -0,0 +1,51 @@
|
|||
<script>
|
||||
import { getContext, onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
import UpdateModal from './UpdateModal.svelte';
|
||||
|
||||
const { open, close } = getContext('simple-modal');
|
||||
let broadcastChannel;
|
||||
|
||||
page.subscribe((p) => {
|
||||
if (broadcastChannel) {
|
||||
broadcastChannel.postMessage({
|
||||
type: 'fetch-doc',
|
||||
path: p.url.pathname,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
async function refreshUpdate() {
|
||||
open(
|
||||
UpdateModal,
|
||||
{
|
||||
close,
|
||||
},
|
||||
{
|
||||
closeButton: false,
|
||||
styleWindow: { background: '#25294A', width: '500px' },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if ('serviceWorker' in navigator) {
|
||||
broadcastChannel = new BroadcastChannel('paimonmoe-sw');
|
||||
broadcastChannel.addEventListener('message', (event) => {
|
||||
if (event.data.type === 'update') refreshUpdate();
|
||||
});
|
||||
|
||||
navigator.serviceWorker.register('/service-worker.js').then(
|
||||
function () {
|
||||
console.log('service worker registration succeeded');
|
||||
},
|
||||
function (error) {
|
||||
console.log('service worker registration failed:', error);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
console.log('service workers are not supported');
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import { fly } from 'svelte/transition';
|
||||
import { getContext } from 'svelte';
|
||||
import { mdiCloseCircle } from '@mdi/js';
|
||||
import { locale, t } from 'svelte-i18n';
|
||||
|
||||
|
@ -30,7 +29,8 @@
|
|||
{ id: 'pt', label: 'Português' },
|
||||
{ id: 'ru', label: 'Русский' },
|
||||
];
|
||||
$: currentLocale = languages.find((e) => e.id === $locale.substring(0, 2)) || { id: 'en', label: 'English' };
|
||||
$: currentLocale =
|
||||
$locale !== null ? languages.find((e) => e.id === $locale.substring(0, 2)) || { id: 'en', label: 'English' } : '';
|
||||
$: locales = languages.filter((e) => e.id !== currentLocale.id);
|
||||
|
||||
function close() {
|
||||
|
@ -60,7 +60,7 @@
|
|||
{/if}
|
||||
<SidebarItem
|
||||
on:clicked={close}
|
||||
active={segment === undefined}
|
||||
active={segment === ''}
|
||||
image="/images/home.png"
|
||||
label={$t('sidebar.home')}
|
||||
href="/"
|
||||
|
@ -160,7 +160,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.paimon-bg::after {
|
||||
content: '';
|
||||
top: -50px;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</div>
|
||||
</a>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.active {
|
||||
@apply bg-primary;
|
||||
@apply bg-opacity-75;
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.active {
|
||||
@apply bg-primary;
|
||||
@apply bg-opacity-75;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.container {
|
||||
height: fit-content;
|
||||
}
|
||||
|
@ -36,4 +36,4 @@
|
|||
min-height: 100px;
|
||||
@apply p-4;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<i on:mouseover={mouseOver} on:mouseleave={mouseLeave} on:mousemove={mouseMove}>
|
||||
<i on:mouseover={mouseOver} on:focus={mouseOver} on:mouseleave={mouseLeave} on:mousemove={mouseMove}>
|
||||
<slot />
|
||||
</i>
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
|||
<div style="top: {y}px; left: {x}px;" class="tooltip">{title}</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.tooltip {
|
||||
@apply p-2 absolute rounded-xl bg-gray-400 border border-gray-800;
|
||||
@apply text-sm text-background z-10;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<span on:mouseover={mouseOver} on:mouseleave={mouseLeave} bind:this={ref}>
|
||||
<span on:mouseover={mouseOver} on:focus={mouseOver} on:mouseleave={mouseLeave} bind:this={ref}>
|
||||
<slot />
|
||||
</span>
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
|||
<div style="top: {y}px; left: {x}px;" class="tooltip">{title}</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.tooltip {
|
||||
@apply p-2 fixed rounded-xl bg-gray-400 border border-gray-800;
|
||||
@apply text-sm text-background z-10;
|
||||
|
|
26
src/components/UpdateModal.svelte
Normal file
26
src/components/UpdateModal.svelte
Normal file
|
@ -0,0 +1,26 @@
|
|||
<script>
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
import Button from '../components/Button.svelte';
|
||||
|
||||
export let close;
|
||||
|
||||
function reload() {
|
||||
window.location.reload();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<p class="text-white font-bold mb-1 text-lg">{$t('update.newUpdate')}</p>
|
||||
<p class="text-gray-400 mb-4">{$t('update.updateRefresh')}</p>
|
||||
<div class="rounded-xl bg-background p-4 mb-4">
|
||||
<p class="text-gray-200">{$t('update.whatsNew')}</p>
|
||||
<ul class="list-disc text-white list-inside">
|
||||
<li>Bug Fixes</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="flex justify-end space-x-2">
|
||||
<Button on:click={close}>{$t('update.later')}</Button>
|
||||
<Button on:click={reload} color="green">{$t('update.refresh')}</Button>
|
||||
</div>
|
||||
</div>
|
|
@ -1,171 +1,169 @@
|
|||
<script>
|
||||
import { onMount, tick } from 'svelte';
|
||||
import { onMount, tick } from 'svelte';
|
||||
|
||||
// props
|
||||
export let items;
|
||||
export let height = '100%';
|
||||
export let itemHeight = undefined;
|
||||
// props
|
||||
export let items;
|
||||
export let height = '100%';
|
||||
export let itemHeight = undefined;
|
||||
|
||||
let foo;
|
||||
let foo;
|
||||
|
||||
// read-only, but visible to consumers via bind:start
|
||||
export let start = 0;
|
||||
export let end = 0;
|
||||
// read-only, but visible to consumers via bind:start
|
||||
export let start = 0;
|
||||
export let end = 0;
|
||||
|
||||
// local state
|
||||
let height_map = [];
|
||||
let rows;
|
||||
let viewport;
|
||||
let contents;
|
||||
let viewport_height = 0;
|
||||
let visible;
|
||||
let mounted;
|
||||
// local state
|
||||
let height_map = [];
|
||||
let rows;
|
||||
let viewport;
|
||||
let contents;
|
||||
let viewport_height = 0;
|
||||
let visible;
|
||||
let mounted;
|
||||
|
||||
let top = 0;
|
||||
let bottom = 0;
|
||||
let average_height;
|
||||
let top = 0;
|
||||
let bottom = 0;
|
||||
let average_height;
|
||||
|
||||
$: visible = items.slice(start, end).map((data, i) => {
|
||||
return { index: i + start, data };
|
||||
});
|
||||
$: visible = items.slice(start, end).map((data, i) => {
|
||||
return { index: i + start, data };
|
||||
});
|
||||
|
||||
// whenever `items` changes, invalidate the current heightmap
|
||||
$: if (mounted) refresh(items, viewport_height, itemHeight);
|
||||
// whenever `items` changes, invalidate the current heightmap
|
||||
$: if (mounted) refresh(items, viewport_height, itemHeight);
|
||||
|
||||
async function refresh(items, viewport_height, itemHeight) {
|
||||
const { scrollTop } = viewport;
|
||||
async function refresh(items, viewport_height, itemHeight) {
|
||||
const { scrollTop } = viewport;
|
||||
|
||||
await tick(); // wait until the DOM is up to date
|
||||
await tick(); // wait until the DOM is up to date
|
||||
|
||||
let content_height = top - scrollTop;
|
||||
let i = start;
|
||||
let content_height = top - scrollTop;
|
||||
let i = start;
|
||||
|
||||
while (content_height < viewport_height && i < items.length) {
|
||||
let row = rows[i - start];
|
||||
while (content_height < viewport_height && i < items.length) {
|
||||
let row = rows[i - start];
|
||||
|
||||
if (!row) {
|
||||
end = i + 1;
|
||||
await tick(); // render the newly visible row
|
||||
row = rows[i - start];
|
||||
}
|
||||
if (!row) {
|
||||
end = i + 1;
|
||||
await tick(); // render the newly visible row
|
||||
row = rows[i - start];
|
||||
}
|
||||
|
||||
const row_height = height_map[i] = itemHeight || row.offsetHeight;
|
||||
content_height += row_height;
|
||||
i += 1;
|
||||
}
|
||||
const row_height = (height_map[i] = itemHeight || row.offsetHeight);
|
||||
content_height += row_height;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
end = i;
|
||||
end = i;
|
||||
|
||||
const remaining = items.length - end;
|
||||
average_height = (top + content_height) / end;
|
||||
const remaining = items.length - end;
|
||||
average_height = (top + content_height) / end;
|
||||
|
||||
bottom = remaining * average_height;
|
||||
bottom = remaining * average_height;
|
||||
height_map.length = items.length;
|
||||
|
||||
|
||||
viewport.scrollTo(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
async function handle_scroll() {
|
||||
const { scrollTop } = viewport;
|
||||
async function handle_scroll() {
|
||||
const { scrollTop } = viewport;
|
||||
|
||||
const old_start = start;
|
||||
const old_start = start;
|
||||
|
||||
for (let v = 0; v < rows.length; v += 1) {
|
||||
height_map[start + v] = itemHeight || rows[v].offsetHeight;
|
||||
}
|
||||
for (let v = 0; v < rows.length; v += 1) {
|
||||
height_map[start + v] = itemHeight || rows[v].offsetHeight;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
let y = 0;
|
||||
let i = 0;
|
||||
let y = 0;
|
||||
|
||||
while (i < items.length) {
|
||||
const row_height = height_map[i] || average_height;
|
||||
if (y + row_height > scrollTop) {
|
||||
start = i;
|
||||
top = y;
|
||||
while (i < items.length) {
|
||||
const row_height = height_map[i] || average_height;
|
||||
if (y + row_height > scrollTop) {
|
||||
start = i;
|
||||
top = y;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
y += row_height;
|
||||
i += 1;
|
||||
}
|
||||
y += row_height;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
while (i < items.length) {
|
||||
y += height_map[i] || average_height;
|
||||
i += 1;
|
||||
while (i < items.length) {
|
||||
y += height_map[i] || average_height;
|
||||
i += 1;
|
||||
|
||||
if (y > scrollTop + viewport_height) break;
|
||||
}
|
||||
if (y > scrollTop + viewport_height) break;
|
||||
}
|
||||
|
||||
end = i;
|
||||
end = i;
|
||||
|
||||
const remaining = items.length - end;
|
||||
average_height = y / end;
|
||||
const remaining = items.length - end;
|
||||
average_height = y / end;
|
||||
|
||||
while (i < items.length) height_map[i++] = average_height;
|
||||
bottom = remaining * average_height;
|
||||
while (i < items.length) height_map[i++] = average_height;
|
||||
bottom = remaining * average_height;
|
||||
|
||||
// prevent jumping if we scrolled up into unknown territory
|
||||
if (start < old_start) {
|
||||
await tick();
|
||||
// prevent jumping if we scrolled up into unknown territory
|
||||
if (start < old_start) {
|
||||
await tick();
|
||||
|
||||
let expected_height = 0;
|
||||
let actual_height = 0;
|
||||
let expected_height = 0;
|
||||
let actual_height = 0;
|
||||
|
||||
for (let i = start; i < old_start; i +=1) {
|
||||
if (rows[i - start]) {
|
||||
expected_height += height_map[i];
|
||||
actual_height += itemHeight || rows[i - start].offsetHeight;
|
||||
}
|
||||
}
|
||||
for (let i = start; i < old_start; i += 1) {
|
||||
if (rows[i - start]) {
|
||||
expected_height += height_map[i];
|
||||
actual_height += itemHeight || rows[i - start].offsetHeight;
|
||||
}
|
||||
}
|
||||
|
||||
const d = actual_height - expected_height;
|
||||
viewport.scrollTo(0, scrollTop + d);
|
||||
}
|
||||
const d = actual_height - expected_height;
|
||||
viewport.scrollTo(0, scrollTop + d);
|
||||
}
|
||||
|
||||
// TODO if we overestimated the space these
|
||||
// rows would occupy we may need to add some
|
||||
// more. maybe we can just call handle_scroll again?
|
||||
}
|
||||
// TODO if we overestimated the space these
|
||||
// rows would occupy we may need to add some
|
||||
// more. maybe we can just call handle_scroll again?
|
||||
}
|
||||
|
||||
// trigger initial refresh
|
||||
onMount(() => {
|
||||
rows = contents.getElementsByTagName('svelte-virtual-list-row');
|
||||
mounted = true;
|
||||
});
|
||||
// trigger initial refresh
|
||||
onMount(() => {
|
||||
rows = contents.getElementsByTagName('svelte-virtual-list-row');
|
||||
mounted = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
svelte-virtual-list-viewport {
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling:touch;
|
||||
display: block;
|
||||
}
|
||||
|
||||
svelte-virtual-list-contents, svelte-virtual-list-row {
|
||||
display: block;
|
||||
}
|
||||
|
||||
svelte-virtual-list-row {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
<svelte-virtual-list-viewport
|
||||
bind:this={viewport}
|
||||
bind:offsetHeight={viewport_height}
|
||||
on:scroll={handle_scroll}
|
||||
style="height: {height};"
|
||||
bind:this={viewport}
|
||||
bind:offsetHeight={viewport_height}
|
||||
on:scroll={handle_scroll}
|
||||
style="height: {height};"
|
||||
>
|
||||
<svelte-virtual-list-contents
|
||||
bind:this={contents}
|
||||
style="padding-top: {top}px; padding-bottom: {bottom}px;"
|
||||
>
|
||||
{#each visible as row (row.index)}
|
||||
<svelte-virtual-list-row>
|
||||
<slot item={row.data} index={row.index}>Missing template</slot>
|
||||
</svelte-virtual-list-row>
|
||||
{/each}
|
||||
</svelte-virtual-list-contents>
|
||||
</svelte-virtual-list-viewport>
|
||||
<svelte-virtual-list-contents bind:this={contents} style="padding-top: {top}px; padding-bottom: {bottom}px;">
|
||||
{#each visible as row (row.index)}
|
||||
<svelte-virtual-list-row>
|
||||
<slot item={row.data} index={row.index}>Missing template</slot>
|
||||
</svelte-virtual-list-row>
|
||||
{/each}
|
||||
</svelte-virtual-list-contents>
|
||||
</svelte-virtual-list-viewport>
|
||||
|
||||
<style lang="postcss">
|
||||
svelte-virtual-list-viewport {
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
display: block;
|
||||
}
|
||||
|
||||
svelte-virtual-list-contents,
|
||||
svelte-virtual-list-row {
|
||||
display: block;
|
||||
}
|
||||
|
||||
svelte-virtual-list-row {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -168,7 +168,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.hovered {
|
||||
@apply text-white !important;
|
||||
@apply bg-primary;
|
||||
|
|
|
@ -190,7 +190,7 @@
|
|||
|
||||
try {
|
||||
const res = await fetchRetry(
|
||||
`${__paimon.env.API_HOST}/corsproxy`,
|
||||
`${import.meta.env.VITE_API_HOST}/corsproxy`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
|
@ -527,7 +527,7 @@
|
|||
</td>
|
||||
<td class="border-b border-gray-700 py-1">
|
||||
{#if wishes[code] !== undefined}
|
||||
<span class="text-white mr-2 whitespace-no-wrap">
|
||||
<span class="text-white mr-2 whitespace-nowrap">
|
||||
<Icon size={0.5} path={mdiClose} />
|
||||
{numberFormat.format(wishes[code].length)}
|
||||
</span>
|
||||
|
@ -585,10 +585,10 @@
|
|||
{#if wishes[code] !== undefined}
|
||||
<tr>
|
||||
<td class="border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap">{type.name} Banner</span>
|
||||
<span class="text-white mr-2 whitespace-nowrap">{type.name} Banner</span>
|
||||
</td>
|
||||
<td class="border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap">
|
||||
<span class="text-white mr-2 whitespace-nowrap">
|
||||
<Icon size={0.5} path={mdiClose} />
|
||||
{numberFormat.format(wishes[code].length)}
|
||||
</span>
|
||||
|
@ -788,7 +788,7 @@
|
|||
<div class="pb-16 md:pb-0" />
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.pill {
|
||||
@apply rounded-2xl;
|
||||
@apply border-2;
|
||||
|
|
|
@ -2,12 +2,12 @@ importScripts('https://www.gstatic.com/firebasejs/8.3.2/firebase-app.js');
|
|||
importScripts('https://www.gstatic.com/firebasejs/8.3.2/firebase-messaging.js');
|
||||
|
||||
const firebaseConfig = {
|
||||
apiKey: __paimon.env.FIREBASE_API_KEY,
|
||||
authDomain: __paimon.env.FIREBASE_AUTH_DOMAIN,
|
||||
projectId: __paimon.env.FIREBASE_PROJECT_ID,
|
||||
storageBucket: __paimon.env.FIREBASE_STORAGE_BUCKET,
|
||||
messagingSenderId: __paimon.env.FIREBASE_MESSAGING_SENDER_ID,
|
||||
appId: __paimon.env.FIREBASE_APP_ID,
|
||||
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
|
||||
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
|
||||
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
|
||||
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
|
||||
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
|
||||
appId: import.meta.env.VITE_FIREBASE_APP_ID,
|
||||
};
|
||||
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
|
|
|
@ -7,7 +7,7 @@ const bannerCategories = ['beginners', 'standard', 'character-event', 'weapon-ev
|
|||
|
||||
async function sendWish(data) {
|
||||
try {
|
||||
await fetch(`${__paimon.env.API_HOST}/wish`, {
|
||||
await fetch(`${import.meta.env.VITE_API_HOST}/wish`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
|
@ -19,7 +19,7 @@ async function sendWish(data) {
|
|||
|
||||
async function sendWishTotal(data) {
|
||||
try {
|
||||
await fetch(`${__paimon.env.API_HOST}/wish/total`, {
|
||||
await fetch(`${import.meta.env.VITE_API_HOST}/wish/total`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
|
@ -31,7 +31,7 @@ async function sendWishTotal(data) {
|
|||
|
||||
async function sendWishConstellation(data) {
|
||||
try {
|
||||
await fetch(`${__paimon.env.API_HOST}/wish/constellation`, {
|
||||
await fetch(`${import.meta.env.VITE_API_HOST}/wish/constellation`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
|
|
67
src/i18n.js
67
src/i18n.js
|
@ -1,23 +1,22 @@
|
|||
import dayjs from 'dayjs';
|
||||
import { register, addMessages, init, getLocaleFromNavigator, locale as $locale } from 'svelte-i18n';
|
||||
import { browser } from '$app/env';
|
||||
|
||||
import en from './locales/en.json';
|
||||
import enItems from './locales/items/en.json';
|
||||
|
||||
const INIT_OPTIONS = {
|
||||
fallbackLocale: 'en',
|
||||
initialLocale: null,
|
||||
initialLocale: 'en',
|
||||
};
|
||||
|
||||
let currentLocale = null;
|
||||
|
||||
let isLoaded = false;
|
||||
$locale.subscribe((value) => {
|
||||
if (value == null) return;
|
||||
if (value === null) return;
|
||||
|
||||
currentLocale = value;
|
||||
if (isLoaded) localStorage.setItem('locale', value);
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('locale', value);
|
||||
dayjsLocales[value]().then(() => dayjs.locale(value));
|
||||
}
|
||||
});
|
||||
|
@ -66,51 +65,27 @@ const dayjsLocales = {
|
|||
vi: () => import('dayjs/locale/vi'),
|
||||
};
|
||||
|
||||
export function startClient() {
|
||||
let used = 'en';
|
||||
const savedLocale = localStorage.getItem('locale');
|
||||
const detectedLocale = getLocaleFromNavigator().substring(0, 2);
|
||||
if (savedLocale !== null) {
|
||||
if (!supportedLanguage.includes(savedLocale)) {
|
||||
localStorage.setItem('locale', 'en');
|
||||
} else {
|
||||
used = savedLocale;
|
||||
}
|
||||
} else if (supportedLanguage.includes(detectedLocale)) {
|
||||
used = detectedLocale;
|
||||
}
|
||||
|
||||
export async function startClient() {
|
||||
init({
|
||||
...INIT_OPTIONS,
|
||||
initialLocale: used,
|
||||
});
|
||||
}
|
||||
|
||||
const DOCUMENT_REGEX = /(^([^.?#@]+)?([?#](.+)?)?|service-worker.*?\.html)$/;
|
||||
export function i18nMiddleware() {
|
||||
init(INIT_OPTIONS);
|
||||
|
||||
return (req, res, next) => {
|
||||
const isDocument = DOCUMENT_REGEX.test(req.originalUrl);
|
||||
if (!isDocument) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
let locale = 'en';
|
||||
if (req.headers['accept-language']) {
|
||||
const headerLang = req.headers['accept-language'].split(',')[0].trim();
|
||||
if (headerLang.length > 1) {
|
||||
locale = headerLang;
|
||||
if (browser) {
|
||||
let used = 'en';
|
||||
const savedLocale = localStorage.getItem('locale');
|
||||
const detectedLocale = getLocaleFromNavigator().substring(0, 2);
|
||||
if (savedLocale !== null) {
|
||||
if (!supportedLanguage.includes(savedLocale)) {
|
||||
localStorage.setItem('locale', 'en');
|
||||
} else {
|
||||
used = savedLocale;
|
||||
}
|
||||
} else {
|
||||
locale = INIT_OPTIONS.initialLocale || INIT_OPTIONS.fallbackLocale;
|
||||
} else if (supportedLanguage.includes(detectedLocale)) {
|
||||
used = detectedLocale;
|
||||
}
|
||||
|
||||
if (locale != null && locale !== currentLocale) {
|
||||
$locale.set(locale.substring(0, 2));
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
$locale.set(used);
|
||||
isLoaded = true;
|
||||
console.log('change i18n', used);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
"message": "Your best Genshin Impact companion! Paimon.moe helps you plan what to farm with an ascension calculator, and it also tracks your progress with a todo list and a wish counter.",
|
||||
"visitor": "{count} visitors in the last 7 days",
|
||||
"banner": {
|
||||
"featured": [
|
||||
"Eula"
|
||||
],
|
||||
"summoned": "Summoned",
|
||||
"percentage": "from all {rarity}",
|
||||
"avg": "Pity average",
|
||||
|
@ -143,10 +140,7 @@
|
|||
"manualButton": "Enable Manual Input",
|
||||
"errorBanner": "Banner time mismatch! Please adjust your server on the settings page. Still not working? Please leave a message on Discord 😅",
|
||||
"globalWishTally": "Global Wish Stats",
|
||||
"pityTooltip": [
|
||||
"Shows your current {rarity} pity",
|
||||
"{count} pulls to guaranteed {rarity}"
|
||||
],
|
||||
"pityTooltip": ["Shows your current {rarity} pity", "{count} pulls to guaranteed {rarity}"],
|
||||
"import": {
|
||||
"title": "Import Wish History",
|
||||
"faqsButton": "FAQ - READ FIRST",
|
||||
|
@ -182,11 +176,7 @@
|
|||
"server": "Select your server:",
|
||||
"wishTallyCheck": "Submit pity for global wish stats",
|
||||
"wishTally": "We are doing a global wish stats! You can submit your wish stats to participate. All pity data will be aggregated to know what is the average pity of paimon.moe users.",
|
||||
"wishTallyCollected": [
|
||||
"What will be collected:",
|
||||
"and",
|
||||
"pity from your wish history"
|
||||
],
|
||||
"wishTallyCollected": ["What will be collected:", "and", "pity from your wish history"],
|
||||
"forceUpdateCheck": "Force update wish history (enable only if your wish history is not updating)",
|
||||
"header": [
|
||||
"Import and backup your Genshin Impact wish history to keep it for more than 6 months. It also automatically tracks your pity and statistics about your wishes!",
|
||||
|
@ -364,11 +354,7 @@
|
|||
"exportFinish": "Export success, please wait until your browser downloads the file!",
|
||||
"wishTallyTitle": "Submit Wish Stats",
|
||||
"wishTally": "We are doing a global wish stats! You can submit your wish stats to participate. All pity data will be aggregated to know what is the average pity of paimon.moe users.",
|
||||
"wishTallyCollected": [
|
||||
"What will be collected:",
|
||||
"and",
|
||||
"pity from your wish history"
|
||||
],
|
||||
"wishTallyCollected": ["What will be collected:", "and", "pity from your wish history"],
|
||||
"wishTallySubmit": "Submit Wish Stats",
|
||||
"wishTallyThankyou": "Thank you for participating!",
|
||||
"manualTitle": "Manual Input Settings",
|
||||
|
@ -380,22 +366,13 @@
|
|||
"subtitle": "After a 1x Wish:",
|
||||
"pressWhenYouGet": "Press {button} when you get {rarity}★",
|
||||
"p1": "It will automatically add the lifetime pulls, 5★, and 4★ pity",
|
||||
"p2": [
|
||||
"When the",
|
||||
"pity reaches 10, it will automatically be reset to 0"
|
||||
],
|
||||
"p3": [
|
||||
"When the",
|
||||
"pity reaches 90, it will automatically be reset to 0"
|
||||
],
|
||||
"p2": ["When the", "pity reaches 10, it will automatically be reset to 0"],
|
||||
"p3": ["When the", "pity reaches 90, it will automatically be reset to 0"],
|
||||
"p4": [
|
||||
"After a 10x Wish, press",
|
||||
"but keep in mind that the pity counter might not be accurate, because there is no way to tell when the drop occured (maybe you got it on the 1st or even the 10th pull). To ensure that the counter is still accurate, you need to check the history table and add it one-by-one like you do 1x Wishes."
|
||||
],
|
||||
"p5": [
|
||||
"You can also press the",
|
||||
"button to edit the values manually!"
|
||||
],
|
||||
"p5": ["You can also press the", "button to edit the values manually!"],
|
||||
"p6": "Press the arrow on the bottom to see your pulls' details. A popup will show up when you get a 5★ or 4★. You can also add or edit the table manually."
|
||||
}
|
||||
},
|
||||
|
@ -535,11 +512,7 @@
|
|||
"calculateTalent": "Calculate Talent Material?",
|
||||
"inputTalentLevel": "Input the 1st, 2nd & 3rd current talent level",
|
||||
"inputTalentNotice": "If it has a different color, subtract it by 3",
|
||||
"inputTalent": [
|
||||
"1st talent lvl",
|
||||
"2nd talent lvl",
|
||||
"3rd talent lvl"
|
||||
],
|
||||
"inputTalent": ["1st talent lvl", "2nd talent lvl", "3rd talent lvl"],
|
||||
"talentToLevel": "to level",
|
||||
"calculate": "Calculate",
|
||||
"unknownInformation": "There are some unknown information",
|
||||
|
@ -548,11 +521,7 @@
|
|||
"expWasted": "EXP Wasted",
|
||||
"addToTodo": "Add to Todo List",
|
||||
"addedToTodo": "Added to Todo List",
|
||||
"talent": [
|
||||
"Attack",
|
||||
"Skill",
|
||||
"Burst"
|
||||
]
|
||||
"talent": ["Attack", "Skill", "Burst"]
|
||||
},
|
||||
"expTable": {
|
||||
"level": "Level",
|
||||
|
@ -644,10 +613,7 @@
|
|||
"todo": {
|
||||
"title": "Todo List",
|
||||
"summary": "Summary",
|
||||
"empty": [
|
||||
"Nothing to do yet 😀",
|
||||
"Add some from the Items page or the Calculator!"
|
||||
],
|
||||
"empty": ["Nothing to do yet 😀", "Add some from the Items page or the Calculator!"],
|
||||
"farmableToday": "Farmable Today",
|
||||
"resin": "Resin needed",
|
||||
"based": "Based on AR:{ar} and WL:{wl}",
|
||||
|
@ -962,5 +928,12 @@
|
|||
"common": {
|
||||
"dataSynced": "Data has been synced!",
|
||||
"driveError": "Drive sync not available right now 😔"
|
||||
},
|
||||
"update": {
|
||||
"newUpdate": "Paimon.moe has a new update!",
|
||||
"updateRefresh": "Click refresh to get the new update",
|
||||
"whatsNew": "What's new",
|
||||
"later": "Later",
|
||||
"refresh": "Refresh"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,21 @@
|
|||
<script context="module">
|
||||
export function load({ error, status }) {
|
||||
return {
|
||||
props: {
|
||||
status,
|
||||
error,
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let status;
|
||||
export let error;
|
||||
|
||||
const dev = process.env.NODE_ENV === 'development';
|
||||
const dev = import.meta.env.DEV;
|
||||
|
||||
let refreshUrl;
|
||||
|
||||
|
@ -39,7 +50,7 @@
|
|||
>
|
||||
Click here to refresh
|
||||
</a>
|
||||
<p class="text-white text-xl mt-2 text-center">Or you can try refresh the page by pressing CTRL+F5</p>
|
||||
<p class="text-white text-xl mt-2 text-center">Or you can try refresh the page by pressing CTRL+SHIFT+R</p>
|
||||
<p class="text-white text-xl mt-2 text-center">
|
||||
You might also want to check your extension, like adblock, it sometimes wrongly block the script needed for the
|
||||
site.
|
|
@ -1,21 +1,17 @@
|
|||
<script context="module">
|
||||
import { waitLocale } from 'svelte-i18n';
|
||||
|
||||
export async function preload() {
|
||||
return waitLocale();
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import '../app.css';
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { derived } from 'svelte/store';
|
||||
import { stores } from '@sapper/app';
|
||||
import { fade } from 'svelte/transition';
|
||||
import localforage from 'localforage';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { startClient } from '../i18n.js';
|
||||
import { navigating, page } from '$app/stores';
|
||||
|
||||
import Modal from 'svelte-simple-modal';
|
||||
import { mdiDiscord, mdiFacebook, mdiGithub, mdiReddit, mdiTwitter } from '@mdi/js';
|
||||
|
||||
import Tailwind from '../components/Tailwindcss.svelte';
|
||||
import Sidebar from '../components/Sidebar/Sidebar.svelte';
|
||||
import Header from '../components/Header.svelte';
|
||||
import DataSync from '../components/DataSync.svelte';
|
||||
|
@ -26,28 +22,35 @@
|
|||
import SettingData from '../components/SettingData.svelte';
|
||||
import Toast from '../components/Toast.svelte';
|
||||
import Icon from '../components/Icon.svelte';
|
||||
import { mdiDiscord, mdiFacebook, mdiGithub, mdiReddit, mdiTelegram, mdiTwitter } from '@mdi/js';
|
||||
import ServiceWorker from '../components/ServiceWorker.svelte';
|
||||
|
||||
export let segment;
|
||||
|
||||
const { preloading, page } = stores();
|
||||
const delayedPreloading = derived(preloading, (currentPreloading, set) => {
|
||||
setTimeout(() => set(currentPreloading), 250);
|
||||
const delayedPreloading = derived(navigating, (_, set) => {
|
||||
set(true);
|
||||
setTimeout(() => set(true), 250);
|
||||
});
|
||||
|
||||
startClient();
|
||||
|
||||
page.subscribe(() => {
|
||||
try {
|
||||
window.reloadAdSlots();
|
||||
} catch (error) {}
|
||||
});
|
||||
|
||||
// check local storage save on load
|
||||
onMount(async () => {
|
||||
await checkLocalSave();
|
||||
|
||||
page.subscribe(() => {
|
||||
try {
|
||||
window.reloadAdSlots();
|
||||
} catch (error) {}
|
||||
console.log('localforage config');
|
||||
localforage.config({
|
||||
driver: [localforage.INDEXEDDB, localforage.LOCALSTORAGE],
|
||||
name: 'paimonmoe',
|
||||
version: 1.0,
|
||||
description: 'paimonmoe local storage',
|
||||
});
|
||||
window.localforage = localforage;
|
||||
await checkLocalSave();
|
||||
});
|
||||
</script>
|
||||
|
||||
<Tailwind />
|
||||
$: segment = $page.url.pathname.substring(1).split('/')[0];
|
||||
</script>
|
||||
|
||||
<Header />
|
||||
<Modal>
|
||||
|
@ -63,8 +66,9 @@
|
|||
<slot />
|
||||
</main>
|
||||
</DataSync>
|
||||
<ServiceWorker />
|
||||
</Modal>
|
||||
{#if $preloading && $delayedPreloading}
|
||||
{#if $navigating && $delayedPreloading}
|
||||
<div transition:fade class="loading-bar" />
|
||||
{/if}
|
||||
<div class="lg:ml-64 px-4 md:px-8 py-8 flex flex-col md:pb-24">
|
||||
|
@ -81,18 +85,20 @@
|
|||
<span class="text-gray-500">{$t('footer.community')}</span>
|
||||
<div>
|
||||
<a
|
||||
class="text-gray-400 hover:text-primary whitespace-no-wrap"
|
||||
class="text-gray-400 hover:text-primary whitespace-nowrap"
|
||||
href="https://github.com/MadeBaruna/paimon-moe"
|
||||
target="_blank"
|
||||
>
|
||||
<Icon path={mdiGithub} size={1} /> {$t('footer.link.github')}
|
||||
<Icon path={mdiGithub} size={1} />
|
||||
{$t('footer.link.github')}
|
||||
</a>
|
||||
<a
|
||||
class="text-gray-400 hover:text-primary whitespace-no-wrap"
|
||||
class="text-gray-400 hover:text-primary whitespace-nowrap"
|
||||
href="https://twitter.com/MadeBaruna"
|
||||
target="_blank"
|
||||
>
|
||||
<Icon path={mdiTwitter} size={1} /> {$t('footer.link.devTwitter')}
|
||||
<Icon path={mdiTwitter} size={1} />
|
||||
{$t('footer.link.devTwitter')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -100,25 +106,28 @@
|
|||
<span class="text-gray-500">{$t('footer.official')}</span>
|
||||
<div>
|
||||
<a
|
||||
class="text-gray-400 hover:text-primary mr-1 whitespace-no-wrap"
|
||||
class="text-gray-400 hover:text-primary mr-1 whitespace-nowrap"
|
||||
href="https://discord.gg/4nbWsCGjjE"
|
||||
target="_blank"
|
||||
>
|
||||
<Icon path={mdiDiscord} size={1} /> {$t('footer.link.discord')}
|
||||
<Icon path={mdiDiscord} size={1} />
|
||||
{$t('footer.link.discord')}
|
||||
</a>
|
||||
<a
|
||||
class="text-gray-400 hover:text-primary mr-1 whitespace-no-wrap"
|
||||
class="text-gray-400 hover:text-primary mr-1 whitespace-nowrap"
|
||||
href="https://www.facebook.com/Genshinimpact/"
|
||||
target="_blank"
|
||||
>
|
||||
<Icon path={mdiFacebook} size={1} /> {$t('footer.link.facebook')}
|
||||
<Icon path={mdiFacebook} size={1} />
|
||||
{$t('footer.link.facebook')}
|
||||
</a>
|
||||
<a
|
||||
class="text-gray-400 hover:text-primary whitespace-no-wrap"
|
||||
class="text-gray-400 hover:text-primary whitespace-nowrap"
|
||||
href="https://www.reddit.com/r/Genshin_Impact/"
|
||||
target="_blank"
|
||||
>
|
||||
<Icon path={mdiReddit} size={1} /> {$t('footer.link.reddit')}
|
||||
<Icon path={mdiReddit} size={1} />
|
||||
{$t('footer.link.reddit')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -132,7 +141,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.loading-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
|
@ -37,7 +37,7 @@
|
|||
let user = '';
|
||||
|
||||
async function getData() {
|
||||
const url = new URL(`${__paimon.env.API_HOST}/wish`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/wish`);
|
||||
const query = new URLSearchParams({ banner: bannerId });
|
||||
url.search = query.toString();
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
import { t } from 'svelte-i18n';
|
||||
|
||||
import { characters } from '../../data/characters';
|
||||
import { builds } from '../../data/build';
|
||||
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
const promoted = ['kaedehara_kazuha', 'shikanoin_heizou'];
|
||||
export let builds;
|
||||
const promoted = Object.keys(builds);
|
||||
let current = 0;
|
||||
|
||||
async function change(index) {
|
||||
|
@ -121,7 +121,7 @@ bg-background-secondary rounded-xl py-2 px-4 hover:bg-background transition-colo
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.pill {
|
||||
@apply rounded-2xl;
|
||||
@apply border-2;
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
<div class="flex flex-col">
|
||||
{#each upcoming as item}
|
||||
<div class="pl-2 pr-1 py-1 rounded-xl mb-1 flex" style="background: {item.color};">
|
||||
<span class="whitespace-no-wrap overflow-x-hidden flex-1 mr-1 text-sm" style="text-overflow: ellipsis;">
|
||||
<span class="whitespace-nowrap overflow-x-hidden flex-1 mr-1 text-sm" style="text-overflow: ellipsis;">
|
||||
{item.name}
|
||||
</span>
|
||||
<span class="bg-black bg-opacity-50 rounded-xl px-2 text-white text-sm">{item.time}</span>
|
||||
|
@ -97,7 +97,7 @@
|
|||
<div class="flex flex-col">
|
||||
{#each current as item}
|
||||
<div class="pl-2 pr-1 py-1 rounded-xl mb-1 flex" style="background: {item.color};">
|
||||
<span class="whitespace-no-wrap overflow-x-hidden flex-1 mr-1 text-sm" style="text-overflow: ellipsis;">
|
||||
<span class="whitespace-nowrap overflow-x-hidden flex-1 mr-1 text-sm" style="text-overflow: ellipsis;">
|
||||
{item.name}
|
||||
</span>
|
||||
<span class="bg-black bg-opacity-50 rounded-xl px-2 text-white text-sm">{item.time}</span>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// let count = '...';
|
||||
|
||||
// async function getData() {
|
||||
// const url = new URL(`${__paimon.env.API_HOST}/visitor`);
|
||||
// const url = new URL(`${import.meta.env.VITE_API_HOST}/visitor`);
|
||||
|
||||
// try {
|
||||
// const res = await fetch(url, {
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
<script context="module">
|
||||
import data from '../../data/achievement/en.json';
|
||||
export async function preload() {
|
||||
return { data };
|
||||
}
|
||||
import achievementData from '../../data/achievement/en.json';
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { locale, t } from 'svelte-i18n';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import debounce from 'lodash/debounce';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { mdiFilter } from '@mdi/js';
|
||||
|
||||
import Check from '../../components/Check.svelte';
|
||||
|
@ -21,10 +18,10 @@
|
|||
import { pushToast } from '../../stores/toast';
|
||||
import Ad from '../../components/Ad.svelte';
|
||||
|
||||
export let data;
|
||||
|
||||
let achievementContainer;
|
||||
|
||||
let data = achievementData;
|
||||
|
||||
let achievement = data;
|
||||
let checkList = {};
|
||||
let list = [];
|
||||
|
@ -494,7 +491,7 @@
|
|||
<Ad type="desktop" variant="lb" id="2" />
|
||||
<Ad type="mobile" variant="lb" id="1" />
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.category {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -83,12 +83,12 @@
|
|||
};
|
||||
}
|
||||
|
||||
export async function preload(page) {
|
||||
const { id } = page.params;
|
||||
export async function load({ params }) {
|
||||
const { id } = params;
|
||||
const artifact = data[id];
|
||||
const recommendedCharacter = getCharacter(id);
|
||||
|
||||
return { id, artifact, recommendedCharacter };
|
||||
return { props: { id, artifact, recommendedCharacter } };
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<script context="module">
|
||||
import data from '../../data/artifacts/en.json';
|
||||
export async function preload() {
|
||||
return { data };
|
||||
}
|
||||
import dataJson from '../../data/artifacts/en.json';
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
@ -11,7 +8,7 @@
|
|||
import TableHeader from '../../components/Table/TableHeader.svelte';
|
||||
import { domains } from '../../data/domain.js';
|
||||
|
||||
export let data;
|
||||
let data = dataJson;
|
||||
let artifactList = [];
|
||||
let artifacts = [];
|
||||
let sortBy = 'maxRarity';
|
||||
|
@ -118,7 +115,7 @@
|
|||
</svelte:head>
|
||||
<div class="lg:ml-64 pt-20 lg:pt-8">
|
||||
<h1 class="font-display px-4 md:px-8 font-black text-5xl text-white">{$t('artifact.title')}</h1>
|
||||
<div class="block overflow-x-auto whitespace-no-wrap pb-8">
|
||||
<div class="block overflow-x-auto whitespace-nowrap pb-8">
|
||||
<div class="px-4 md:px-8 table max-w-full">
|
||||
<table class="w-full block p-4 bg-item rounded-xl">
|
||||
<thead>
|
||||
|
|
|
@ -630,7 +630,7 @@
|
|||
{#if currentMax.usage[i] > 0}
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap"
|
||||
<span class="text-white mr-2 whitespace-nowrap"
|
||||
>{currentMax.usage[i]}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
@ -652,7 +652,7 @@
|
|||
{#if item.amount > 0}
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap"
|
||||
<span class="text-white mr-2 whitespace-nowrap"
|
||||
>{item.amount}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
@ -670,7 +670,7 @@
|
|||
{/each}
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap"
|
||||
<span class="text-white mr-2 whitespace-nowrap"
|
||||
>{numberFormat.format(moraNeeded)}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="block overflow-x-auto whitespace-no-wrap pb-1">
|
||||
<div class="block overflow-x-auto whitespace-nowrap pb-1">
|
||||
<div class="table w-full">
|
||||
<div class="bg-item rounded-xl p-4 w-full">
|
||||
<table>
|
||||
|
@ -126,7 +126,7 @@
|
|||
><Icon className="mb-1 text-gray-400" path={mdiArrowRight} size={0.7} /></td
|
||||
>
|
||||
<td class="pr-2 text-white text-center">{step[i + 1]}</td>
|
||||
<td class="px-2 text-white whitespace-no-wrap" style="min-width: 180px;">
|
||||
<td class="px-2 text-white whitespace-nowrap" style="min-width: 180px;">
|
||||
{#each resources as res, j}
|
||||
{#if row.usage[j] > 0}
|
||||
<span class="mr-2">
|
||||
|
@ -145,7 +145,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
td,
|
||||
th {
|
||||
@apply py-1;
|
||||
|
|
|
@ -6,18 +6,28 @@
|
|||
import dayjs from 'dayjs';
|
||||
|
||||
let fateValues = [
|
||||
{ id: "interwinedFate", name: $t('calculator.fateCount.interwinedFate'), image: "/images/intertwined_fate.png", amount: 0 },
|
||||
{ id: "starglitter", name: $t('calculator.fateCount.starglitter'), image: "/images/starglitter.png", amount: 0 },
|
||||
{ id: "stardust", name: $t('calculator.fateCount.stardust'), image: "/images/stardust.png", amount: 0 },
|
||||
{ id: "primogem", name: $t('calculator.fateCount.primogem'), image: "/images/primogem.png", amount: 0 },
|
||||
{ id: "genesisCrystal", name: $t('calculator.fateCount.genesisCrystal'), image: "/images/genesis_crystal.png", amount: 0 },
|
||||
{ id: "welkinMoon", name: $t('calculator.fateCount.welkinMoon'), image: "/images/welkin_moon.png", amount: 0 },
|
||||
{
|
||||
id: 'interwinedFate',
|
||||
name: $t('calculator.fateCount.interwinedFate'),
|
||||
image: '/images/intertwined_fate.png',
|
||||
amount: 0,
|
||||
},
|
||||
{ id: 'starglitter', name: $t('calculator.fateCount.starglitter'), image: '/images/starglitter.png', amount: 0 },
|
||||
{ id: 'stardust', name: $t('calculator.fateCount.stardust'), image: '/images/stardust.png', amount: 0 },
|
||||
{ id: 'primogem', name: $t('calculator.fateCount.primogem'), image: '/images/primogem.png', amount: 0 },
|
||||
{
|
||||
id: 'genesisCrystal',
|
||||
name: $t('calculator.fateCount.genesisCrystal'),
|
||||
image: '/images/genesis_crystal.png',
|
||||
amount: 0,
|
||||
},
|
||||
{ id: 'welkinMoon', name: $t('calculator.fateCount.welkinMoon'), image: '/images/welkin_moon.png', amount: 0 },
|
||||
];
|
||||
|
||||
let parameters = [
|
||||
{ name: "Days until pull", amount: 0 },
|
||||
{ name: "Stardust Wishes (left this month)", amount: 5 }
|
||||
]
|
||||
{ name: 'Days until pull', amount: 0 },
|
||||
{ name: 'Stardust Wishes (left this month)', amount: 5 },
|
||||
];
|
||||
|
||||
let result = null;
|
||||
let totalPrimogem = 0;
|
||||
|
@ -29,39 +39,44 @@
|
|||
if (value.amount >= 0) {
|
||||
let total = 0;
|
||||
switch (value.id) {
|
||||
case "interwinedFate":
|
||||
total = value.amount*160;
|
||||
case 'interwinedFate':
|
||||
total = value.amount * 160;
|
||||
break;
|
||||
case "starglitter":
|
||||
total = Math.floor(value.amount/5)*160;
|
||||
case 'starglitter':
|
||||
total = Math.floor(value.amount / 5) * 160;
|
||||
break;
|
||||
case "stardust":
|
||||
case 'stardust':
|
||||
let dateNow = dayjs();
|
||||
let monthPull = dateNow.add(parameters[0].amount, 'day').startOf('month');
|
||||
let monthDiff = monthPull.diff(dateNow, 'month');
|
||||
let maxStardustFate = monthDiff*5+parameters[1].amount;
|
||||
total = Math.min(Math.floor(value.amount/75), maxStardustFate)*160;
|
||||
let maxStardustFate = monthDiff * 5 + parameters[1].amount;
|
||||
total = Math.min(Math.floor(value.amount / 75), maxStardustFate) * 160;
|
||||
break;
|
||||
case "primogem":
|
||||
case 'primogem':
|
||||
total = value.amount;
|
||||
break;
|
||||
case "genesisCrystal":
|
||||
case 'genesisCrystal':
|
||||
total = value.amount;
|
||||
break;
|
||||
case "welkinMoon":
|
||||
let days = Math.min(value.amount, parameters[0].amount)
|
||||
total = Math.floor(days/30)*300 + days*90
|
||||
case 'welkinMoon':
|
||||
let days = Math.min(value.amount, parameters[0].amount);
|
||||
total = Math.floor(days / 30) * 300 + days * 90;
|
||||
}
|
||||
if (total>0) {
|
||||
totalPrimogem += total
|
||||
result.push({name: value.name, image: value.image, amount: value.amount, total: total })
|
||||
if (total > 0) {
|
||||
totalPrimogem += total;
|
||||
result.push({ name: value.name, image: value.image, amount: value.amount, total: total });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parameters[0].amount>0) {
|
||||
let total = parameters[0].amount*60;
|
||||
if (parameters[0].amount > 0) {
|
||||
let total = parameters[0].amount * 60;
|
||||
totalPrimogem += total;
|
||||
result.push({name: $t('calculator.fateCount.dailyCommission'), image: "/images/commission.png", amount: parameters[0].amount, total: total})
|
||||
result.push({
|
||||
name: $t('calculator.fateCount.dailyCommission'),
|
||||
image: '/images/commission.png',
|
||||
amount: parameters[0].amount,
|
||||
total: total,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +98,15 @@
|
|||
</div>
|
||||
<div class="flex flex-row items-center">
|
||||
<div class="w-full">
|
||||
<Input className="text-center" bind:value={value.amount} on:change={onChange} type="number" min="0" step="1" pattern="\d*" />
|
||||
<Input
|
||||
className="text-center"
|
||||
bind:value={value.amount}
|
||||
on:change={onChange}
|
||||
type="number"
|
||||
min="0"
|
||||
step="1"
|
||||
pattern="\d*"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -98,22 +121,28 @@
|
|||
</div>
|
||||
<div class="flex flex-row items-center">
|
||||
<div class="w-full">
|
||||
<Input className="text-center" bind:value={value.amount} on:change={onChange} type="number" min="0" step="1" pattern="\d*" />
|
||||
<Input
|
||||
className="text-center"
|
||||
bind:value={value.amount}
|
||||
on:change={onChange}
|
||||
type="number"
|
||||
min="0"
|
||||
step="1"
|
||||
pattern="\d*"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="md:col-span-2 xl:col-span-1">
|
||||
<Button className="block w-full md:w-auto" on:click={calculate}
|
||||
>{$t('calculator.fateCount.calculate')}</Button
|
||||
>
|
||||
<Button className="block w-full md:w-auto" on:click={calculate}>{$t('calculator.fateCount.calculate')}</Button>
|
||||
{#if result !== null}
|
||||
<div>
|
||||
<div
|
||||
transition:fade={{ duration: 100 }}
|
||||
class="rounded-xl bg-background p-4 block md:inline-block"
|
||||
style="height: fit-content; width: fit-content;"
|
||||
transition:fade={{ duration: 100 }}
|
||||
class="rounded-xl bg-background p-4 block md:inline-block"
|
||||
style="height: fit-content; width: fit-content;"
|
||||
>
|
||||
<table>
|
||||
<tr>
|
||||
|
@ -138,7 +167,7 @@
|
|||
</tr>
|
||||
{/each}
|
||||
<tr>
|
||||
<td class="border-t border-gray-700 text-white text-right whitespace-no-wrap" colspan={5}>
|
||||
<td class="border-t border-gray-700 text-white text-right whitespace-nowrap" colspan={5}>
|
||||
{$t('calculator.fateCount.totalPrimogem')}
|
||||
{totalPrimogem}
|
||||
<img class="mr-1 w-6 inline" src="/images/primogem.png" alt="Primogem" />
|
||||
|
|
|
@ -334,7 +334,7 @@
|
|||
</tr>
|
||||
{/each}
|
||||
<tr>
|
||||
<td class="border-t border-gray-700 text-white text-right whitespace-no-wrap" colspan={5}>
|
||||
<td class="border-t border-gray-700 text-white text-right whitespace-nowrap" colspan={5}>
|
||||
{$t('calculator.fate.totalGenesis')}
|
||||
{numberFormat.format(resultTotal)}
|
||||
<img class="mr-1 w-6 inline" src="/images/genesis_crystal.png" alt="Genesis" />
|
||||
|
@ -343,7 +343,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border-t border-gray-700 text-white text-right whitespace-no-wrap" colspan={5}>
|
||||
<td class="border-t border-gray-700 text-white text-right whitespace-nowrap" colspan={5}>
|
||||
{$t('calculator.fate.totalPrice')}
|
||||
{currencyLabel}{numberFormat.format(resultTotalPrice)}
|
||||
</td>
|
||||
|
|
|
@ -84,13 +84,13 @@
|
|||
<p class="block text-center text-gray-400">{$t('calculator.friendship.based', { values: { ar: $ar } })}</p>
|
||||
<table class="text-gray-200">
|
||||
<tr>
|
||||
<td class="text-xl font-bold text-primary whitespace-no-wrap pr-4 border-b border-gray-700 pb-1">
|
||||
<td class="text-xl font-bold text-primary whitespace-nowrap pr-4 border-b border-gray-700 pb-1">
|
||||
{$t('calculator.friendship.resultDay', { values: { result } })}
|
||||
</td>
|
||||
<td class="border-b border-gray-700 pb-1">{$t('calculator.friendship.result')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-xl font-bold text-primary whitespace-no-wrap pr-4 pt-1">
|
||||
<td class="text-xl font-bold text-primary whitespace-nowrap pr-4 pt-1">
|
||||
{$t('calculator.friendship.resultDay', { values: { result: resultSerenitea } })}
|
||||
</td>
|
||||
<td class="pt-1">{$t('calculator.friendship.resultSerenitea')}</td>
|
||||
|
@ -102,7 +102,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.slider {
|
||||
@apply w-full h-4 rounded-xl;
|
||||
-webkit-appearance: none;
|
||||
|
|
|
@ -132,7 +132,7 @@
|
|||
<table class="w-full">
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap"
|
||||
<span class="text-white mr-2 whitespace-nowrap"
|
||||
>{resinOutput.resin}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
@ -150,7 +150,7 @@
|
|||
<tr><td colspan="2" class="text-white text-center pt-2">{$t('calculator.resin.or')}</td></tr>
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap"
|
||||
<span class="text-white mr-2 whitespace-nowrap"
|
||||
>{resinOutput.condensed.resin}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
@ -166,7 +166,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap"
|
||||
<span class="text-white mr-2 whitespace-nowrap"
|
||||
>{resinOutput.condensed.condensedResin}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
@ -184,7 +184,9 @@
|
|||
<tr>
|
||||
<td class="text-red-400" colspan="2">
|
||||
{$t('calculator.resin.fullTime')}:
|
||||
{fullTime.locale($t('calculator.resin.timeFormat')).format('dddd HH:mm:ss')} ({fullTime.locale($t('calculator.resin.timeFormat')).fromNow()})
|
||||
{fullTime.locale($t('calculator.resin.timeFormat')).format('dddd HH:mm:ss')} ({fullTime
|
||||
.locale($t('calculator.resin.timeFormat'))
|
||||
.fromNow()})
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
counTimeRelative();
|
||||
</script>
|
||||
|
||||
<div class="block overflow-x-auto whitespace-no-wrap pb-1">
|
||||
<div class="block overflow-x-auto whitespace-nowrap pb-1">
|
||||
<div class="table w-full">
|
||||
<div class="bg-item rounded-xl p-4 w-full">
|
||||
<table class="w-full">
|
||||
|
@ -57,7 +57,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
td,
|
||||
th {
|
||||
@apply py-1;
|
||||
|
|
|
@ -441,7 +441,7 @@
|
|||
{#if currentMax.usage[i] > 0}
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap"
|
||||
<span class="text-white mr-2 whitespace-nowrap"
|
||||
>{currentMax.usage[i]}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
@ -463,7 +463,7 @@
|
|||
{#if item.amount > 0}
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap"
|
||||
<span class="text-white mr-2 whitespace-nowrap"
|
||||
>{item.amount}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
@ -481,7 +481,7 @@
|
|||
{/each}
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap"
|
||||
<span class="text-white mr-2 whitespace-nowrap"
|
||||
>{numberFormat.format(moraNeeded)}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
<script context="module">
|
||||
import { builds as buildsJson } from '../../data/build';
|
||||
import artifactData from '../../data/artifacts/en.json';
|
||||
import weaponData from '../../data/weapons/en.json';
|
||||
|
||||
export async function preload(page) {
|
||||
const { id } = page.params;
|
||||
export async function load({ params, fetch }) {
|
||||
const { id } = params;
|
||||
const data = await import(`../../data/characterData/${id}.json`);
|
||||
const buildData = buildsJson[id];
|
||||
const buildData = await (await fetch(`/characters/build/${id}.json`)).json();
|
||||
|
||||
return { id, data, buildData, artifactData, weaponData };
|
||||
return { props: { id, data, buildData } };
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -16,8 +15,6 @@
|
|||
export let id;
|
||||
export let data;
|
||||
export let buildData;
|
||||
export let artifactData;
|
||||
export let weaponData;
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import { t, locale } from 'svelte-i18n';
|
||||
|
@ -340,34 +337,34 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md:px-4 mt-4 block overflow-x-auto whitespace-no-wrap w-screen md:w-auto">
|
||||
<div class="md:px-4 mt-4 block overflow-x-auto whitespace-nowrap w-screen md:w-auto">
|
||||
<div class="px-4" style="width: min-content;">
|
||||
<div class="table max-w-full rounded-xl border border-gray-200 border-opacity-25">
|
||||
<table class="text-gray-200 w-full">
|
||||
<tr>
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2">
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2">
|
||||
{$t('characters.asc')}
|
||||
</td>
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2">
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2">
|
||||
{$t('characters.lvl')}
|
||||
</td>
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2">
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2">
|
||||
{$t('characters.hp')}
|
||||
</td>
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2">
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2">
|
||||
{$t('characters.atk')}
|
||||
</td>
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2">
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2">
|
||||
{$t('characters.def')}
|
||||
</td>
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2"
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2"
|
||||
>{$t('characters.critRate')}
|
||||
</td>
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2"
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2"
|
||||
>{$t('characters.critDamage')}
|
||||
</td>
|
||||
{#if data.statGrow !== 'critRate' && data.statGrow !== 'critDamage'}
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2">
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2">
|
||||
{$t(`characters.${data.statGrow}`)}
|
||||
</td>
|
||||
{/if}
|
||||
|
@ -556,7 +553,7 @@
|
|||
class="flex items-center justify-center bg-background rounded-md px-2 py-1 mb-1 mr-1"
|
||||
style="height: 40px;"
|
||||
>
|
||||
<p class="text-center whitespace-no-wrap text-primary" style="padding-top: 2px;">
|
||||
<p class="text-center whitespace-nowrap text-primary" style="padding-top: 2px;">
|
||||
{$t('artifact.choose2')}
|
||||
</p>
|
||||
</div>
|
||||
|
@ -735,7 +732,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.pill {
|
||||
@apply rounded-2xl;
|
||||
@apply border-2;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { afterUpdate, onMount, tick } from 'svelte';
|
||||
import { onMount, tick } from 'svelte';
|
||||
|
||||
export let id;
|
||||
export let char;
|
||||
|
@ -64,7 +64,7 @@
|
|||
</div>
|
||||
</a>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.small {
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
|
@ -75,8 +75,6 @@
|
|||
.cell {
|
||||
width: calc(33.33333% - 1rem);
|
||||
|
||||
@screen md {
|
||||
@apply w-24;
|
||||
}
|
||||
@apply md:w-24;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
td:not(:last-child) {
|
||||
@apply border-r;
|
||||
}
|
||||
|
|
11
src/routes/characters/build/[id].json.js
Normal file
11
src/routes/characters/build/[id].json.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { builds } from '../../../data/build';
|
||||
|
||||
/** @type {import('./__types/items').RequestHandler} */
|
||||
export async function GET({ params }) {
|
||||
const { id } = params;
|
||||
const build = builds[id];
|
||||
|
||||
return {
|
||||
body: build,
|
||||
};
|
||||
}
|
|
@ -450,7 +450,7 @@
|
|||
<p class="text-gray-400 px-4 md:px-8 font-medium pb-2 mt-4">
|
||||
※ {$t('characters.subtitle')}
|
||||
</p>
|
||||
<div class="block overflow-x-auto whitespace-no-wrap pb-8">
|
||||
<div class="block overflow-x-auto whitespace-nowrap pb-8">
|
||||
<div class="px-4 md:px-8 table">
|
||||
<table class="w-full block p-4 bg-item rounded-xl">
|
||||
<thead>
|
||||
|
@ -521,7 +521,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
tr.rare:hover {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<script context="module">
|
||||
import artifacts from '../../data/artifacts/en.json';
|
||||
import artifactsJson from '../../data/artifacts/en.json';
|
||||
import { domains } from '../../data/domain.js';
|
||||
export async function preload(page) {
|
||||
const { id } = page.params;
|
||||
export async function load({ params }) {
|
||||
const { id } = params;
|
||||
const domain = domains[id];
|
||||
|
||||
return { id, artifacts, domain };
|
||||
return { props: { id, domain } };
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -17,8 +17,8 @@
|
|||
import Button from '../../components/Button.svelte';
|
||||
|
||||
export let id;
|
||||
export let artifacts;
|
||||
export let domain;
|
||||
let artifacts = artifactsJson;
|
||||
|
||||
let currentArtifacts = [];
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script context="module">
|
||||
import data from '../../data/fishing/en.json';
|
||||
import dataJson from '../../data/fishing/en.json';
|
||||
import locations from '../../data/fishing/location.json';
|
||||
|
||||
let spots = {
|
||||
|
@ -13,8 +13,8 @@
|
|||
spots[location.location].push({ ...location, id });
|
||||
}
|
||||
|
||||
export async function preload() {
|
||||
return { data, spots };
|
||||
export async function load() {
|
||||
return { props: { spots } };
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
|||
|
||||
const { open: openModal, close: closeModal } = getContext('simple-modal');
|
||||
|
||||
export let data;
|
||||
let data = dataJson;
|
||||
export let spots;
|
||||
|
||||
let fishList = data;
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
{#each result as [item, amount], i}
|
||||
<tr>
|
||||
<td class="text-right border-gray-700 py-1 {i === 0 ? '' : 'border-t'}">
|
||||
<span class="text-white mr-2 whitespace-no-wrap">
|
||||
<span class="text-white mr-2 whitespace-nowrap">
|
||||
{amount}
|
||||
<Icon size={0.5} path={mdiClose} />
|
||||
</span>
|
||||
|
@ -82,7 +82,7 @@
|
|||
{#if coins > 0}
|
||||
<tr>
|
||||
<td class="text-right border-t border-gray-700 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap">
|
||||
<span class="text-white mr-2 whitespace-nowrap">
|
||||
{coins}
|
||||
<Icon size={0.5} path={mdiClose} />
|
||||
</span>
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
<script context="module">
|
||||
import setsData from '../../data/furnishing/sets/en.json';
|
||||
import data from '../../data/furnishing/en.json';
|
||||
export async function preload() {
|
||||
return { data, setsData };
|
||||
}
|
||||
import setsDataJson from '../../data/furnishing/sets/en.json';
|
||||
import furnishingDataJson from '../../data/furnishing/en.json';
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { locale, t } from 'svelte-i18n';
|
||||
import debounce from 'lodash/debounce';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { mdiCheckCircleOutline, mdiClose } from '@mdi/js';
|
||||
|
||||
import Button from '../../components/Button.svelte';
|
||||
|
@ -21,8 +18,8 @@
|
|||
|
||||
const { open: openModal } = getContext('simple-modal');
|
||||
|
||||
export let data;
|
||||
export let setsData;
|
||||
let data = furnishingDataJson;
|
||||
let setsData = setsDataJson;
|
||||
|
||||
let loading = true;
|
||||
let furnishing = {};
|
||||
|
@ -277,7 +274,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.popup {
|
||||
@apply text-sm pt-1 hidden p-2 rounded-xl;
|
||||
}
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
<script context="module">
|
||||
import data from '../../data/furnishing/en.json';
|
||||
import categories from '../../data/furnishing/category/en.json';
|
||||
export async function preload() {
|
||||
return { data, categories };
|
||||
}
|
||||
import dataJson from '../../data/furnishing/en.json';
|
||||
import categoriesJson from '../../data/furnishing/category/en.json';
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { locale, t } from 'svelte-i18n';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import { mdiMinus, mdiPlus } from '@mdi/js';
|
||||
import debounce from 'lodash/debounce';
|
||||
import debounce from 'lodash.debounce';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
import { readSave, updateSave } from '../../stores/saveManager';
|
||||
import { getAccountPrefix } from '../../stores/account';
|
||||
import Button from '../../components/Button.svelte';
|
||||
|
||||
export let data;
|
||||
export let categories;
|
||||
let data = dataJson;
|
||||
let categories = categoriesJson;
|
||||
|
||||
let loading = true;
|
||||
let active = {
|
||||
|
@ -221,7 +218,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.category {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
<script context="module">
|
||||
import data from '../../data/furnishing/en.json';
|
||||
export async function preload() {
|
||||
return { data };
|
||||
}
|
||||
import dataJson from '../../data/furnishing/en.json';
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { locale, t } from 'svelte-i18n';
|
||||
import debounce from 'lodash/debounce';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { mdiInformationOutline, mdiMinus, mdiPlus } from '@mdi/js';
|
||||
|
||||
import TableHeader from '../../components/Table/TableHeader.svelte';
|
||||
|
@ -17,7 +14,7 @@
|
|||
import { getAccountPrefix } from '../../stores/account';
|
||||
import { readSave, updateSave } from '../../stores/saveManager';
|
||||
|
||||
export let data;
|
||||
let data = dataJson;
|
||||
|
||||
let type = 'hall';
|
||||
let items = [];
|
||||
|
@ -259,7 +256,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
<div class="flex mt-4 wrapper">
|
||||
<div class="block overflow-x-auto xl:overflow-x-visible whitespace-no-wrap">
|
||||
<div class="block overflow-x-auto xl:overflow-x-visible whitespace-nowrap">
|
||||
<div class="px-4 table">
|
||||
<table class="w-full block pl-4 pr-4 py-2 md:pl-8 md:py-4 bg-item rounded-xl">
|
||||
<tr>
|
||||
|
@ -363,7 +360,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.pill {
|
||||
@apply rounded-2xl;
|
||||
@apply border-2;
|
||||
|
@ -375,7 +372,7 @@
|
|||
@apply outline-none;
|
||||
@apply transition;
|
||||
@apply duration-100;
|
||||
@apply whitespace-no-wrap;
|
||||
@apply whitespace-nowrap;
|
||||
|
||||
&:hover {
|
||||
@apply border-primary;
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
<script context="module">
|
||||
export async function load({ fetch }) {
|
||||
const promoted = ['kaedehara_kazuha', 'shikanoin_heizou'];
|
||||
const builds = {};
|
||||
for (const p of promoted) {
|
||||
const response = await fetch(`/characters/build/${p}.json`);
|
||||
const b = await response.json();
|
||||
builds[p] = b;
|
||||
}
|
||||
|
||||
return {
|
||||
props: { builds },
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import debounce from 'lodash/debounce';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { locale } from 'svelte-i18n';
|
||||
|
||||
import Masonry from '../components/Masonry.svelte';
|
||||
|
@ -19,6 +35,8 @@
|
|||
import Build from './_index/build.svelte';
|
||||
import Ad from '../components/Ad.svelte';
|
||||
|
||||
export let builds;
|
||||
|
||||
let refreshLayout;
|
||||
let isMobile = false;
|
||||
|
||||
|
@ -64,7 +82,7 @@
|
|||
<Ad type="mobile" variant="mpu" id="1" />
|
||||
</div>
|
||||
{/if}
|
||||
<Build on:done={onDone} />
|
||||
<Build on:done={onDone} {builds} />
|
||||
<Event on:done={onDone} />
|
||||
<Item on:done={onDone} />
|
||||
<Discord on:done={onDone} />
|
||||
|
|
|
@ -169,7 +169,7 @@
|
|||
<CharacterSelect bind:selected={selectedCharacter} placeholder={$t('items.searchCharacter')} />
|
||||
<WeaponSelect bind:selected={selectedWeapon} placeholder={$t('items.searchWeapon')} />
|
||||
</div>
|
||||
<div class="block overflow-x-auto whitespace-no-wrap pb-8">
|
||||
<div class="block overflow-x-auto whitespace-nowrap pb-8">
|
||||
<div class="px-4 md:px-8 table max-w-full">
|
||||
<table class="w-full block p-4 bg-item rounded-xl">
|
||||
<thead>
|
||||
|
@ -283,7 +283,7 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="block overflow-x-auto whitespace-no-wrap pb-8">
|
||||
<div class="block overflow-x-auto whitespace-nowrap pb-8">
|
||||
<div class="px-4 md:px-8 table max-w-full">
|
||||
<table class="w-full block p-4 bg-item rounded-xl">
|
||||
<thead>
|
||||
|
@ -338,7 +338,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
td {
|
||||
@apply text-white;
|
||||
@apply px-4;
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
<script context="module">
|
||||
import data from '../../data/radiantSpincrystal/en.json';
|
||||
export async function preload() {
|
||||
return { data };
|
||||
}
|
||||
import dataJson from '../../data/radiantSpincrystal/en.json';
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { locale, t } from 'svelte-i18n';
|
||||
import debounce from 'lodash/debounce';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { mdiMapMarker, mdiMusic, mdiOpenInNew } from '@mdi/js';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
import Check from '../../components/Check.svelte';
|
||||
|
@ -16,7 +13,7 @@
|
|||
import { readSave, updateSave } from '../../stores/saveManager';
|
||||
import Ad from '../../components/Ad.svelte';
|
||||
|
||||
export let data;
|
||||
let data = dataJson;
|
||||
|
||||
let spincrystals = data;
|
||||
let checkList = {};
|
||||
|
@ -136,7 +133,7 @@
|
|||
<Ad type="desktop" variant="lb" id="2" />
|
||||
<Ad type="mobile" variant="lb" id="1" />
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.text {
|
||||
line-height: initial;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
if ($firebaseToken === '') return;
|
||||
|
||||
console.log('get reminder');
|
||||
const url = new URL(`${__paimon.env.API_HOST}/reminder`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/reminder`);
|
||||
const query = new URLSearchParams({ token: $firebaseToken, type: 'hoyolab' });
|
||||
url.search = query.toString();
|
||||
|
||||
|
@ -59,7 +59,7 @@
|
|||
|
||||
async function deleteCurrentReminder() {
|
||||
console.log('delete reminder');
|
||||
const url = new URL(`${__paimon.env.API_HOST}/reminder`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/reminder`);
|
||||
const query = new URLSearchParams({ token: $firebaseToken, type: 'hoyolab' });
|
||||
url.search = query.toString();
|
||||
|
||||
|
@ -86,7 +86,7 @@
|
|||
const reminderTime = dayjs(time, 'HH:mm').utc().year(2000).month(0).date(1).format('YYYY-MM-DD HH:mm:ssZ');
|
||||
|
||||
try {
|
||||
const res = await fetch(`${__paimon.env.API_HOST}/reminder`, {
|
||||
const res = await fetch(`${import.meta.env.VITE_API_HOST}/reminder`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
if ($firebaseToken === '') return;
|
||||
|
||||
console.log('get reminder');
|
||||
const url = new URL(`${__paimon.env.API_HOST}/reminder`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/reminder`);
|
||||
const query = new URLSearchParams({ token: $firebaseToken, type: 'transformer' });
|
||||
url.search = query.toString();
|
||||
|
||||
|
@ -70,7 +70,7 @@
|
|||
|
||||
async function deleteCurrentReminder() {
|
||||
console.log('delete reminder');
|
||||
const url = new URL(`${__paimon.env.API_HOST}/reminder`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/reminder`);
|
||||
const query = new URLSearchParams({ token: $firebaseToken, type: 'transformer' });
|
||||
url.search = query.toString();
|
||||
|
||||
|
@ -109,7 +109,7 @@
|
|||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`${__paimon.env.API_HOST}/reminder`, {
|
||||
const res = await fetch(`${import.meta.env.VITE_API_HOST}/reminder`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
@screen md {
|
||||
.not-supported {
|
||||
width: fit-content;
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
<p class="text-red-400 mb-2">{$t('settings.importWarning')}</p>
|
||||
{#if !loading}
|
||||
<div class="flex">
|
||||
<Button className="mr-2 overflow-hidden whitespace-no-wrap" on:click={() => input.click()}>
|
||||
<Button className="mr-2 overflow-hidden whitespace-nowrap" on:click={() => input.click()}>
|
||||
{files !== null && files[0] ? files[0].name : $t('settings.selectFile')}
|
||||
</Button>
|
||||
{#if files !== null && files[0]}
|
||||
|
|
|
@ -475,14 +475,14 @@
|
|||
<a
|
||||
href="https://discord.gg/tPURAYgHV9"
|
||||
target="_blank"
|
||||
class="whitespace-no-wrap bg-background rounded-xl pr-2 text-blue-400 hover:underline"
|
||||
class="whitespace-nowrap bg-background rounded-xl pr-2 text-blue-400 hover:underline"
|
||||
><Icon path={mdiDiscord} /> Discord</a
|
||||
>
|
||||
{$t('settings.or')}
|
||||
<a
|
||||
href="https://github.com/MadeBaruna/paimon-moe/issues"
|
||||
target="_blank"
|
||||
class="whitespace-no-wrap bg-background rounded-xl pr-2 text-blue-400 hover:underline"
|
||||
class="whitespace-nowrap bg-background rounded-xl pr-2 text-blue-400 hover:underline"
|
||||
><Icon path={mdiGithub} /> Github Issues</a
|
||||
>
|
||||
{$t('settings.thanks')}
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
$: prevEnded = prev !== null && now.isAfter(prev.end);
|
||||
$: shouldShowHourStart = diffStart <= 86400000 || event.duration > 6.5 || !prevNearby;
|
||||
$: shouldShowHourEnd = diffEnd <= 86400000 || event.duration > 6.5 || !prevNearby;
|
||||
|
||||
</script>
|
||||
|
||||
<div
|
||||
|
@ -43,7 +42,7 @@
|
|||
>
|
||||
<div class="event-item {nextDiff < 1 ? '' : 'rounded-xl'}" />
|
||||
<span
|
||||
class="event-name text sticky left-0 font-display text-base md:text-lg text-black font-bold whitespace-no-wrap overflow-hidden"
|
||||
class="event-name text sticky left-0 font-display text-base md:text-lg text-black font-bold whitespace-nowrap overflow-hidden"
|
||||
>
|
||||
{event.name}
|
||||
</span>
|
||||
|
@ -82,7 +81,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
div.event-item {
|
||||
position: absolute;
|
||||
opacity: 1;
|
||||
|
@ -102,5 +101,4 @@
|
|||
text-shadow: var(--color) -1px -1px 4px, var(--color) 1px -1px 4px, var(--color) -1px 1px 4px,
|
||||
var(--color) 1px 1px 4px, var(--color) 0 0 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -332,7 +332,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
::-webkit-scrollbar {
|
||||
height: 8px;
|
||||
}
|
||||
|
|
|
@ -270,7 +270,6 @@
|
|||
|
||||
$: $todos, updateSummary();
|
||||
$: columnCount, updateId();
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -304,7 +303,7 @@
|
|||
{#each Object.entries(todayOnlyItems) as [id, amount]}
|
||||
<tr class="today-only">
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class={`${amount === 0 ? 'line-through text-gray-600' : 'text-white'} mr-2 whitespace-no-wrap`}>
|
||||
<span class={`${amount === 0 ? 'line-through text-gray-600' : 'text-white'} mr-2 whitespace-nowrap`}>
|
||||
{numberFormat.format(amount)}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
@ -339,7 +338,7 @@
|
|||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<div class="flex justify-end items-center">
|
||||
<span class="text-white mr-2 whitespace-no-wrap">
|
||||
<span class="text-white mr-2 whitespace-nowrap">
|
||||
{numberFormat.format(amount)}
|
||||
</span>
|
||||
<img src="/images/resin.png" alt="resin" class="w-6 h-6 mr-2" />
|
||||
|
@ -375,7 +374,7 @@
|
|||
{#each Object.entries(summary) as [id, amount]}
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class={`${amount === 0 ? 'line-through text-gray-600' : 'text-white'} mr-2 whitespace-no-wrap`}>
|
||||
<span class={`${amount === 0 ? 'line-through text-gray-600' : 'text-white'} mr-2 whitespace-nowrap`}>
|
||||
{numberFormat.format(amount)}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
@ -460,7 +459,7 @@
|
|||
{#each Object.entries(todo.resources).sort((a, b) => b[1] - a[1]) as [id, amount]}
|
||||
<tr>
|
||||
<td class="text-right border-b border-gray-700 py-1">
|
||||
<span class={`${amount === 0 ? 'line-through text-gray-600' : 'text-white'} mr-2 whitespace-no-wrap`}>
|
||||
<span class={`${amount === 0 ? 'line-through text-gray-600' : 'text-white'} mr-2 whitespace-nowrap`}>
|
||||
{numberFormat.format(amount)}
|
||||
<Icon size={0.5} path={mdiClose} /></span
|
||||
>
|
||||
|
@ -491,11 +490,10 @@
|
|||
</Masonry>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
tr.today-only:last-child {
|
||||
td {
|
||||
@apply border-b-0;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -35,13 +35,13 @@
|
|||
return Object.values(collection).sort((a, b) => a.id.localeCompare(b.id));
|
||||
}
|
||||
|
||||
export async function preload(page) {
|
||||
const { id } = page.params;
|
||||
export async function load({ params }) {
|
||||
const { id } = params;
|
||||
const weapon = data[id];
|
||||
const materials = weaponList[id].ascension[0].items;
|
||||
const recommendedCharacter = getCharacter(id);
|
||||
|
||||
return { id, weapon, materials, recommendedCharacter };
|
||||
return { props: { id, weapon, materials, recommendedCharacter } };
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -137,22 +137,22 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="mt-4 flex overflow-x-auto whitespace-no-wrap md:w-auto">
|
||||
<div class="mt-4 flex overflow-x-auto whitespace-nowrap md:w-auto">
|
||||
<div style="width: min-content;">
|
||||
<div class="table max-w-full rounded-xl border border-gray-200 border-opacity-25">
|
||||
<table class="text-gray-200 w-full">
|
||||
<tr>
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2">
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2">
|
||||
{$t('weapon.asc')}
|
||||
</td>
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2">
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2">
|
||||
{$t('weapon.lvl')}
|
||||
</td>
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2">
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2">
|
||||
{$t('weapon.baseAtk')}
|
||||
</td>
|
||||
{#if weapon.secondary.name}
|
||||
<td class="text-center whitespace-no-wrap border-gray-700 font-semibold px-2">
|
||||
<td class="text-center whitespace-nowrap border-gray-700 font-semibold px-2">
|
||||
{$t(`weapon.${weapon.secondary.name}`)}
|
||||
</td>
|
||||
{/if}
|
||||
|
@ -185,7 +185,7 @@
|
|||
<Ad type="mobile" variant="lb" id="1" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
td:not(:last-child) {
|
||||
@apply border-r;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<script context="module">
|
||||
import data from '../../data/weapons/en.json';
|
||||
export async function preload() {
|
||||
return { data };
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
@ -12,7 +9,7 @@
|
|||
import { formatStat } from '../../helper';
|
||||
import Ad from '../../components/Ad.svelte';
|
||||
|
||||
export let data;
|
||||
let weaponData = data;
|
||||
let weaponList = [];
|
||||
let sortBy = 'name';
|
||||
let sortOrder = true;
|
||||
|
@ -34,7 +31,7 @@
|
|||
|
||||
function process() {
|
||||
const _weapons = [];
|
||||
for (const [id, weapon] of Object.entries(data)) {
|
||||
for (const [id, weapon] of Object.entries(weaponData)) {
|
||||
if (['amber_bead', 'ebony_bow', 'quartz', 'the_flagstaff'].includes(id)) continue;
|
||||
|
||||
_weapons.push({
|
||||
|
@ -94,7 +91,7 @@
|
|||
|
||||
async function changeLocale(locale) {
|
||||
const _data = await import(`../../data/weapons/${locale}.json`);
|
||||
data = _data.default;
|
||||
weaponData = _data.default;
|
||||
process();
|
||||
}
|
||||
|
||||
|
@ -115,7 +112,7 @@
|
|||
<p class="text-gray-400 px-4 md:px-8 font-medium pb-4" style="margin-top: -1rem;">
|
||||
※ {$t('weapon.subtitle')}
|
||||
</p>
|
||||
<div class="block overflow-x-auto whitespace-no-wrap pb-8 relative">
|
||||
<div class="block overflow-x-auto whitespace-nowrap pb-8 relative">
|
||||
<Ad type="desktop" variant="mpu" id="1" class="absolute top-0" style="right: 50px;" />
|
||||
<div class="px-4 md:px-8 table max-w-full">
|
||||
<table class="w-full block p-4 bg-item rounded-xl">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script context="module">
|
||||
export async function preload(page) {
|
||||
const { id } = page.params;
|
||||
return { id };
|
||||
export async function load({ params }) {
|
||||
const { id } = params;
|
||||
return { props: { id } };
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -510,7 +510,7 @@
|
|||
</div>
|
||||
{:else}
|
||||
<div class="flex mt-4 wrapper">
|
||||
<div class="block overflow-x-auto xl:overflow-x-visible whitespace-no-wrap px">
|
||||
<div class="block overflow-x-auto xl:overflow-x-visible whitespace-nowrap px">
|
||||
<div class="flex pl-4 md:pl-8 mb-2">
|
||||
<button on:click={() => toggleShowRarity(0)} class={`pill legendary ${showRarity[0] ? 'active' : ''}`}>
|
||||
5 <Icon path={mdiStar} size={0.75} className="mb-1" />
|
||||
|
@ -600,7 +600,7 @@
|
|||
: ''}"
|
||||
>
|
||||
<td
|
||||
class="border-t border-gray-700 px-4 text-gray-200 whitespace-no-wrap relative"
|
||||
class="border-t border-gray-700 px-4 text-gray-200 whitespace-nowrap relative"
|
||||
style="font-family: monospace;"
|
||||
>
|
||||
{pull.formattedTime}
|
||||
|
@ -710,19 +710,18 @@
|
|||
<Ad type="mobile" variant="lb" id="1" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.wrapper {
|
||||
@apply flex-col-reverse;
|
||||
|
||||
.chart-area {
|
||||
@apply px-4;
|
||||
|
||||
@screen md {
|
||||
@apply px-8;
|
||||
}
|
||||
@apply md:px-8;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1920px) {
|
||||
@media (min-width: 1920px) {
|
||||
.wrapper {
|
||||
@apply flex-row;
|
||||
|
||||
.chart-area {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import { onMount, getContext, createEventDispatcher } from 'svelte';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { mdiPencil, mdiStar, mdiChevronDown, mdiTableOfContents, mdiArrowUpCircle } from '@mdi/js';
|
||||
import debounce from 'lodash/debounce';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
const { open: openModal, close: closeModal } = getContext('simple-modal');
|
||||
|
||||
|
@ -319,7 +319,7 @@
|
|||
isEdit ? 'bg-item flex-col py-2' : 'bg-background flex-row items-center justify-center mb-2 p-4'
|
||||
} rounded-xl flex relative`}
|
||||
>
|
||||
<span class="text-gray-200 whitespace-no-wrap flex-1">
|
||||
<span class="text-gray-200 whitespace-nowrap flex-1">
|
||||
{$t('wish.lifetimePulls')}<br />
|
||||
<span class="flex items-center text-gray-600">
|
||||
<img class="w-4 h-4 mr-2" src="/images/primogem.png" alt="primogem" />
|
||||
|
@ -345,7 +345,7 @@
|
|||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<span class="text-gray-200 whitespace-no-wrap flex-1">
|
||||
<span class="text-gray-200 whitespace-nowrap flex-1">
|
||||
5★ {$t('wish.pity')}
|
||||
<br /><span class="text-gray-600">{$t('wish.guarantee', { values: { pity: legendaryPity } })}</span>
|
||||
</span>
|
||||
|
@ -374,7 +374,7 @@
|
|||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<span class="text-gray-200 whitespace-no-wrap flex-1">
|
||||
<span class="text-gray-200 whitespace-nowrap flex-1">
|
||||
4★ {$t('wish.pity')}
|
||||
<br /><span class="text-gray-600">{$t('wish.guarantee', { values: { pity: 10 } })}</span>
|
||||
</span>
|
||||
|
@ -476,7 +476,7 @@
|
|||
{:else if pull.type === 'unknown_3_star'}
|
||||
<td class="border-b border-gray-700 py-1 pl-2 font-semibold text-primary">Unknown</td>
|
||||
{/if}
|
||||
<td class="border-b border-gray-700 text-xs py-1 px-2 whitespace-no-wrap" style="font-family: monospace;">
|
||||
<td class="border-b border-gray-700 text-xs py-1 px-2 whitespace-nowrap" style="font-family: monospace;">
|
||||
{pull.time}
|
||||
</td>
|
||||
<td class="text-right border-b border-gray-700 py-1">{pull.pity}</td>
|
||||
|
@ -487,7 +487,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.pill {
|
||||
@apply rounded-2xl;
|
||||
@apply border-2;
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
<td class="text-gray-400 text-sm font-display pr-2 md:pr-4 text-left">{$t('wish.detail.rarity')}</td>
|
||||
<td class="text-gray-400 text-sm font-display pr-2 md:pr-4 text-right">{$t('wish.detail.total')}</td>
|
||||
<td class="text-gray-400 text-sm font-display pr-2 md:pr-4 text-right">{$t('wish.detail.percent')}</td>
|
||||
<td class="text-gray-400 text-sm font-display text-right whitespace-no-wrap">{$t('wish.detail.pityAverage')}</td>
|
||||
<td class="text-gray-400 text-sm font-display text-right whitespace-nowrap">{$t('wish.detail.pityAverage')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-legendary-from font-semibold pr-2 md:pr-4 border-t border-gray-700">
|
||||
|
@ -101,7 +101,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-rare-from font-semibold pl-4 md:pl-4 pr-2 md:pr-4 border-t border-gray-700 whitespace-no-wrap">
|
||||
<td class="text-rare-from font-semibold pl-4 md:pl-4 pr-2 md:pr-4 border-t border-gray-700 whitespace-nowrap">
|
||||
└ {$t('wish.detail.character')}
|
||||
</td>
|
||||
<td class="text-rare-from font-semibold pr-2 md:pr-4 text-right border-t border-gray-700">
|
||||
|
@ -115,7 +115,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-rare-from font-semibold pl-4 md:pl-4 pr-2 md:pr-4 border-t border-gray-700 whitespace-no-wrap">
|
||||
<td class="text-rare-from font-semibold pl-4 md:pl-4 pr-2 md:pr-4 border-t border-gray-700 whitespace-nowrap">
|
||||
└ {$t('wish.detail.weapon')}
|
||||
</td>
|
||||
<td class="text-rare-from font-semibold pr-2 md:pr-4 text-right border-t border-gray-700">
|
||||
|
@ -136,13 +136,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
span.pity {
|
||||
@apply rounded-xl;
|
||||
@apply text-gray-400;
|
||||
@apply border;
|
||||
@apply border-legendary-from;
|
||||
@apply whitespace-no-wrap;
|
||||
@apply whitespace-nowrap;
|
||||
@apply px-2;
|
||||
@apply mb-1;
|
||||
@apply mr-1;
|
||||
|
|
|
@ -703,7 +703,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.pill {
|
||||
@apply rounded-2xl;
|
||||
@apply border-2;
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
</p>
|
||||
<p class="mb-2">
|
||||
{$t('wish.welcomeStart1')}
|
||||
<span class="bg-background px-2 rounded-xl font-bold whitespace-no-wrap">{$t('wish.autoImport')}</span>
|
||||
<span class="bg-background px-2 rounded-xl font-bold whitespace-nowrap">{$t('wish.autoImport')}</span>
|
||||
{$t('wish.welcomeStart2')}
|
||||
<Icon path={mdiArrowUp} size={1.2} />
|
||||
</p>
|
||||
|
@ -54,7 +54,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.bubble::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
if (wishCount === 0) return;
|
||||
|
||||
try {
|
||||
const url = new URL(`${__paimon.env.API_HOST}/wish/summary`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/wish/summary`);
|
||||
const query = new URLSearchParams({ banner: current });
|
||||
url.search = query.toString();
|
||||
|
||||
|
@ -99,7 +99,7 @@
|
|||
if (percentages[current] === undefined) return;
|
||||
|
||||
try {
|
||||
const url = new URL(`${__paimon.env.API_HOST}/wish/summary/luck`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/wish/summary/luck`);
|
||||
const query = new URLSearchParams({ banner: current, rarity });
|
||||
url.search = query.toString();
|
||||
|
||||
|
@ -151,7 +151,7 @@
|
|||
}
|
||||
|
||||
try {
|
||||
const url = new URL(`${__paimon.env.API_HOST}/wish/summary/winrateoff`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/wish/summary/winrateoff`);
|
||||
const query = new URLSearchParams({ banner: current, rarity });
|
||||
url.search = query.toString();
|
||||
|
||||
|
@ -368,7 +368,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.pill {
|
||||
@apply text-sm;
|
||||
@apply rounded-2xl;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import { createEventDispatcher, onMount } from 'svelte';
|
||||
import dayjs from 'dayjs';
|
||||
import debounce from 'lodash/debounce';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
import { characters } from '../../data/characters';
|
||||
import { weaponList } from '../../data/weaponList';
|
||||
|
@ -304,7 +304,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.container {
|
||||
@apply flex flex-col gap-4;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<td class="text-white text-md font-semibold pr-2 md:pr-4 flex-1 w-full">{$t(`wish.types.${type.id}`)}</td>
|
||||
<td class="text-gray-400 text-sm font-display pr-2 md:pr-4 text-right">{$t('wish.summary.total')}</td>
|
||||
<td class="text-gray-400 text-sm font-display pr-2 md:pr-4 text-right">{$t('wish.summary.percent')}</td>
|
||||
<td class="text-gray-400 text-sm font-display text-right whitespace-no-wrap">{$t('wish.summary.pityAverage')}</td>
|
||||
<td class="text-gray-400 text-sm font-display text-right whitespace-nowrap">{$t('wish.summary.pityAverage')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-legendary-from font-semibold pr-2 md:pr-4 border-t border-gray-700">
|
||||
|
@ -131,13 +131,13 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
span.pity {
|
||||
@apply rounded-xl;
|
||||
@apply text-gray-400;
|
||||
@apply border;
|
||||
@apply border-legendary-from;
|
||||
@apply whitespace-no-wrap;
|
||||
@apply whitespace-nowrap;
|
||||
@apply px-2;
|
||||
@apply mb-1;
|
||||
@apply mr-1;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { getContext, onMount } from 'svelte';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { goto } from '@sapper/app';
|
||||
import { goto } from '$app/navigation';
|
||||
import { t } from 'svelte-i18n';
|
||||
import {
|
||||
mdiCheckBold,
|
||||
|
@ -251,7 +251,7 @@
|
|||
|
||||
try {
|
||||
const res = await fetchRetry(
|
||||
`${__paimon.env.API_HOST}/corsproxy`,
|
||||
`${import.meta.env.VITE_API_HOST}/corsproxy`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
|
@ -286,7 +286,7 @@
|
|||
}
|
||||
|
||||
if (lastCount < fetchSize && dat.data.list.length > 0) {
|
||||
await fetch(`${__paimon.env.API_HOST}/corsreset`);
|
||||
await fetch(`${import.meta.env.VITE_API_HOST}/corsreset`);
|
||||
fetchSize = 6;
|
||||
lastCount = fetchSize;
|
||||
error = $t('wish.import.invalidData');
|
||||
|
@ -828,7 +828,7 @@
|
|||
|
||||
async function getNews() {
|
||||
try {
|
||||
const res = await fetch(`${__paimon.env.API_HOST}/news/wish`);
|
||||
const res = await fetch(`${import.meta.env.VITE_API_HOST}/news/wish`);
|
||||
if (res.status === 200) {
|
||||
const json = await res.json();
|
||||
news = json.message;
|
||||
|
@ -1037,9 +1037,10 @@
|
|||
<p class="text-white">{$t('wish.import.guide.pc2.3')}</p>
|
||||
<div class="flex">
|
||||
<pre
|
||||
class="bg-black text-white bg-opacity-50 whitespace-pre-wrap break-all p-2 rounded-xl text-xs select-all flex-1">
|
||||
{$server === 'China' ? powershellScriptChina : powershellScript}
|
||||
</pre>
|
||||
class="bg-black text-white bg-opacity-50 whitespace-pre-wrap break-all p-2 rounded-xl text-xs select-all flex-1">{$server ===
|
||||
'China'
|
||||
? powershellScriptChina
|
||||
: powershellScript}</pre>
|
||||
<button
|
||||
on:click={copyScript}
|
||||
class="bg-black bg-opacity-50 hover:bg-opacity-25 text-white px-2 ml-1 rounded-xl"
|
||||
|
@ -1101,9 +1102,11 @@
|
|||
</div>
|
||||
<div class="content flex-col items-center pb-2">
|
||||
<p class="text-white">{$t('wish.import.guide.pclog.2')}</p>
|
||||
<pre class="bg-black text-white bg-opacity-50 whitespace-pre-wrap break-all p-2 rounded-xl text-xs select-all">
|
||||
{$server === 'China' ? $t('wish.import.logLocation.china') : $t('wish.import.logLocation.global')}
|
||||
</pre>
|
||||
<pre
|
||||
class="bg-black text-white bg-opacity-50 whitespace-pre-wrap break-all p-2 rounded-xl text-xs select-all">{$server ===
|
||||
'China'
|
||||
? $t('wish.import.logLocation.china')
|
||||
: $t('wish.import.logLocation.global')}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-3 mb-2">
|
||||
|
@ -1363,10 +1366,10 @@
|
|||
{#if wishes[code] !== undefined}
|
||||
<tr>
|
||||
<td class="px-2 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap">{type.name} Banner</span>
|
||||
<span class="text-white mr-2 whitespace-nowrap">{type.name} Banner</span>
|
||||
</td>
|
||||
<td class="pr-2 py-1">
|
||||
<span class="text-white mr-2 whitespace-no-wrap">
|
||||
<span class="text-white mr-2 whitespace-nowrap">
|
||||
<Icon size={0.5} path={mdiClose} />
|
||||
{numberFormat.format(wishes[code].length)}
|
||||
</span>
|
||||
|
@ -1416,7 +1419,7 @@
|
|||
<Ad class="ml-4" type="desktop" variant="mpu" id="1" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.step-number {
|
||||
min-height: 2rem;
|
||||
}
|
||||
|
|
|
@ -255,7 +255,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
@media (min-width: 1920px) {
|
||||
.top-header {
|
||||
@apply flex-row;
|
||||
|
|
|
@ -1,294 +0,0 @@
|
|||
<script context="module">
|
||||
export async function preload(page) {
|
||||
const { id } = page.params;
|
||||
return { id };
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { mdiLoading } from '@mdi/js';
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
import { t } from 'svelte-i18n';
|
||||
import Icon from '../../../components/Icon.svelte';
|
||||
import { banners } from '../../../data/banners';
|
||||
import { characters } from '../../../data/characters';
|
||||
import { weaponList } from '../../../data/weaponList';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import duration from 'dayjs/plugin/duration';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
dayjs.extend(duration);
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
const numberFormat = Intl.NumberFormat('en', {
|
||||
maximumFractionDigits: 2,
|
||||
minimumFractionDigits: 0,
|
||||
});
|
||||
|
||||
const numberFormatFixed = Intl.NumberFormat('en', {
|
||||
maximumFractionDigits: 2,
|
||||
minimumFractionDigits: 2,
|
||||
});
|
||||
|
||||
export let id;
|
||||
let banner = {};
|
||||
let loading = true;
|
||||
let data;
|
||||
let legendaryList = [];
|
||||
let totalGuarantee = 0;
|
||||
let totalFeatured = 0;
|
||||
|
||||
let legendaryPity = [];
|
||||
let rarePity = [];
|
||||
let rarePercentage = {
|
||||
min: 0,
|
||||
max: 0,
|
||||
};
|
||||
|
||||
if (id.startsWith('2')) {
|
||||
banner = banners.standard[0];
|
||||
} else if (id.startsWith('3')) {
|
||||
const index = Number(id.substring(4)) - 1;
|
||||
banner = banners.characters[index];
|
||||
} else if (id.startsWith('4')) {
|
||||
const index = Number(id.substring(4)) - 1;
|
||||
banner = banners.weapons[index];
|
||||
}
|
||||
|
||||
async function getData() {
|
||||
const url = new URL(`${__paimon.env.API_HOST}/wish`);
|
||||
const query = new URLSearchParams({ banner: id });
|
||||
url.search = query.toString();
|
||||
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
|
||||
data = await res.json();
|
||||
|
||||
let totalRare = data.total.rare;
|
||||
if (id > 300011 && id < 400000) {
|
||||
totalRare = data.list.reduce((prev, current) => {
|
||||
if (banner.featuredRare.includes(current.name)) {
|
||||
prev += current.count;
|
||||
}
|
||||
return prev;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
legendaryList = data.list
|
||||
.sort((a, b) => {
|
||||
return b.count - a.count;
|
||||
})
|
||||
.map((e) => {
|
||||
if (e.type === 'character') {
|
||||
const rarity = characters[e.name].rarity;
|
||||
e.percentage = rarity === 5 ? e.count / data.total.legendary : e.count / totalRare;
|
||||
} else if (e.type === 'weapon') {
|
||||
const rarity = weaponList[e.name].rarity;
|
||||
e.percentage = rarity === 5 ? e.count / data.total.legendary : e.count / totalRare;
|
||||
}
|
||||
|
||||
if (id !== '200001' && banner.featured.includes(e.name)) {
|
||||
totalGuarantee = e.guaranteed;
|
||||
totalFeatured = e.count;
|
||||
}
|
||||
return e;
|
||||
});
|
||||
|
||||
legendaryPity = data.pityCount.legendary.slice(1, 91).map((e, i) => {
|
||||
const percentage = e / data.countEachPity[i];
|
||||
return {
|
||||
total: e,
|
||||
percentage,
|
||||
};
|
||||
});
|
||||
|
||||
rarePity = data.pityCount.rare.map((e) => ({
|
||||
total: e,
|
||||
percentage: e / data.total.rare,
|
||||
}));
|
||||
rarePity.forEach((e) => {
|
||||
if (rarePercentage.min > e.percentage) {
|
||||
rarePercentage.min = e.percentage;
|
||||
}
|
||||
if (rarePercentage.max < e.percentage) {
|
||||
rarePercentage.max = e.percentage;
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
function mapVal(value, x1, y1, x2, y2) {
|
||||
return ((value - x1) * (y2 - x2)) / (y1 - x1) + x2;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
getData();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Wish Tally - Paimon.moe</title>
|
||||
<meta name="description" content="Genshin Impact Wish Tally average pity percentage from paimon.moe users" />
|
||||
<meta property="og:description" content="Genshin Impact Wish Tally average pity percentage from paimon.moe users" />
|
||||
</svelte:head>
|
||||
<div>
|
||||
<div class="lg:ml-64 pt-20 lg:pt-8">
|
||||
<h1 class="font-display px-4 md:px-8 font-black text-4xl text-white">{$t('wish.tally.title')} {banner.name}</h1>
|
||||
<p class="text-gray-400 px-4 md:px-8 font-medium pb-4" style="margin-top: -1rem;">
|
||||
※ {$t('wish.tally.subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
<div class="lg:ml-64 px-8">
|
||||
<div class="flex flex-col lg:flex-row items-end">
|
||||
<img src="/images/banners/{banner.name} {banner.image}.png" alt={banner.name} class="rounded-xl w-full h-auto lg:h-64 lg:w-auto" />
|
||||
{#if loading}
|
||||
<Icon className="m-4" path={mdiLoading} color="white" size={2} spin />
|
||||
{:else}
|
||||
<div class="border border-gray-700 rounded-xl ml-4" style="width: fit-content; height: fit-content;">
|
||||
<table class="text-white">
|
||||
<tr>
|
||||
<td class="px-2 border-r border-gray-700">Last Update</td>
|
||||
<td class="px-2 border-gray-700">{dayjs(data.time).fromNow()}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-2 border-t border-r border-gray-700">Wish Total</td>
|
||||
<td class="px-2 border-t border-gray-700">{numberFormat.format(data.total.all)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-2 border-t border-r border-gray-700">Total User</td>
|
||||
<td class="px-2 border-t border-gray-700">{numberFormat.format(data.total.users)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-2 border-t border-r border-gray-700">5★ Median</td>
|
||||
<td class="px-2 border-t border-gray-700">{numberFormat.format(data.median.legendary)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-2 border-t border-r border-gray-700">Total 5★</td>
|
||||
<td class="px-2 border-t border-gray-700">
|
||||
{numberFormat.format(data.total.legendary)}
|
||||
({numberFormat.format((data.total.legendary / data.total.all) * 100)}%)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-2 border-t border-r border-gray-700">Total 4★</td>
|
||||
<td class="px-2 border-t border-gray-700">
|
||||
{numberFormat.format(data.total.rare)}
|
||||
({numberFormat.format((data.total.rare / data.total.all) * 100)}%)
|
||||
</td>
|
||||
</tr>
|
||||
{#if id > 300000 && id < 400000}
|
||||
<tr>
|
||||
<td class="px-2 border-t border-r border-gray-700">Won 50:50</td>
|
||||
<td class="px-2 border-t border-gray-700">
|
||||
{numberFormat.format(
|
||||
((totalFeatured - totalGuarantee) / (data.total.legendary - totalGuarantee)) * 100,
|
||||
)}%
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if !loading}
|
||||
<div class="flex flex-col lg:flex-row space-y-4 lg:space-x-4">
|
||||
<div
|
||||
class="border border-gray-700 rounded-xl mt-4 overflow-hidden"
|
||||
style="width: fit-content; height: fit-content;"
|
||||
>
|
||||
<table class="text-white">
|
||||
<tr>
|
||||
<td class="text-center px-2 border-gray-700 text-sm">5★ Total<br />Chance%</td>
|
||||
{#each [...new Array(10)] as _, i}
|
||||
<td class="text-center px-2 border-l border-gray-700">{i + 1}</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{#each [...new Array(9)] as _, i}
|
||||
<tr>
|
||||
<td class="text-center px-2 border-t border-gray-700">{i * 10 + 1} - {(i + 1) * 10}</td>
|
||||
{#each [...new Array(10)] as _, j}
|
||||
<td
|
||||
class="text-center px-2 border-t border-l border-gray-700"
|
||||
style="font-family: monospace; background: rgba(25, 142, 81, {legendaryPity[i * 10 + j]
|
||||
.percentage});"
|
||||
title="Pity {i * 10 + j + 1}"
|
||||
>
|
||||
{legendaryPity[i * 10 + j].total}
|
||||
<br />
|
||||
{numberFormatFixed.format((legendaryPity[i * 10 + j].percentage || 0) * 100)}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
</div>
|
||||
<div
|
||||
class="border border-gray-700 rounded-xl mt-4 overflow-hidden"
|
||||
style="width: fit-content; height: fit-content;"
|
||||
>
|
||||
<table class="text-white">
|
||||
<tr>
|
||||
<td class="text-center px-2 border-gray-700">4★</td>
|
||||
<td class="text-center px-2 border-l border-gray-700">Total</td>
|
||||
<td class="text-center px-2 border-l border-gray-700">%</td>
|
||||
</tr>
|
||||
{#each rarePity as pity, i}
|
||||
<tr>
|
||||
<td class="text-center px-2 border-t border-gray-700">{i + 1}</td>
|
||||
<td class="text-center px-2 border-l border-t border-gray-700" style="font-family: monospace;">
|
||||
{numberFormat.format(pity.total)}
|
||||
</td>
|
||||
<td
|
||||
class="text-center px-2 border-l border-t border-gray-700"
|
||||
style="font-family: monospace; background: rgba(25, 142, 81, {mapVal(
|
||||
pity.percentage,
|
||||
rarePercentage.min,
|
||||
rarePercentage.max,
|
||||
0,
|
||||
1,
|
||||
)});"
|
||||
>
|
||||
{numberFormat.format(pity.percentage * 100)}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
</div>
|
||||
<div class="border border-gray-700 rounded-xl mt-4" style="width: fit-content; height: fit-content;">
|
||||
<table class="text-white">
|
||||
<tr>
|
||||
<td class="text-center px-2 border-r border-gray-700">Name</td>
|
||||
<td class="text-center px-2 border-r border-gray-700">Total</td>
|
||||
<td class="text-center px-2">%</td>
|
||||
</tr>
|
||||
{#each legendaryList as item}
|
||||
<tr>
|
||||
<td class="px-2 border-t border-r border-gray-700">
|
||||
{item.type === 'character' ? characters[item.name].name : weaponList[item.name].name}
|
||||
</td>
|
||||
<td class="px-2 border-t border-r border-gray-700 text-right" style="font-family: monospace;">
|
||||
{item.count}
|
||||
</td>
|
||||
<td class="px-2 border-t border-gray-700 text-right" style="font-family: monospace;">
|
||||
{numberFormatFixed.format(item.percentage * 100)}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
|
@ -104,11 +104,11 @@
|
|||
min: 0,
|
||||
max: 0,
|
||||
};
|
||||
|
||||
|
||||
const rareInclude = {
|
||||
300011: ['rosaria'],
|
||||
300012: ['yanfei', 'noelle', 'diona'],
|
||||
};
|
||||
300011: ['rosaria'],
|
||||
300012: ['yanfei', 'noelle', 'diona'],
|
||||
};
|
||||
let promotedRarePercentage = 0;
|
||||
|
||||
let legendaryList = [];
|
||||
|
@ -122,7 +122,7 @@
|
|||
});
|
||||
|
||||
async function getData() {
|
||||
const url = new URL(`${__paimon.env.API_HOST}/wish`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/wish`);
|
||||
const query = new URLSearchParams({ banner: id });
|
||||
url.search = query.toString();
|
||||
|
||||
|
@ -173,19 +173,22 @@
|
|||
|
||||
// only for zhongli banner upward
|
||||
if (id > 300011 && id < 400000) {
|
||||
const totalRare = data.list.reduce((prev, current) => {
|
||||
if (rareInclude[id].includes(current.name)) {
|
||||
prev.total += current.count;
|
||||
}
|
||||
if (featured[1] === current.name) {
|
||||
prev.featured = current.count;
|
||||
}
|
||||
return prev;
|
||||
}, {
|
||||
total: 0,
|
||||
featured: 0,
|
||||
});
|
||||
promotedRarePercentage = totalRare.featured / totalRare.total * 100
|
||||
const totalRare = data.list.reduce(
|
||||
(prev, current) => {
|
||||
if (rareInclude[id].includes(current.name)) {
|
||||
prev.total += current.count;
|
||||
}
|
||||
if (featured[1] === current.name) {
|
||||
prev.featured = current.count;
|
||||
}
|
||||
return prev;
|
||||
},
|
||||
{
|
||||
total: 0,
|
||||
featured: 0,
|
||||
},
|
||||
);
|
||||
promotedRarePercentage = (totalRare.featured / totalRare.total) * 100;
|
||||
}
|
||||
|
||||
legendary = {
|
||||
|
@ -340,7 +343,7 @@
|
|||
100,
|
||||
)}%
|
||||
{$t('wish.tally.wonFiftyFifty')}
|
||||
{:else if id > 300011 && id < 400000 && i === 1}
|
||||
{:else if id > 300011 && id < 400000 && i === 1}
|
||||
{numberFormat.format(promotedRarePercentage)}%
|
||||
{$t('wish.tally.fromFourStarFeatured')}
|
||||
{:else}
|
||||
|
@ -365,7 +368,7 @@
|
|||
{numberFormat.format(legendary.percentage)}%
|
||||
</p>
|
||||
<div class="flex flex-col flex-1">
|
||||
<p class="font-semibold whitespace-no-wrap">
|
||||
<p class="font-semibold whitespace-nowrap">
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
|
@ -380,7 +383,7 @@
|
|||
{numberFormatSecondary.format(rare.percentage)}%
|
||||
</p>
|
||||
<div class="flex flex-col flex-1">
|
||||
<p class="font-semibold whitespace-no-wrap">
|
||||
<p class="font-semibold whitespace-nowrap">
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
|
@ -489,7 +492,7 @@
|
|||
<table class="text-white w-full table-fixed text-sm">
|
||||
<tr>
|
||||
<td
|
||||
class="font-display text-gray-200 font-semibold px-2 py-1 whitespace-no-wrap text-right border-b border-background"
|
||||
class="font-display text-gray-200 font-semibold px-2 py-1 whitespace-nowrap text-right border-b border-background"
|
||||
>
|
||||
5★<br />{$t('wish.tally.pity')}
|
||||
</td>
|
||||
|
@ -535,11 +538,14 @@
|
|||
</table>
|
||||
</div>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="border border-background rounded-xl hidden xl:block overflow-hidden mr-4 mb-2" style="width: fit-content;">
|
||||
<div
|
||||
class="border border-background rounded-xl hidden xl:block overflow-hidden mr-4 mb-2"
|
||||
style="width: fit-content;"
|
||||
>
|
||||
<table class="text-white text-sm">
|
||||
<tr>
|
||||
<td
|
||||
class="font-display text-gray-200 font-semibold px-2 py-1 whitespace-no-wrap text-right border-b border-background"
|
||||
class="font-display text-gray-200 font-semibold px-2 py-1 whitespace-nowrap text-right border-b border-background"
|
||||
>
|
||||
4★ {$t('wish.tally.pity')}
|
||||
</td>
|
||||
|
@ -578,20 +584,20 @@
|
|||
</div>
|
||||
<div class="flex flex-wrap text-white -mt-2 mb-2">
|
||||
<div class="space-y-2 flex flex-col flex-wrap mr-2 mt-2">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-no-wrap">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-nowrap">
|
||||
{$t('wish.tally.wishTotal')} <span class="font-semibold ml-2">{numberFormat.format(data.total.all)}</span>
|
||||
</div>
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-no-wrap">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-nowrap">
|
||||
{$t('wish.tally.worth')} <img class="w-4 h-4 inline mx-1" src="/images/primogem.png" alt="primogem" />
|
||||
<span class="font-semibold">{numberFormat.format(data.total.all * 160)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2 flex flex-col flex-wrap mt-2">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-no-wrap">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-nowrap">
|
||||
{$t('wish.tally.median')}
|
||||
<span class="font-semibold ml-2">{numberFormat.format(data.median.legendary)}</span>
|
||||
</div>
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-no-wrap">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-nowrap">
|
||||
{$t('wish.tally.user')} <span class="font-semibold ml-2">{numberFormat.format(data.total.users)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -603,7 +609,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
@screen xl {
|
||||
.pity-summary {
|
||||
min-width: 320px;
|
||||
|
|
|
@ -119,7 +119,7 @@
|
|||
});
|
||||
|
||||
async function getData() {
|
||||
const url = new URL(`${__paimon.env.API_HOST}/wish`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/wish`);
|
||||
const query = new URLSearchParams({ banner: id });
|
||||
url.search = query.toString();
|
||||
|
||||
|
@ -381,7 +381,7 @@
|
|||
{numberFormat.format(legendary.percentage)}%
|
||||
</p>
|
||||
<div class="flex flex-col flex-1">
|
||||
<p class="font-semibold whitespace-no-wrap">
|
||||
<p class="font-semibold whitespace-nowrap">
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
|
@ -396,7 +396,7 @@
|
|||
{numberFormatSecondary.format(rare.percentage)}%
|
||||
</p>
|
||||
<div class="flex flex-col flex-1">
|
||||
<p class="font-semibold whitespace-no-wrap">
|
||||
<p class="font-semibold whitespace-nowrap">
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
|
@ -505,7 +505,7 @@
|
|||
<table class="text-white w-full table-fixed text-sm">
|
||||
<tr>
|
||||
<td
|
||||
class="font-display text-gray-200 font-semibold px-2 py-1 whitespace-no-wrap text-right border-b border-background"
|
||||
class="font-display text-gray-200 font-semibold px-2 py-1 whitespace-nowrap text-right border-b border-background"
|
||||
>
|
||||
5★<br />{$t('wish.tally.pity')}
|
||||
</td>
|
||||
|
@ -560,7 +560,7 @@
|
|||
<table class="text-white text-sm">
|
||||
<tr>
|
||||
<td
|
||||
class="font-display text-gray-200 font-semibold px-2 py-1 whitespace-no-wrap text-right border-b border-background"
|
||||
class="font-display text-gray-200 font-semibold px-2 py-1 whitespace-nowrap text-right border-b border-background"
|
||||
>
|
||||
4★ {$t('wish.tally.pity')}
|
||||
</td>
|
||||
|
@ -599,27 +599,27 @@
|
|||
</div>
|
||||
<div class="flex flex-wrap text-white -mt-2 mb-2">
|
||||
<div class="space-y-2 flex flex-col flex-wrap mr-2 mt-2">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-no-wrap">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-nowrap">
|
||||
{$t('wish.tally.wishTotal')} <span class="font-semibold ml-2">{numberFormat.format(data.total.all)}</span>
|
||||
</div>
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-no-wrap">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-nowrap">
|
||||
{$t('wish.tally.worth')} <img class="w-4 h-4 inline mx-1" src="/images/primogem.png" alt="primogem" />
|
||||
<span class="font-semibold">{numberFormat.format(data.total.all * 160)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2 flex flex-col flex-wrap mr-2 mt-2">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-no-wrap">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-nowrap">
|
||||
{$t('wish.tally.median')}
|
||||
<span class="font-semibold ml-2">{numberFormat.format(data.median.legendary)}</span>
|
||||
</div>
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-no-wrap">
|
||||
<div class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-nowrap">
|
||||
{$t('wish.tally.user')} <span class="font-semibold ml-2">{numberFormat.format(data.total.users)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2 flex flex-col flex-wrap mt-2">
|
||||
<a
|
||||
href="/wish/tally/{id}"
|
||||
class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-no-wrap hover:opacity-75"
|
||||
class="bg-background rounded-xl px-4 py-2 flex-1 flex items-center whitespace-nowrap hover:opacity-75"
|
||||
>
|
||||
{$t('wish.tally.detail')}
|
||||
</a>
|
||||
|
@ -632,7 +632,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
@screen xl {
|
||||
.pity-summary {
|
||||
min-width: 320px;
|
||||
|
|
|
@ -142,7 +142,7 @@
|
|||
loading = true;
|
||||
loadingCons = true;
|
||||
|
||||
const url = new URL(`${__paimon.env.API_HOST}/wish`);
|
||||
const url = new URL(`${import.meta.env.VITE_API_HOST}/wish`);
|
||||
const query = new URLSearchParams({ banner: id });
|
||||
url.search = query.toString();
|
||||
|
||||
|
@ -626,7 +626,7 @@
|
|||
{numberFormat.format(legendary.percentage)}%
|
||||
</td>
|
||||
<td class="bg-background rounded-r-xl py-4 pr-4 text-legendary-from">
|
||||
<p class="font-semibold whitespace-no-wrap">
|
||||
<p class="font-semibold whitespace-nowrap">
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
|
@ -644,7 +644,7 @@
|
|||
{numberFormat.format(rare.percentage)}%
|
||||
</td>
|
||||
<td class="bg-background rounded-r-xl py-4 pr-4 text-rare-from">
|
||||
<p class="font-semibold whitespace-no-wrap">
|
||||
<p class="font-semibold whitespace-nowrap">
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
|
@ -818,7 +818,7 @@
|
|||
<Ad type="mobile" variant="lb" id="2" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
@screen md {
|
||||
.select-name {
|
||||
width: 100%;
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import sirv from 'sirv';
|
||||
import polka from 'polka';
|
||||
import compression from 'compression';
|
||||
import * as sapper from '@sapper/server';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { i18nMiddleware } from './i18n.js';
|
||||
|
||||
const { PORT, NODE_ENV } = process.env;
|
||||
const dev = NODE_ENV === 'development';
|
||||
|
||||
function serve(pathname) {
|
||||
const filter = (req) => req.path === pathname;
|
||||
const read = (file) => fs.readFileSync(path.join('__sapper__/dev', file));
|
||||
|
||||
return (req, res, next) => {
|
||||
if (filter(req)) {
|
||||
try {
|
||||
const file = path.posix.normalize(decodeURIComponent(req.path));
|
||||
const data = read(file);
|
||||
res.setHeader('Content-Type', 'text/javascript');
|
||||
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
||||
res.end(data);
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
next();
|
||||
} else {
|
||||
console.error(err);
|
||||
res.statusCode = 500;
|
||||
res.end('an error occurred while reading a static file from disk');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
polka() // You can also use Express
|
||||
.use(
|
||||
compression({ threshold: 0 }),
|
||||
sirv('static', { dev }),
|
||||
i18nMiddleware(),
|
||||
serve('/firebase-messaging-sw.js'),
|
||||
serve('/firebase-messaging-sw.js.map'),
|
||||
sapper.middleware(),
|
||||
)
|
||||
.listen(PORT, (err) => {
|
||||
if (err) console.log('error', err);
|
||||
});
|
|
@ -1,86 +1,72 @@
|
|||
import { timestamp, files, shell } from '@sapper/service-worker';
|
||||
import { version } from '$service-worker';
|
||||
|
||||
const ASSETS = `cache${timestamp}`;
|
||||
const CACHE = `cache${version}`;
|
||||
const channel = new BroadcastChannel('paimonmoe-sw');
|
||||
|
||||
// `shell` is an array of all the files generated by the bundler,
|
||||
// `files` is an array of everything in the `static` directory
|
||||
const to_cache = shell.concat(files);
|
||||
const staticAssets = new Set(to_cache);
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.open(ASSETS)
|
||||
.then(cache => cache.addAll(to_cache))
|
||||
.then(() => {
|
||||
self.skipWaiting();
|
||||
})
|
||||
);
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(self.skipWaiting());
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(
|
||||
caches.keys().then(async keys => {
|
||||
// delete old caches
|
||||
for (const key of keys) {
|
||||
if (key !== ASSETS) await caches.delete(key);
|
||||
}
|
||||
async function fetchAddCache(url) {
|
||||
try {
|
||||
const cache = await caches.open(CACHE);
|
||||
const cachedRes = await cache.match(url);
|
||||
|
||||
self.clients.claim();
|
||||
})
|
||||
);
|
||||
});
|
||||
if (cachedRes) return;
|
||||
|
||||
|
||||
/**
|
||||
* Fetch the asset from the network and store it in the cache.
|
||||
* Fall back to the cache if the user is offline.
|
||||
*/
|
||||
async function fetchAndCache(request) {
|
||||
const cache = await caches.open(`offline${timestamp}`)
|
||||
|
||||
try {
|
||||
const response = await fetch(request);
|
||||
cache.put(request, response.clone());
|
||||
return response;
|
||||
} catch (err) {
|
||||
const response = await cache.match(request);
|
||||
if (response) return response;
|
||||
|
||||
throw err;
|
||||
}
|
||||
const res = await fetch(url);
|
||||
cache.put(url, res.clone());
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
if (event.request.method !== 'GET' || event.request.headers.has('range')) return;
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
caches.keys().then(async (keys) => {
|
||||
let needUpdate = false;
|
||||
// delete old caches
|
||||
for (const key of keys) {
|
||||
if (key !== CACHE) {
|
||||
await caches.delete(key);
|
||||
needUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
const url = new URL(event.request.url);
|
||||
self.clients.claim();
|
||||
console.log('SW NEED UPDATE', needUpdate);
|
||||
if (needUpdate) {
|
||||
channel.postMessage({
|
||||
type: 'update',
|
||||
version,
|
||||
});
|
||||
}
|
||||
|
||||
// don't try to handle e.g. data: URIs
|
||||
const isHttp = url.protocol.startsWith('http');
|
||||
const isDevServerRequest = url.hostname === self.location.hostname && url.port !== self.location.port;
|
||||
const isStaticAsset = url.host === self.location.host && staticAssets.has(url.pathname);
|
||||
const skipBecauseUncached = event.request.cache === 'only-if-cached' && !isStaticAsset;
|
||||
|
||||
if (isHttp && !isDevServerRequest && !skipBecauseUncached) {
|
||||
event.respondWith(
|
||||
(async () => {
|
||||
// always serve static files and bundler-generated assets from cache.
|
||||
// if your application has other URLs with data that will never change,
|
||||
// set this variable to true for them and they will only be fetched once.
|
||||
const cachedAsset = isStaticAsset && await caches.match(event.request);
|
||||
|
||||
// for pages, you might want to serve a shell `service-worker-index.html` file,
|
||||
// which Sapper has generated for you. It's not right for every
|
||||
// app, but if it's right for yours then uncomment this section
|
||||
/*
|
||||
if (!cachedAsset && url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
|
||||
return caches.match('/service-worker-index.html');
|
||||
}
|
||||
*/
|
||||
|
||||
return cachedAsset || fetchAndCache(event.request);
|
||||
})()
|
||||
);
|
||||
}
|
||||
fetchAddCache('/');
|
||||
channel.addEventListener('message', (event) => {
|
||||
if (event.data.type === 'fetch-doc') {
|
||||
fetchAddCache(event.data.path);
|
||||
}
|
||||
});
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', async (event) => {
|
||||
if (!event.request.url.startsWith(self.location.origin) || event.request.method !== 'GET') return;
|
||||
|
||||
event.respondWith(
|
||||
(async () => {
|
||||
const cache = await caches.open(CACHE);
|
||||
const cachedRes = await cache.match(event.request);
|
||||
|
||||
if (cachedRes) {
|
||||
return cachedRes;
|
||||
}
|
||||
|
||||
const res = await fetch(event.request);
|
||||
cache.put(event.request, res.clone());
|
||||
return res;
|
||||
})(),
|
||||
);
|
||||
});
|
||||
|
|
|
@ -7,12 +7,12 @@ export const notificationSupported = writable(false);
|
|||
export const notificationAllowed = writable(true);
|
||||
|
||||
const firebaseConfig = {
|
||||
apiKey: __paimon.env.FIREBASE_API_KEY,
|
||||
authDomain: __paimon.env.FIREBASE_AUTH_DOMAIN,
|
||||
projectId: __paimon.env.FIREBASE_PROJECT_ID,
|
||||
storageBucket: __paimon.env.FIREBASE_STORAGE_BUCKET,
|
||||
messagingSenderId: __paimon.env.FIREBASE_MESSAGING_SENDER_ID,
|
||||
appId: __paimon.env.FIREBASE_APP_ID,
|
||||
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
|
||||
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
|
||||
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
|
||||
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
|
||||
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
|
||||
appId: import.meta.env.VITE_FIREBASE_APP_ID,
|
||||
};
|
||||
|
||||
let messaging;
|
||||
|
@ -67,7 +67,7 @@ async function initFirebase() {
|
|||
firebase.initializeApp(firebaseConfig);
|
||||
messaging = firebase.messaging();
|
||||
}
|
||||
|
||||
|
||||
await getToken();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import dayjs from 'dayjs';
|
||||
import { writable } from 'svelte/store';
|
||||
import debounce from 'lodash/debounce';
|
||||
import debounce from 'lodash.debounce';
|
||||
import localforage from 'localforage';
|
||||
import { t as $t } from 'svelte-i18n';
|
||||
|
||||
|
|
506
static/ads.txt
506
static/ads.txt
|
@ -1,506 +0,0 @@
|
|||
# Publisher Collective Ads.txt file 2021-11-22 09:49:38
|
||||
|
||||
# Display
|
||||
google.com, pub-6177961780147591, DIRECT, f08c47fec0942fa0
|
||||
google.com, pub-2145138345242651, DIRECT, f08c47fec0942fa0
|
||||
sovrn.com, 240955, DIRECT, fafdf38b16bf6b2b
|
||||
lijit.com, 240955, DIRECT, fafdf38b16bf6b2b
|
||||
lijit.com, 240955-eb, DIRECT, fafdf38b16bf6b2b
|
||||
gumgum.com, 11645, RESELLER, ffdef49475d318a9
|
||||
openx.com, 537120960, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 83499, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 538959099, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 539924617, RESELLER, 6a698e2ec38604c6
|
||||
openx.com, 540447791, RESELLER, 6a698e2ec38604c6
|
||||
pubmatic.com, 137711, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 156212, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 62483, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 156700, RESELLER, 5d62403b186f2ace
|
||||
openx.com, 539870614, DIRECT, 6a698e2ec38604c6
|
||||
rubiconproject.com, 18580, DIRECT, 0bfd66d529a55807
|
||||
rubiconproject.com, 20406, RESELLER, 0bfd66d529a55807
|
||||
rubiconproject.com, 17960, RESELLER, 0bfd66d529a55807
|
||||
gumgum.com, 11645, RESELLER, ffdef49475d318a9
|
||||
appnexus.com, 1360, RESELLER, f5ab79cb980f11d1
|
||||
indexexchange.com, 189344, DIRECT, 50b1c356f2c5c8fc
|
||||
indexexchange.com, 189345, DIRECT, 50b1c356f2c5c8fc
|
||||
pubmatic.com, 158540, RESELLER, 5d62403b186f2ace
|
||||
EMXDGT.com, 1290, DIRECT, 1e1d41537f7cad7f
|
||||
Appnexus.com, 1356, RESELLER, f5ab79cb980f11d1
|
||||
pubmatic.com, 158684, DIRECT, 5d62403b186f2ace
|
||||
appnexus.com, 11440, DIRECT, f5ab79cb980f11d1
|
||||
triplelift.com, 9332, DIRECT, 6c33edb13117fd86
|
||||
triplelift.com, 9332-EB, DIRECT, 6c33edb13117fd86
|
||||
yahoo.com, 56371, DIRECT
|
||||
yahoo.com, 56374, DIRECT
|
||||
rubiconproject.com, 9061, RESELLER, 0bfd66d529a55807
|
||||
rubiconproject.com, 10061, RESELLER, 0bfd66d529a55807
|
||||
rubiconproject.com, 17250, RESELLER, 0bfd66d529a55807
|
||||
improvedigital.com, 1787, DIRECT
|
||||
improvedigital.com, 1787, RESELLER
|
||||
google.com, pub-1386280613967939, RESELLER, f08c47fec0942fa0
|
||||
rhythmone.com, 1879993427, DIRECT, a670c89d4a324e47
|
||||
video.unrulymedia.com, 1879993427, DIRECT
|
||||
rhythmone.com, 907951026, DIRECT, a670c89d4a324e47
|
||||
video.unrulymedia.com, 907951026, DIRECT
|
||||
adagio.io, 1107, DIRECT
|
||||
rubiconproject.com, 19116, RESELLER, 0bfd66d529a55807
|
||||
pubmatic.com, 159110, RESELLER, 5d62403b186f2ace
|
||||
improvedigital.com, 1790, RESELLER
|
||||
onetag.com, 6b859b96c564fbe, RESELLER
|
||||
onetag.com, 74d276d460678b8, DIRECT
|
||||
yahoo.com, 58905, RESELLER, e1a5b5b6e3255540
|
||||
aol.com, 58905, RESELLER, e1a5b5b6e3255540
|
||||
appnexus.com, 13099, RESELLER
|
||||
smartadserver.com, 4111, RESELLER
|
||||
conversantmedia.com, 100316, RESELLER, 03113cd04947736d
|
||||
yieldmo.com, 2850174797239755356, DIRECT
|
||||
yieldmo.com, 2850176953179120222, DIRECT
|
||||
contextweb.com, 561118, RESELLER, 89ff185a4c4e857c
|
||||
appnexus.com, 7911, RESELLER
|
||||
rhythmone.com, 3463482822,RESELLER,a670c89d4a324e47
|
||||
video.unrulymedia.com, 3463482822, RESELLER
|
||||
rubiconproject.com, 17070, RESELLER, 0bfd66d529a55807
|
||||
pubnative.net, 1007284, RESELLER, d641df8625486a7b
|
||||
pubnative.net, 1007285, RESELLER, d641df8625486a7b
|
||||
pubnative.net, 1007286, RESELLER, d641df8625486a7b
|
||||
admanmedia.com, 746, RESELLER
|
||||
pubmatic.com, 160648, RESELLER, 5d62403b186f2ace
|
||||
indexexchange.com, 194520, RESELLER, 50b1c356f2c5c8fc
|
||||
onetag.com, 664e107d9f2b748, RESELLER
|
||||
conversantmedia.com, 100270, RESELLER, 03113cd04947736d
|
||||
improvedigital.com, 2021, DIRECT
|
||||
aps.amazon.com,26c60b4f-549a-4efd-8ae0-f00e07c46204,DIRECT
|
||||
pubmatic.com,157150,RESELLER,5d62403b186f2ace
|
||||
pubmatic.com, 160006, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 160096, RESELLER, 5d62403b186f2ace
|
||||
openx.com,540191398,RESELLER,6a698e2ec38604c6
|
||||
rubiconproject.com,18020,RESELLER,0bfd66d529a55807
|
||||
appnexus.com,1908,RESELLER,f5ab79cb980f11d1
|
||||
appnexus.com,3663,RESELLER,f5ab79cb980f11d1
|
||||
adtech.com,12068,RESELLER,e1a5b5b6e3255540
|
||||
districtm.io,100962,RESELLER,3fd707be9c4527c3
|
||||
rhythmone.com,1654642120,RESELLER,a670c89d4a324e47
|
||||
yahoo.com,55029,RESELLER,e1a5b5b6e3255540
|
||||
indexexchange.com,192410,RESELLER,50b1c356f2c5c8fc
|
||||
ad-generation.jp, 12474, RESELLER, 7f4ea9029ac04e53
|
||||
adtech.com, 4958, DIRECT, e1a5b5b6e3255540
|
||||
triplelift.com,7194,DIRECT,6c33edb13117fd86
|
||||
EMXDGT.com,1803, DIRECT, 1e1d41537f7cad7f
|
||||
Appnexus.com, 1356, RESELLER, f5ab79cb980f11d1
|
||||
smaato.com,1100044650,RESELLER,07bcf65f187117b4
|
||||
gumgum.com,14141,RESELLER,ffdef49475d318a9
|
||||
Contextweb.com,562377,DIRECT,89ff185a4c4e857c
|
||||
indexexchange.com, 193657, DIRECT
|
||||
admanmedia.com,726,RESELLER
|
||||
yieldmo.com,2719019867620450718,RESELLER
|
||||
sharethrough.com,7144eb80,RESELLER
|
||||
loopme.com,11405,RESELLER
|
||||
emxdgt.com,2009,RESELLER,1e1d41537f7cad7f
|
||||
yahoo.com, 59100, DIRECT
|
||||
conversantmedia.com, 42024, DIRECT, 03113cd04947736d
|
||||
smartadserver.com,4125,RESELLER,060d053dcf45cbf3
|
||||
contextweb.com, 562541, RESELLER, 89ff185a4c4e857c
|
||||
themediagrid.com,jtqkmp,RESELLER,35d5010d7789b49d
|
||||
sovrn.com,375328,RESELLER,fafdf38b16bf6b2b
|
||||
lijit.com,375328,RESELLER,fafdf38b16bf6b2b
|
||||
smaato.com, 1100046863, DIRECT, 07bcf65f187117b4
|
||||
smaato.com, 1100004890, DIRECT, 07bcf65f187117b4
|
||||
adcolony.com, 496220845654deec, RESELLER, 1ad675c9de6b5176
|
||||
admanmedia.com, 552, RESELLER
|
||||
appnexus.com, 1752, RESELLER, f5ab79cb980f11d1
|
||||
appnexus.com, 4052, RESELLER
|
||||
appnexus.com, 8790, RESELLER, f5ab79cb980f11d1
|
||||
bidmachine.io, 36, RESELLER
|
||||
bidmachine.io, 60, RESELLER
|
||||
bidmachine.io, 74, RESELLER
|
||||
bidmachine.io, 77, RESELLER
|
||||
blis.com, 86, RESELLER, 61453ae19a4b73f4
|
||||
contextweb.com, 558622, RESELLER, 89ff185a4c4e857c
|
||||
engagebdr.com, 16, RESELLER
|
||||
gammassp.com, 1516331892, RESELLER, 31ac53fec2772a83
|
||||
indexexchange.com, 183920, RESELLER, 50b1c356f2c5c8fc
|
||||
indexexchange.com, 184270, RESELLER, 50b1c356f2c5c8fc
|
||||
inmobi.com, 55049d2e109d4ac1820ca1432dda4e13, RESELLER, 83e75a7ae333ca9d
|
||||
mobilefuse.com, 2281, RESELLER
|
||||
openx.com, 540421297, RESELLER, 6a698e2ec38604c6
|
||||
pokkt.com, 5886, RESELLER, c45702d9311e25fd
|
||||
pubmatic.com, 156177, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 156389, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 156424, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 156425, RESELLER, 5d62403b186f2ace
|
||||
pubnative.net, 1004796, RESELLER, d641df8625486a7b
|
||||
pubnative.net, 1007194, RESELLER, d641df8625486a7b
|
||||
rhythmone.com, 4201299756, RESELLER, a670c89d4a324e47
|
||||
smartadserver.com, 3117, RESELLER
|
||||
startapp.com, smt, RESELLER
|
||||
xad.com, 241, RESELLER, 81cbf0a75a5e0e9a
|
||||
indexexchange.com, 184665, RESELLER, 50b1c356f2c5c8fc
|
||||
synacor.com, 82321, RESELLER, e108f11b2cdf7d5b
|
||||
33across.com, 0014000001aXjnGAAS, RESELLER, bbea06d9c4d2853c
|
||||
adtech.com, 12094, RESELLER
|
||||
advangelists.com, 8d3bba7425e7c98c50f52ca1b52d3735, RESELLER, 60d26397ec060f98
|
||||
appnexus.com, 10239, RESELLER, f5ab79cb980f11d1
|
||||
emxdgt.com, 326, RESELLER, 1e1d41537f7cad7f
|
||||
google.com, pub-9557089510405422, RESELLER, f08c47fec0942fa0
|
||||
gumgum.com, 13318, RESELLER, ffdef49475d318a9
|
||||
openx.com, 537120563, RESELLER, 6a698e2ec38604c6
|
||||
pubmatic.com, 156423, RESELLER, 5d62403b186f2ace
|
||||
rhythmone.com, 2439829435, RESELLER, a670c89d4a324e47
|
||||
rubiconproject.com, 16414, RESELLER, 0bfd66d529a55807
|
||||
advertising.com, 19623, RESELLER
|
||||
indexexchange.com, 183965, RESELLER, 50b1c356f2c5c8fc
|
||||
pubmatic.com, 156084, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 156325, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 156458, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 18222, RESELLER, 0bfd66d529a55807
|
||||
appnexus.com, 9316, RESELLER, f5ab79cb980f11d1
|
||||
appnexus.com, 4052, RESELLER, f5ab79cb980f11d1
|
||||
conversantmedia.com, 20923, RESELLER
|
||||
openx.com, 540031703, RESELLER, 6a698e2ec38604c6
|
||||
appnexus.com, 1908, RESELLER, f5ab79cb980f11d1
|
||||
districtm.io, 101769, RESELLER, 3fd707be9c4527c3
|
||||
google.com, pub-9685734445476814, RESELLER, f08c47fec0942fa0
|
||||
improvedigital.com, 1669, RESELLER
|
||||
indexexchange.com, 191740, RESELLER, 50b1c356f2c5c8fc
|
||||
themediagrid.com, P5JONV, RESELLER, 35d5010d7789b49d
|
||||
onetag.com, 572a470226457b8, RESELLER
|
||||
openx.com, 540401713, RESELLER, 6a698e2ec38604c6
|
||||
pubmatic.com, 156344, RESELLER, 5d62403b186f2ace
|
||||
advertising.com, 28605, RESELLER
|
||||
appnexus.com, 6849, RESELLER, f5ab79cb980f11d1
|
||||
indexexchange.com, 182257, RESELLER, 50b1c356f2c5c8fc
|
||||
pubmatic.com, 159277, RESELLER, 5d62403b186f2ace
|
||||
rhythmone.com, 905992537, RESELLER, a670c89d4a324e47
|
||||
rubiconproject.com, 15268, RESELLER, 0bfd66d529a55807
|
||||
spotx.tv, 285547, RESELLER, 7842df1d2fe2db34
|
||||
spotxchange.com, 285547, RESELLER, 7842df1d2fe2db34
|
||||
video.unrulymedia.com, 905992537, RESELLER, a670c89d4a324e47
|
||||
rubiconproject.com, 13344, RESELLER, 0bfd66d529a55807
|
||||
spotx.tv, 94794, RESELLER, 7842df1d2fe2db34
|
||||
spotxchange.com, 94794, RESELLER, 7842df1d2fe2db34
|
||||
advertising.com, 8603, RESELLER
|
||||
aol.com, 53392, RESELLER
|
||||
freewheel.tv, 799841, RESELLER
|
||||
freewheel.tv, 799921, RESELLER
|
||||
pubmatic.com, 156307, RESELLER, 5d62403b186f2ace
|
||||
rhythmone.com, 1166984029, RESELLER, a670c89d4a324e47
|
||||
spotx.tv, 71451, RESELLER, 7842df1d2fe2db34
|
||||
spotxchange.com, 71451, RESELLER, 7842df1d2fe2db34
|
||||
tremorhub.com, z87wm, RESELLER, 1a4e959a1b50034a
|
||||
aralego.com, par-488A3E6BD8D997D0ED8B3BD34D8BA4B, RESELLER
|
||||
ucfunnel.com, par-488A3E6BD8D997D0ED8B3BD34D8BA4B, RESELLER
|
||||
yahoo.com, 55317, RESELLER
|
||||
pubnx.com, 337-1, RESELLER, 8728b7e97e589da4
|
||||
justpremium.com,2776,DIRECT
|
||||
appnexus.com, 7118, RESELLER
|
||||
improvedigital.com, 185, RESELLER
|
||||
indexexchange.com, 189872, RESELLER
|
||||
openx.com, 539653634, RESELLER, 6a698e2ec38604c6
|
||||
rhythmone.com, 4116102010, RESELLER, a670c89d4a324e47
|
||||
video.unrulymedia.com, 4116102010, RESELLER
|
||||
adingo.jp, 24292, DIRECT
|
||||
pubmatic.com, 156313, RESELLER, 5d62403b186f2ace
|
||||
appnexus.com, 7044, RESELLER, f5ab79cb980f11d1
|
||||
openx.com, 540679900, RESELLER, 6a698e2ec38604c6
|
||||
webeyemob.com, 70080, RESELLER
|
||||
admixer.net, 3bc509b2-6568-4bd8-a997-9859ba0c9118, RESELLER
|
||||
pubmatic.com, 158060, RESELLER, 5d62403b186f2ace
|
||||
adcolony.com, 801e49d1be83b5f9, RESELLER, 1ad675c9de6b5176
|
||||
amxrtb.com, 105199357, DIRECT
|
||||
indexexchange.com, 191503, RESELLER
|
||||
appnexus.com, 11786, RESELLER
|
||||
appnexus.com, 9393, RESELLER
|
||||
appnexus.com, 3153, RESELLER, f5ab79cb980f11d1
|
||||
appnexus.com, 11924, RESELLER, f5ab79cb980f11d1
|
||||
smartadserver.com, 3056, RESELLER
|
||||
Appnexus.com, 1356, RESELLER, f5ab79cb980f11d1
|
||||
appnexus.com, 1908, RESELLER, f5ab79cb980f11d1
|
||||
lijit.com, 260380, RESELLER, fafdf38b16bf6b2b
|
||||
sovrn.com, 260380, RESELLER, fafdf38b16bf6b2b
|
||||
openx.com, 538959099, RESELLER, 6a698e2ec38604c6
|
||||
pubmatic.com, 137711, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 17960, RESELLER, 0bfd66d529a55807
|
||||
pubmatic.com, 158355, RESELLER, 5d62403b186f2ace
|
||||
advertising.com, 28305, RESELLER
|
||||
avct.cloud, 5f7eef8974c1ab4156b8df8e, DIRECT
|
||||
smartadserver.com, 3894, DIRECT
|
||||
contextweb.com, 560288, RESELLER, 89ff185a4c4e857c
|
||||
pubmatic.com, 156439, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 154037, RESELLER, 5d62403b186f2ace
|
||||
rubiconproject.com, 16114, RESELLER, 0bfd66d529a55807
|
||||
openx.com, 537149888, RESELLER, 6a698e2ec38604c6
|
||||
appnexus.com, 3703, RESELLER, f5ab79cb980f11d1
|
||||
districtm.io, 101760, RESELLER, 3fd707be9c4527c3
|
||||
loopme.com, 5679, RESELLER, 6c8d5f95897a5a3b
|
||||
xad.com, 958, RESELLER, 81cbf0a75a5e0e9a
|
||||
rhythmone.com, 2564526802, RESELLER, a670c89d4a324e47
|
||||
smaato.com, 1100044045, RESELLER, 07bcf65f187117b4
|
||||
pubnative.net, 1006576, RESELLER, d641df8625486a7b
|
||||
adyoulike.com, b4bf4fdd9b0b915f746f6747ff432bde, RESELLER
|
||||
axonix.com, 57264, RESELLER
|
||||
admanmedia.com, 43, RESELLER
|
||||
smartadserver.com, 4012, DIRECT
|
||||
smartadserver.com, 4016, DIRECT
|
||||
smartadserver.com, 4071, DIRECT
|
||||
smartadserver.com, 4073, DIRECT
|
||||
smartadserver.com, 4074, DIRECT
|
||||
themediagrid.com, GD57SQ, DIRECT, 35d5010d7789b49d
|
||||
themediagrid.com, TU8HG3, DIRECT, 35d5010d7789b49d
|
||||
outbrain.com, 0043a849877c1a638231d82dd1b7e08b62, DIRECT
|
||||
appnexus.com, 7597, RESELLER, f5ab79cb980f11d1
|
||||
smartadserver.com, 1827, RESELLER
|
||||
improvedigital.com, 335, RESELLER
|
||||
appnexus.com, 3538, RESELLER
|
||||
appnexus.com, 3539, RESELLER
|
||||
appnexus.com, 3540, RESELLER
|
||||
appnexus.com, 7290, RESELLER
|
||||
sharethrough.com, 8af06d76, DIRECT, d53b998a7bd4ecd2
|
||||
network-n.com, pa_1f00a408, DIRECT
|
||||
network-n.com, pa_e8715185, DIRECT
|
||||
network-n.com, pa_601d8ead, DIRECT
|
||||
network-n.com, pa_a94525bd, DIRECT
|
||||
network-n.com, nn_dc828890, DIRECT
|
||||
network-n.com, pa_c73f329c, DIRECT
|
||||
network-n.com, pa_2df17875, DIRECT
|
||||
network-n.com, pa_90a1369b, DIRECT
|
||||
network-n.com, nn_a92f3c5a, DIRECT
|
||||
network-n.com, pa_bf035bcc, DIRECT
|
||||
network-n.com, pa_6eed24a5, DIRECT
|
||||
network-n.com, pa_c8a21379, DIRECT
|
||||
network-n.com, pa_989c8bff, DIRECT
|
||||
network-n.com, nn_67b3bb73, DIRECT
|
||||
network-n.com, nn_b811ecf3, DIRECT
|
||||
network-n.com, pa_eef26576, DIRECT
|
||||
network-n.com, pa_dcddaaf3, DIRECT
|
||||
network-n.com, pa_778becb4, DIRECT
|
||||
network-n.com, pa_21f59c37, DIRECT
|
||||
network-n.com, pa_c01f38e8, DIRECT
|
||||
network-n.com, pa_2d21e00f, DIRECT
|
||||
network-n.com, pa_d176ae16, DIRECT
|
||||
network-n.com, pa_ebb120be, DIRECT
|
||||
network-n.com, pa_fc69d8ef, DIRECT
|
||||
network-n.com, pa_2c42efa0, DIRECT
|
||||
network-n.com, pa_553f610d, DIRECT
|
||||
network-n.com, pa_96068c5c, DIRECT
|
||||
network-n.com, pa_ab87406f, DIRECT
|
||||
network-n.com, nn_a5e5e413, DIRECT
|
||||
network-n.com, pa_e890a22a, DIRECT
|
||||
network-n.com, nn_83d97ca3, DIRECT
|
||||
network-n.com, pa_9435d9ba, DIRECT
|
||||
network-n.com, pa_ac496ffe, DIRECT
|
||||
network-n.com, pa_bc60f533, DIRECT
|
||||
network-n.com, pa_24924b4f, DIRECT
|
||||
network-n.com, pa_cefd0185, DIRECT
|
||||
network-n.com, nn_f75084c9, DIRECT
|
||||
network-n.com, pa_9e3ef9d5, DIRECT
|
||||
network-n.com, nn_0c0a2f6a, DIRECT
|
||||
network-n.com, pa_6f8e433a, DIRECT
|
||||
network-n.com, nn_52929841, DIRECT
|
||||
network-n.com, nn_16fa43c0, DIRECT
|
||||
network-n.com, pa_709fd813, DIRECT
|
||||
network-n.com, pa_ab112065, DIRECT
|
||||
network-n.com, pa_fc8784a7, DIRECT
|
||||
network-n.com, pa_6450db25, DIRECT
|
||||
network-n.com, nn_0b8aac73, DIRECT
|
||||
network-n.com, nn_bb9e3d06, DIRECT
|
||||
network-n.com, pa_90d616a0, DIRECT
|
||||
network-n.com, nn_e3dedfc5, DIRECT
|
||||
network-n.com, pa_67d19afe, DIRECT
|
||||
network-n.com, pa_c850e4e2, DIRECT
|
||||
network-n.com, pa_569c4b29, DIRECT
|
||||
network-n.com, pa_58acb23d, DIRECT
|
||||
network-n.com, pa_c52e2e53, DIRECT
|
||||
network-n.com, pa_d1a744aa, DIRECT
|
||||
network-n.com, pa_c0fd608c, DIRECT
|
||||
network-n.com, pa_e97f4d64, DIRECT
|
||||
network-n.com, pa_abb78c2d, DIRECT
|
||||
network-n.com, pa_d83981e9, DIRECT
|
||||
network-n.com, pa_9a65dfce, DIRECT
|
||||
network-n.com, pa_98a54d0d, DIRECT
|
||||
network-n.com, nn_bac8480a, DIRECT
|
||||
network-n.com, pa_bee9082e, DIRECT
|
||||
network-n.com, pa_0312b635, DIRECT
|
||||
network-n.com, pa_777b07ca, DIRECT
|
||||
network-n.com, pa_07aaf1a3, DIRECT
|
||||
network-n.com, pa_f2f8099b, DIRECT
|
||||
network-n.com, nn_1cdeb505, DIRECT
|
||||
network-n.com, pa_d2cb5c22, DIRECT
|
||||
network-n.com, pa_f8d9d92f, DIRECT
|
||||
network-n.com, pa_7c030473, DIRECT
|
||||
network-n.com, pa_debf04a3, DIRECT
|
||||
network-n.com, pa_58bd4c90, DIRECT
|
||||
network-n.com, nn_93ace404, DIRECT
|
||||
network-n.com, pa_91564061, DIRECT
|
||||
network-n.com, pa_7fa5cef8, DIRECT
|
||||
network-n.com, nn_991ceb73, DIRECT
|
||||
network-n.com, pa_2a5a6810, DIRECT
|
||||
network-n.com, pa_deb3cc73, DIRECT
|
||||
network-n.com, nn_ccf14111, DIRECT
|
||||
network-n.com, nn_dd147396, DIRECT
|
||||
network-n.com, nn_c70bf603, DIRECT
|
||||
network-n.com, pa_5012520c, DIRECT
|
||||
network-n.com, pa_7113c86e, DIRECT
|
||||
network-n.com, pa_ef8dab28, DIRECT
|
||||
network-n.com, pa_d1ad6473, DIRECT
|
||||
network-n.com, pa_755836fa, DIRECT
|
||||
network-n.com, pa_fec65292, DIRECT
|
||||
network-n.com, pa_f90a5700, DIRECT
|
||||
network-n.com, pa_8f187460, DIRECT
|
||||
network-n.com, pa_bb1db0e3, DIRECT
|
||||
network-n.com, pa_5f907e2a, DIRECT
|
||||
network-n.com, pa_73adf5f4, DIRECT
|
||||
network-n.com, pa_17cde183, DIRECT
|
||||
network-n.com, nn_d590fc4b, DIRECT
|
||||
network-n.com, pa_e144c3fb, DIRECT
|
||||
network-n.com, pa_695cef04, DIRECT
|
||||
network-n.com, nn_20819473, DIRECT
|
||||
network-n.com, pa_ae37eff2, DIRECT
|
||||
network-n.com, pa_5b7caaf0, DIRECT
|
||||
network-n.com, pa_cfc7cf7f, DIRECT
|
||||
network-n.com, pa_8b270543, DIRECT
|
||||
network-n.com, pa_17e2f1c8, DIRECT
|
||||
network-n.com, pa_ed7b677a, DIRECT
|
||||
network-n.com, nn_da08cd6a, DIRECT
|
||||
network-n.com, nn_ea8d1b4e, DIRECT
|
||||
network-n.com, pa_740be19b, DIRECT
|
||||
network-n.com, pa_14616587, DIRECT
|
||||
network-n.com, pa_207cb2a8, DIRECT
|
||||
network-n.com, pa_b843870e, DIRECT
|
||||
network-n.com, pa_50c4b9dd, DIRECT
|
||||
network-n.com, nn_40020810, DIRECT
|
||||
network-n.com, nn_0ab02a98, DIRECT
|
||||
network-n.com, pa_2b66dc72, DIRECT
|
||||
network-n.com, nn_218286a3, DIRECT
|
||||
network-n.com, pa_cd3ca5de, DIRECT
|
||||
network-n.com, pa_7da8e293, DIRECT
|
||||
network-n.com, pa_0947c454, DIRECT
|
||||
network-n.com, pa_d684b280, DIRECT
|
||||
network-n.com, pa_c0c730e2, DIRECT
|
||||
network-n.com, pa_ddf947b1, DIRECT
|
||||
network-n.com, nn_ad9aa896, DIRECT
|
||||
network-n.com, nn_668ba8bf, DIRECT
|
||||
network-n.com, nn_5a267a53, DIRECT
|
||||
network-n.com, pa_064fb665, DIRECT
|
||||
network-n.com, nn_3f8d45b3, DIRECT
|
||||
network-n.com, nn_eae4fb13, DIRECT
|
||||
network-n.com, pa_57f34d61, DIRECT
|
||||
network-n.com, nn_7442e9fc, DIRECT
|
||||
network-n.com, pa_db5ae67a, DIRECT
|
||||
network-n.com, pa_30e0139a, DIRECT
|
||||
network-n.com, pa_43ea0a09, DIRECT
|
||||
network-n.com, pa_2243b60b, DIRECT
|
||||
network-n.com, nn_7004e887, DIRECT
|
||||
network-n.com, pa_39bf5b96, DIRECT
|
||||
network-n.com, pa_c201a0b6, DIRECT
|
||||
network-n.com, nn_eef26576, DIRECT
|
||||
network-n.com, nn_c73f329c, DIRECT
|
||||
network-n.com, pa_6cdbf87f, DIRECT
|
||||
network-n.com, nn_a94525bd, DIRECT
|
||||
network-n.com, pa_0b71c320, DIRECT
|
||||
network-n.com, nn_c69fccc0, DIRECT
|
||||
network-n.com, pa_2e0fe469, DIRECT
|
||||
network-n.com, nn_601d8ead, DIRECT
|
||||
network-n.com, pa_5e3e6279, DIRECT
|
||||
network-n.com, pa_82d73b26, DIRECT
|
||||
network-n.com, pa_7bef0373, DIRECT
|
||||
network-n.com, nn_39bf5b96, DIRECT
|
||||
network-n.com, pa_0e5827bf, DIRECT
|
||||
network-n.com, pa_5471d680, DIRECT
|
||||
network-n.com, pa_ad4e5de9, DIRECT
|
||||
network-n.com, pa_b568ea31, DIRECT
|
||||
network-n.com, pa_177acef3, DIRECT
|
||||
network-n.com, pa_fda9576c, DIRECT
|
||||
network-n.com, pa_02b64c13, DIRECT
|
||||
network-n.com, pa_8c91333e, DIRECT
|
||||
network-n.com, pa_51ef4921, DIRECT
|
||||
network-n.com, pa_622654f6, DIRECT
|
||||
network-n.com, pa_78f6e17e, DIRECT
|
||||
network-n.com, pa_3da102b3, DIRECT
|
||||
network-n.com, pa_7a0dc518, DIRECT
|
||||
network-n.com, pa_1c1156a0, DIRECT
|
||||
network-n.com, pa_614dd772, DIRECT
|
||||
network-n.com, pa_0d3e7ddf, DIRECT
|
||||
network-n.com, pa_b3a8ca4e, DIRECT
|
||||
network-n.com, nn_c9936d92, DIRECT
|
||||
network-n.com, pa_58d7eb0a, DIRECT
|
||||
network-n.com, pa_dc781657, DIRECT
|
||||
network-n.com, pa_50dd4c60, DIRECT
|
||||
network-n.com, pa_c69fccc0, DIRECT
|
||||
network-n.com, pa_d9bd0d92, DIRECT
|
||||
network-n.com, pa_51ee7e6e, DIRECT
|
||||
network-n.com, pa_c9936d92, DIRECT
|
||||
network-n.com, pa_f2af0d42, DIRECT
|
||||
network-n.com, pa_fbbe6928, DIRECT
|
||||
network-n.com, pa_1591dae1, DIRECT
|
||||
network-n.com, pa_738413d8, DIRECT
|
||||
network-n.com, pa_a276e152, DIRECT
|
||||
network-n.com, pa_a730b684, DIRECT
|
||||
network-n.com, pa_a863cb34, DIRECT
|
||||
network-n.com, pa_3f85e405, DIRECT
|
||||
network-n.com, pa_c201a0b6, DIRECT
|
||||
network-n.com, pa_cddb4912, DIRECT
|
||||
network-n.com, pa_eaba5433, DIRECT
|
||||
network-n.com, pa_bdc939c3, DIRECT
|
||||
network-n.com, pa_2b011291, DIRECT
|
||||
network-n.com, pa_c43098ca, DIRECT
|
||||
network-n.com, pa_2b011291, DIRECT
|
||||
network-n.com, pa_2b011291, DIRECT
|
||||
network-n.com, pa_a80811f1, DIRECT
|
||||
network-n.com, pa_6bda6bb5, DIRECT
|
||||
|
||||
# Video
|
||||
EMXDGT.com,1309, DIRECT, 1e1d41537f7cad7f
|
||||
appnexus.com, 1356, RESELLER, f5ab79cb980f11d1
|
||||
pubmatic.com, 158682, DIRECT, 5d62403b186f2ace
|
||||
openx.com, 540886248, DIRECT, 6a698e2ec38604c6
|
||||
google.com, pub-5760410923284845, DIRECT, f08c47fec0942fa0
|
||||
themediagrid.com,EB14XD,DIRECT,35d5010d7789b49d
|
||||
advertising.com, 28814, RESELLER
|
||||
advertising.com, 28816, RESELLER
|
||||
appnexus.com, 12564, RESELLER, f5ab79cb980f11d1
|
||||
indexexchange.com, 193162, RESELLER
|
||||
google.com, pub-5760410923284845, RESELLER, f08c47fec0942fa0
|
||||
pubmatic.com, 159247, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 160127, RESELLER, 5d62403b186f2ace
|
||||
rhythmone.com, 4245644886, RESELLER, a670c89d4a324e47
|
||||
video.unrulymedia.com, 4245644886, RESELLER
|
||||
districtm.io, 102080, DIRECT, 3fd707be9c4527c3
|
||||
appnexus.com, 1908, RESELLER, f5ab79cb980f11d1
|
||||
advertising.com, 28784, DIRECT
|
||||
advertising.com, 28783, DIRECT
|
||||
indexexchange.com, 193792, DIRECT
|
||||
sonobi.com, a015179bd7, DIRECT, d1a215d9eb5aee9e
|
||||
rhythmone.com, 1059622079, RESELLER, a670c89d4a324e47
|
||||
contextweb.com, 560606, RESELLER, 89ff185a4c4e857c
|
||||
sonobi.com, 649aabf138, DIRECT, d1a215d9eb5aee9e
|
||||
spotxchange.com, 268145, DIRECT, 7842df1d2fe2db34
|
||||
spotx.tv, 268145, DIRECT, 7842df1d2fe2db34
|
||||
spotxchange.com, 268145, RESELLER, 7842df1d2fe2db34
|
||||
spotx.tv, 268145, RESELLER, 7842df1d2fe2db34
|
||||
freewheel.tv, 1237631, DIRECT
|
||||
freewheel.tv, 1237711, RESELLER
|
||||
aps.amazon.com,968a0f5c-e5ed-4ba9-bf43-8be1f5b68988,DIRECT
|
||||
pubmatic.com, 160887, RESELLER, 5d62403b186f2ace
|
||||
pubmatic.com, 160887, DIRECT, 5d62403b186f2ace
|
||||
primis.tech, 28588, DIRECT, b6b21d256ef43532
|
||||
spotxchange.com, 84294, RESELLER, 7842df1d2fe2db34
|
||||
spotx.tv, 84294, RESELLER, 7842df1d2fe2db34
|
||||
advertising.com, 7372, RESELLER
|
||||
yahoo.com, 59260, RESELLER
|
||||
pubmatic.com, 156595, RESELLER, 5d62403b186f2ace
|
||||
google.com, pub-1320774679920841, RESELLER, f08c47fec0942fa0
|
||||
openx.com, 540258065, RESELLER, 6a698e2ec38604c6
|
||||
rubiconproject.com, 20130, RESELLER, 0bfd66d529a55807
|
||||
freewheel.tv, 19129, RESELLER, 74e8e47458f74754
|
||||
freewheel.tv, 19133, RESELLER, 74e8e47458f74754
|
||||
smartadserver.com, 3436, RESELLER, 060d053dcf45cbf3
|
||||
indexexchange.com, 191923, RESELLER, 50b1c356f2c5c8fc
|
||||
contextweb.com, 562350, RESELLER, 89ff185a4c4e857c
|
||||
tremorhub.com, mb9eo-oqsbf, RESELLER, 1a4e959a1b50034a
|
||||
telaria.com, mb9eo-oqsbf, RESELLER, 1a4e959a1b50034a
|
||||
adform.com, 2078, RESELLER
|
||||
xandr.com, 13171, RESELLER
|
||||
supply.colossusssp.com, 290, RESELLER, 6c5b49d96ec1b458
|
||||
emxdgt.com, 1349, RESELLER, 1e1d41537f7cad7f
|
||||
Media.net, 8CU695QH7, RESELLER
|
|
@ -1,11 +1,34 @@
|
|||
const sveltePreprocess = require('svelte-preprocess');
|
||||
const postcss = require('./postcss.config');
|
||||
// const sveltePreprocess = require('svelte-preprocess');
|
||||
// const postcss = require('./postcss.config');
|
||||
|
||||
const preprocess = sveltePreprocess({
|
||||
defaults: {
|
||||
style: 'postcss',
|
||||
// const preprocess = sveltePreprocess({
|
||||
// defaults: {
|
||||
// style: 'postcss',
|
||||
// },
|
||||
// postcss,
|
||||
// });
|
||||
|
||||
// module.exports = { preprocess };
|
||||
|
||||
import preprocess from 'svelte-preprocess';
|
||||
import adapter from '@sveltejs/adapter-static';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
prerender: {
|
||||
default: true,
|
||||
},
|
||||
serviceWorker: {
|
||||
register: false,
|
||||
},
|
||||
},
|
||||
postcss,
|
||||
});
|
||||
preprocess: [
|
||||
preprocess({
|
||||
postcss: true,
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = { preprocess };
|
||||
export default config;
|
||||
|
|
178
tailwind.config.cjs
Normal file
178
tailwind.config.cjs
Normal file
|
@ -0,0 +1,178 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
theme: {
|
||||
screens: {
|
||||
sm: '640px',
|
||||
md: '768px',
|
||||
lg: '1024px',
|
||||
xl: '1280px',
|
||||
},
|
||||
fontFamily: {
|
||||
display: ['Catamaran', 'sans-serif'],
|
||||
body: ['Poppins', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
transparent: 'transparent',
|
||||
current: 'currentColor',
|
||||
|
||||
black: '#000',
|
||||
white: '#fff',
|
||||
|
||||
gray: {
|
||||
100: '#f7fafc',
|
||||
200: '#edf2f7',
|
||||
300: '#e2e8f0',
|
||||
400: '#cbd5e0',
|
||||
500: '#a0aec0',
|
||||
600: '#718096',
|
||||
700: '#4a5568',
|
||||
800: '#2d3748',
|
||||
900: '#1a202c',
|
||||
},
|
||||
red: {
|
||||
100: '#fff5f5',
|
||||
200: '#fed7d7',
|
||||
300: '#feb2b2',
|
||||
400: '#fc8181',
|
||||
500: '#f56565',
|
||||
600: '#e53e3e',
|
||||
700: '#c53030',
|
||||
800: '#9b2c2c',
|
||||
900: '#742a2a',
|
||||
},
|
||||
orange: {
|
||||
100: '#fffaf0',
|
||||
200: '#feebc8',
|
||||
300: '#fbd38d',
|
||||
400: '#f6ad55',
|
||||
500: '#ed8936',
|
||||
600: '#dd6b20',
|
||||
700: '#c05621',
|
||||
800: '#9c4221',
|
||||
900: '#7b341e',
|
||||
},
|
||||
yellow: {
|
||||
100: '#fffff0',
|
||||
200: '#fefcbf',
|
||||
300: '#faf089',
|
||||
400: '#f6e05e',
|
||||
500: '#ecc94b',
|
||||
600: '#d69e2e',
|
||||
700: '#b7791f',
|
||||
800: '#975a16',
|
||||
900: '#744210',
|
||||
},
|
||||
green: {
|
||||
100: '#f0fff4',
|
||||
200: '#c6f6d5',
|
||||
300: '#9ae6b4',
|
||||
400: '#68d391',
|
||||
500: '#48bb78',
|
||||
600: '#38a169',
|
||||
700: '#2f855a',
|
||||
800: '#276749',
|
||||
900: '#22543d',
|
||||
},
|
||||
teal: {
|
||||
100: '#e6fffa',
|
||||
200: '#b2f5ea',
|
||||
300: '#81e6d9',
|
||||
400: '#4fd1c5',
|
||||
500: '#38b2ac',
|
||||
600: '#319795',
|
||||
700: '#2c7a7b',
|
||||
800: '#285e61',
|
||||
900: '#234e52',
|
||||
},
|
||||
blue: {
|
||||
100: '#ebf8ff',
|
||||
200: '#bee3f8',
|
||||
300: '#90cdf4',
|
||||
400: '#63b3ed',
|
||||
500: '#4299e1',
|
||||
600: '#3182ce',
|
||||
700: '#2b6cb0',
|
||||
800: '#2c5282',
|
||||
900: '#2a4365',
|
||||
},
|
||||
indigo: {
|
||||
100: '#ebf4ff',
|
||||
200: '#c3dafe',
|
||||
300: '#a3bffa',
|
||||
400: '#7f9cf5',
|
||||
500: '#667eea',
|
||||
600: '#5a67d8',
|
||||
700: '#4c51bf',
|
||||
800: '#434190',
|
||||
900: '#3c366b',
|
||||
},
|
||||
purple: {
|
||||
100: '#faf5ff',
|
||||
200: '#e9d8fd',
|
||||
300: '#d6bcfa',
|
||||
400: '#b794f4',
|
||||
500: '#9f7aea',
|
||||
600: '#805ad5',
|
||||
700: '#6b46c1',
|
||||
800: '#553c9a',
|
||||
900: '#44337a',
|
||||
},
|
||||
pink: {
|
||||
100: '#fff5f7',
|
||||
200: '#fed7e2',
|
||||
300: '#fbb6ce',
|
||||
400: '#f687b3',
|
||||
500: '#ed64a6',
|
||||
600: '#d53f8c',
|
||||
700: '#b83280',
|
||||
800: '#97266d',
|
||||
900: '#702459',
|
||||
},
|
||||
|
||||
background: '#202442',
|
||||
'background-secondary': '#25294A',
|
||||
item: '#2D325A',
|
||||
primary: '#4E7CFF',
|
||||
button: '#394076',
|
||||
rare: {
|
||||
from: '#D28FD6',
|
||||
to: '#665680',
|
||||
},
|
||||
legendary: {
|
||||
from: '#FFB13F',
|
||||
to: '#846332',
|
||||
},
|
||||
},
|
||||
fontSize: {
|
||||
xs: '0.75rem',
|
||||
sm: '0.875rem',
|
||||
base: '1rem',
|
||||
lg: '1.125rem',
|
||||
xl: '1.25rem',
|
||||
'2xl': '1.5rem',
|
||||
'3xl': '1.875rem',
|
||||
'4xl': '2.25rem',
|
||||
'5xl': '3rem',
|
||||
'6xl': '4rem',
|
||||
},
|
||||
extend: {
|
||||
borderRadius: {
|
||||
xl: '12px',
|
||||
'2xl': '16px',
|
||||
},
|
||||
boxShadow: {
|
||||
rare: '0 0 0 3px rgba(173, 118, 176, 0.5)',
|
||||
legendary: '0 0 0 3px rgba(185, 129, 46, 0.5)',
|
||||
outline: '0 0 0 2px #4E7CFF',
|
||||
select: '0 20px 16px rgba(0, 0, 0, 0.5)',
|
||||
},
|
||||
height: {
|
||||
14: '3.5rem',
|
||||
},
|
||||
width: {
|
||||
14: '3.5rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue