mirror of
https://github.com/MadeBaruna/paimon-moe.git
synced 2024-12-12 09:51:08 +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/
|
/src/node_modules/@sapper/
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
/__sapper__/
|
/__sapper__/
|
||||||
|
.svelte-kit
|
||||||
|
/build
|
||||||
.env
|
.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.
|
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
|
# Development
|
||||||
|
|
||||||
```
|
```
|
||||||
# install dependencies
|
# install dependencies
|
||||||
yarn
|
pnpm i
|
||||||
|
|
||||||
# you need the api to run wish importer and wish tally
|
# you need the api to run wish importer and wish tally
|
||||||
git clone https://github.com/MadeBaruna/paimon-moe-api
|
git clone https://github.com/MadeBaruna/paimon-moe-api
|
||||||
|
@ -20,10 +20,10 @@ docker-compose up -d
|
||||||
# run in dev mode
|
# run in dev mode
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
vi .env
|
vi .env
|
||||||
yarn dev
|
pnpm dev
|
||||||
|
|
||||||
# export as production static site
|
# export as production static site
|
||||||
yarn export
|
pnpm build
|
||||||
```
|
```
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
54
package.json
54
package.json
|
@ -1,50 +1,34 @@
|
||||||
{
|
{
|
||||||
|
"type": "module",
|
||||||
"name": "paimon-moe",
|
"name": "paimon-moe",
|
||||||
"description": "A collection of tools to help playing Genshin Impact",
|
"description": "A collection of tools to help playing Genshin Impact",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "NODE_OPTIONS=--max_old_space_size=4096 sapper dev",
|
"dev": "vite dev --port 3000",
|
||||||
"build": "sapper build --legacy",
|
"build": "NODE_OPTIONS=--max_old_space_size=4096 vite build",
|
||||||
"export": "NODE_OPTIONS=--max_old_space_size=4096 sapper export --legacy && cp __sapper__/build/firebase-messaging-sw.js __sapper__/export",
|
"preview": "vite preview",
|
||||||
"start": "node __sapper__/build"
|
"start": "node build"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"compression": "^1.7.1",
|
|
||||||
"exceljs": "^4.2.1",
|
|
||||||
"localforage": "^1.9.0",
|
|
||||||
"polka": "next",
|
|
||||||
"prettier": "^2.2.1",
|
|
||||||
"sirv": "^1.0.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"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",
|
"@mdi/js": "^5.9.55",
|
||||||
"@rollup/plugin-babel": "^5.0.0",
|
"@sveltejs/adapter-static": "1.0.0-next.37",
|
||||||
"@rollup/plugin-commonjs": "^16.0.0",
|
"@sveltejs/kit": "^1.0.0-next.379",
|
||||||
"@rollup/plugin-dynamic-import-vars": "^1.1.1",
|
"autoprefixer": "^10.4.7",
|
||||||
"@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",
|
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
"dayjs": "^1.9.4",
|
"dayjs": "^1.9.4",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"postcss": "^8.2.10",
|
"exceljs": "^4.3.0",
|
||||||
"postcss-load-config": "^3.0.0",
|
"localforage": "^1.10.0",
|
||||||
"postcss-nested": "^5.0.1",
|
"lodash.debounce": "^4.0.8",
|
||||||
"rollup": "^2.3.4",
|
"postcss": "^8.4.14",
|
||||||
"rollup-plugin-svelte": "^7.0.0",
|
"postcss-nested": "^5.0.6",
|
||||||
"rollup-plugin-terser": "^7.0.0",
|
"prettier": "^2.7.1",
|
||||||
"sapper": "^0.28.0",
|
"prettier-plugin-svelte": "^2.7.0",
|
||||||
"svelte": "^3.17.3",
|
"svelte": "^3.17.3",
|
||||||
"svelte-i18n": "^3.3.6",
|
"svelte-i18n": "^3.4.0",
|
||||||
"svelte-preprocess": "^4.5.1",
|
"svelte-preprocess": "^4.10.7",
|
||||||
"svelte-simple-modal": "^0.6.1",
|
"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 = '';
|
let envString = '';
|
||||||
envString += `GOOGLE_DRIVE_CLIENT_ID=${process.env.GOOGLE_DRIVE_CLIENT_ID}\n`;
|
envString += `VITE_GOOGLE_DRIVE_CLIENT_ID=${process.env.GOOGLE_DRIVE_CLIENT_ID}\n`;
|
||||||
envString += `GOOGLE_DRIVE_API_KEY=${process.env.GOOGLE_DRIVE_API_KEY}\n`;
|
envString += `VITE_GOOGLE_DRIVE_API_KEY=${process.env.GOOGLE_DRIVE_API_KEY}\n`;
|
||||||
envString += `API_HOST=${process.env.API_HOST}\n`;
|
envString += `VITE_API_HOST=${process.env.API_HOST}\n`;
|
||||||
envString += `FIREBASE_API_KEY=${process.env.FIREBASE_API_KEY}\n`
|
envString += `VITE_FIREBASE_API_KEY=${process.env.FIREBASE_API_KEY}\n`;
|
||||||
envString += `FIREBASE_AUTH_DOMAIN=${process.env.FIREBASE_AUTH_DOMAIN}\n`
|
envString += `VITE_FIREBASE_AUTH_DOMAIN=${process.env.FIREBASE_AUTH_DOMAIN}\n`;
|
||||||
envString += `FIREBASE_PROJECT_ID=${process.env.FIREBASE_PROJECT_ID}\n`
|
envString += `VITE_FIREBASE_PROJECT_ID=${process.env.FIREBASE_PROJECT_ID}\n`;
|
||||||
envString += `FIREBASE_STORAGE_BUCKET=${process.env.FIREBASE_STORAGE_BUCKET}\n`
|
envString += `VITE_FIREBASE_STORAGE_BUCKET=${process.env.FIREBASE_STORAGE_BUCKET}\n`;
|
||||||
envString += `FIREBASE_MESSAGING_SENDER_ID=${process.env.FIREBASE_MESSAGING_SENDER_ID}\n`
|
envString += `VITE_FIREBASE_MESSAGING_SENDER_ID=${process.env.FIREBASE_MESSAGING_SENDER_ID}\n`;
|
||||||
envString += `FIREBASE_APP_ID=${process.env.FIREBASE_APP_ID}\n`
|
envString += `VITE_FIREBASE_APP_ID=${process.env.FIREBASE_APP_ID}\n`;
|
||||||
|
|
||||||
fs.writeFileSync('.env', envString);
|
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:type" content="website" />
|
||||||
<meta property="og:image" content="https://paimon.moe/paimon-og.png" />
|
<meta property="og:image" content="https://paimon.moe/paimon-og.png" />
|
||||||
|
|
||||||
%sapper.base%
|
|
||||||
|
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Catamaran:wght@600;700;900&family=Poppins:wght@400;500;600&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Catamaran:wght@600;700;900&family=Poppins:wght@400;500;600&display=swap"
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
/>
|
/>
|
||||||
<link rel="manifest" href="manifest.json" crossorigin="use-credentials" />
|
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
||||||
<link rel="icon" type="image/png" href="favicon.png" />
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||||
|
|
||||||
<!-- <script src="https://js.sentry-cdn.com/446c4cef71a54aafb71b698555500b7d.min.js" crossorigin="anonymous"></script> -->
|
<!-- <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>
|
<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-app.js"></script>
|
||||||
<script src="https://www.gstatic.com/firebasejs/8.3.2/firebase-messaging.js"></script>
|
<script src="https://www.gstatic.com/firebasejs/8.3.2/firebase-messaging.js"></script>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
html {
|
html {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #25294a;
|
background: #25294a;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Sapper creates a <script> tag containing `src/client.js`
|
%sveltekit.head%
|
||||||
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%
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.AdSlots = window.AdSlots || { cmd: [], disableScripts: ['gpt'] };
|
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>
|
<script async src="https://kumo.network-n.com/dist/app.js?n=2" site="paimonmoe"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="font-body h-full bg-background-secondary">
|
<body class="font-body h-full bg-background-secondary">
|
||||||
<!-- The application will be rendered inside this element,
|
<div id="sapper" class="flex flex-col h-full">%sveltekit.body%</div>
|
||||||
because `src/client.js` references it -->
|
|
||||||
<div id="sapper" class="flex flex-col h-full">%sapper.html%</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</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 type;
|
||||||
export let variant;
|
export let variant;
|
||||||
export let id;
|
export let id;
|
||||||
export let style;
|
export let style = '';
|
||||||
|
|
||||||
let _class = '';
|
let _class = '';
|
||||||
export { _class as class };
|
export { _class as class };
|
||||||
|
|
|
@ -166,7 +166,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.hovered {
|
.hovered {
|
||||||
@apply text-white !important;
|
@apply text-white !important;
|
||||||
@apply bg-primary;
|
@apply bg-primary;
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label
|
<label
|
||||||
class="checkbox-wrapper flex flex-1 pl-4 items-center rounded-2xl h-14 {disabled ? 'cursor-not-allowed' : 'cursor-pointer'} {inverted
|
class="checkbox-wrapper flex flex-1 pl-4 items-center rounded-2xl h-14 {disabled
|
||||||
? 'bg-item'
|
? 'cursor-not-allowed'
|
||||||
: 'bg-background'} {className}"
|
: 'cursor-pointer'} {inverted ? 'bg-item' : 'bg-background'} {className}"
|
||||||
style="--bg: {inverted ? '#202442' : '#2D325A'};"
|
style="--bg: {inverted ? '#202442' : '#2D325A'};"
|
||||||
>
|
>
|
||||||
<span class="flex-1 text-white"><slot /></span>
|
<span class="flex-1 text-white"><slot /></span>
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
</svg>
|
</svg>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.checkbox {
|
.checkbox {
|
||||||
fill: none;
|
fill: none;
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
|
|
||||||
const { open: openModal, close: closeModal } = getContext('simple-modal');
|
const { open: openModal, close: closeModal } = getContext('simple-modal');
|
||||||
|
|
||||||
const CLIENT_ID = __paimon.env.GOOGLE_DRIVE_CLIENT_ID;
|
const CLIENT_ID = import.meta.env.VITE_GOOGLE_DRIVE_CLIENT_ID;
|
||||||
const API_KEY = __paimon.env.GOOGLE_DRIVE_API_KEY;
|
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 DISCOVERY_DOCS = ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'];
|
||||||
const SCOPES = 'https://www.googleapis.com/auth/drive.appdata';
|
const SCOPES = 'https://www.googleapis.com/auth/drive.appdata';
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.header::after {
|
.header::after {
|
||||||
content: '';
|
content: '';
|
||||||
top: -40px;
|
top: -40px;
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
{#if spin !== false}
|
{#if spin !== false}
|
||||||
{#if inverse}
|
{#if inverse}
|
||||||
<style>
|
<style lang="postcss">
|
||||||
@keyframes spin-inverse {
|
@keyframes spin-inverse {
|
||||||
to {
|
to {
|
||||||
transform: rotate(-360deg);
|
transform: rotate(-360deg);
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{:else}
|
{:else}
|
||||||
<style>
|
<style lang="postcss">
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
to {
|
to {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
svg {
|
svg {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
|
@ -81,27 +81,6 @@
|
||||||
}
|
}
|
||||||
</script>
|
</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
|
An almost direct copy and paste of: https://css-tricks.com/a-lightweight-masonry-solution
|
||||||
Usage:
|
Usage:
|
||||||
|
@ -124,6 +103,28 @@ $s: var(--grid-gap); // .5em;
|
||||||
<div
|
<div
|
||||||
bind:this={masonryElement}
|
bind:this={masonryElement}
|
||||||
class={`__grid--masonry ${stretchFirst ? '__stretch-first' : ''}`}
|
class={`__grid--masonry ${stretchFirst ? '__stretch-first' : ''}`}
|
||||||
style={`--grid-gap: ${gridGap}; --col-width: ${colWidth};`}>
|
style={`--grid-gap: ${gridGap}; --col-width: ${colWidth};`}
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</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}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.hovered {
|
.hovered {
|
||||||
@apply text-white !important;
|
@apply text-white !important;
|
||||||
@apply bg-primary;
|
@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>
|
<script>
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import { getContext } from 'svelte';
|
|
||||||
import { mdiCloseCircle } from '@mdi/js';
|
import { mdiCloseCircle } from '@mdi/js';
|
||||||
import { locale, t } from 'svelte-i18n';
|
import { locale, t } from 'svelte-i18n';
|
||||||
|
|
||||||
|
@ -30,7 +29,8 @@
|
||||||
{ id: 'pt', label: 'Português' },
|
{ id: 'pt', label: 'Português' },
|
||||||
{ id: 'ru', label: 'Русский' },
|
{ 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);
|
$: locales = languages.filter((e) => e.id !== currentLocale.id);
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
<SidebarItem
|
<SidebarItem
|
||||||
on:clicked={close}
|
on:clicked={close}
|
||||||
active={segment === undefined}
|
active={segment === ''}
|
||||||
image="/images/home.png"
|
image="/images/home.png"
|
||||||
label={$t('sidebar.home')}
|
label={$t('sidebar.home')}
|
||||||
href="/"
|
href="/"
|
||||||
|
@ -160,7 +160,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.paimon-bg::after {
|
.paimon-bg::after {
|
||||||
content: '';
|
content: '';
|
||||||
top: -50px;
|
top: -50px;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.active {
|
.active {
|
||||||
@apply bg-primary;
|
@apply bg-primary;
|
||||||
@apply bg-opacity-75;
|
@apply bg-opacity-75;
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.active {
|
.active {
|
||||||
@apply bg-primary;
|
@apply bg-primary;
|
||||||
@apply bg-opacity-75;
|
@apply bg-opacity-75;
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.container {
|
.container {
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</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 />
|
<slot />
|
||||||
</i>
|
</i>
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
<div style="top: {y}px; left: {x}px;" class="tooltip">{title}</div>
|
<div style="top: {y}px; left: {x}px;" class="tooltip">{title}</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.tooltip {
|
.tooltip {
|
||||||
@apply p-2 absolute rounded-xl bg-gray-400 border border-gray-800;
|
@apply p-2 absolute rounded-xl bg-gray-400 border border-gray-800;
|
||||||
@apply text-sm text-background z-10;
|
@apply text-sm text-background z-10;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</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 />
|
<slot />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
<div style="top: {y}px; left: {x}px;" class="tooltip">{title}</div>
|
<div style="top: {y}px; left: {x}px;" class="tooltip">{title}</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.tooltip {
|
.tooltip {
|
||||||
@apply p-2 fixed rounded-xl bg-gray-400 border border-gray-800;
|
@apply p-2 fixed rounded-xl bg-gray-400 border border-gray-800;
|
||||||
@apply text-sm text-background z-10;
|
@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>
|
<script>
|
||||||
import { onMount, tick } from 'svelte';
|
import { onMount, tick } from 'svelte';
|
||||||
|
|
||||||
// props
|
// props
|
||||||
export let items;
|
export let items;
|
||||||
export let height = '100%';
|
export let height = '100%';
|
||||||
export let itemHeight = undefined;
|
export let itemHeight = undefined;
|
||||||
|
|
||||||
let foo;
|
let foo;
|
||||||
|
|
||||||
// read-only, but visible to consumers via bind:start
|
// read-only, but visible to consumers via bind:start
|
||||||
export let start = 0;
|
export let start = 0;
|
||||||
export let end = 0;
|
export let end = 0;
|
||||||
|
|
||||||
// local state
|
// local state
|
||||||
let height_map = [];
|
let height_map = [];
|
||||||
let rows;
|
let rows;
|
||||||
let viewport;
|
let viewport;
|
||||||
let contents;
|
let contents;
|
||||||
let viewport_height = 0;
|
let viewport_height = 0;
|
||||||
let visible;
|
let visible;
|
||||||
let mounted;
|
let mounted;
|
||||||
|
|
||||||
let top = 0;
|
let top = 0;
|
||||||
let bottom = 0;
|
let bottom = 0;
|
||||||
let average_height;
|
let average_height;
|
||||||
|
|
||||||
$: visible = items.slice(start, end).map((data, i) => {
|
$: visible = items.slice(start, end).map((data, i) => {
|
||||||
return { index: i + start, data };
|
return { index: i + start, data };
|
||||||
});
|
});
|
||||||
|
|
||||||
// whenever `items` changes, invalidate the current heightmap
|
// whenever `items` changes, invalidate the current heightmap
|
||||||
$: if (mounted) refresh(items, viewport_height, itemHeight);
|
$: if (mounted) refresh(items, viewport_height, itemHeight);
|
||||||
|
|
||||||
async function refresh(items, viewport_height, itemHeight) {
|
async function refresh(items, viewport_height, itemHeight) {
|
||||||
const { scrollTop } = viewport;
|
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 content_height = top - scrollTop;
|
||||||
let i = start;
|
let i = start;
|
||||||
|
|
||||||
while (content_height < viewport_height && i < items.length) {
|
while (content_height < viewport_height && i < items.length) {
|
||||||
let row = rows[i - start];
|
let row = rows[i - start];
|
||||||
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
end = i + 1;
|
end = i + 1;
|
||||||
await tick(); // render the newly visible row
|
await tick(); // render the newly visible row
|
||||||
row = rows[i - start];
|
row = rows[i - start];
|
||||||
}
|
}
|
||||||
|
|
||||||
const row_height = height_map[i] = itemHeight || row.offsetHeight;
|
const row_height = (height_map[i] = itemHeight || row.offsetHeight);
|
||||||
content_height += row_height;
|
content_height += row_height;
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
end = i;
|
end = i;
|
||||||
|
|
||||||
const remaining = items.length - end;
|
const remaining = items.length - end;
|
||||||
average_height = (top + content_height) / end;
|
average_height = (top + content_height) / end;
|
||||||
|
|
||||||
bottom = remaining * average_height;
|
bottom = remaining * average_height;
|
||||||
height_map.length = items.length;
|
height_map.length = items.length;
|
||||||
|
|
||||||
viewport.scrollTo(0, 0);
|
viewport.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handle_scroll() {
|
async function handle_scroll() {
|
||||||
const { scrollTop } = viewport;
|
const { scrollTop } = viewport;
|
||||||
|
|
||||||
const old_start = start;
|
const old_start = start;
|
||||||
|
|
||||||
for (let v = 0; v < rows.length; v += 1) {
|
for (let v = 0; v < rows.length; v += 1) {
|
||||||
height_map[start + v] = itemHeight || rows[v].offsetHeight;
|
height_map[start + v] = itemHeight || rows[v].offsetHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let y = 0;
|
let y = 0;
|
||||||
|
|
||||||
while (i < items.length) {
|
while (i < items.length) {
|
||||||
const row_height = height_map[i] || average_height;
|
const row_height = height_map[i] || average_height;
|
||||||
if (y + row_height > scrollTop) {
|
if (y + row_height > scrollTop) {
|
||||||
start = i;
|
start = i;
|
||||||
top = y;
|
top = y;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
y += row_height;
|
y += row_height;
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i < items.length) {
|
while (i < items.length) {
|
||||||
y += height_map[i] || average_height;
|
y += height_map[i] || average_height;
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
if (y > scrollTop + viewport_height) break;
|
if (y > scrollTop + viewport_height) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
end = i;
|
end = i;
|
||||||
|
|
||||||
const remaining = items.length - end;
|
const remaining = items.length - end;
|
||||||
average_height = y / end;
|
average_height = y / end;
|
||||||
|
|
||||||
while (i < items.length) height_map[i++] = average_height;
|
while (i < items.length) height_map[i++] = average_height;
|
||||||
bottom = remaining * average_height;
|
bottom = remaining * average_height;
|
||||||
|
|
||||||
// prevent jumping if we scrolled up into unknown territory
|
// prevent jumping if we scrolled up into unknown territory
|
||||||
if (start < old_start) {
|
if (start < old_start) {
|
||||||
await tick();
|
await tick();
|
||||||
|
|
||||||
let expected_height = 0;
|
let expected_height = 0;
|
||||||
let actual_height = 0;
|
let actual_height = 0;
|
||||||
|
|
||||||
for (let i = start; i < old_start; i +=1) {
|
for (let i = start; i < old_start; i += 1) {
|
||||||
if (rows[i - start]) {
|
if (rows[i - start]) {
|
||||||
expected_height += height_map[i];
|
expected_height += height_map[i];
|
||||||
actual_height += itemHeight || rows[i - start].offsetHeight;
|
actual_height += itemHeight || rows[i - start].offsetHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const d = actual_height - expected_height;
|
const d = actual_height - expected_height;
|
||||||
viewport.scrollTo(0, scrollTop + d);
|
viewport.scrollTo(0, scrollTop + d);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO if we overestimated the space these
|
// TODO if we overestimated the space these
|
||||||
// rows would occupy we may need to add some
|
// rows would occupy we may need to add some
|
||||||
// more. maybe we can just call handle_scroll again?
|
// more. maybe we can just call handle_scroll again?
|
||||||
}
|
}
|
||||||
|
|
||||||
// trigger initial refresh
|
// trigger initial refresh
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
rows = contents.getElementsByTagName('svelte-virtual-list-row');
|
rows = contents.getElementsByTagName('svelte-virtual-list-row');
|
||||||
mounted = true;
|
mounted = true;
|
||||||
});
|
});
|
||||||
</script>
|
</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
|
<svelte-virtual-list-viewport
|
||||||
bind:this={viewport}
|
bind:this={viewport}
|
||||||
bind:offsetHeight={viewport_height}
|
bind:offsetHeight={viewport_height}
|
||||||
on:scroll={handle_scroll}
|
on:scroll={handle_scroll}
|
||||||
style="height: {height};"
|
style="height: {height};"
|
||||||
>
|
>
|
||||||
<svelte-virtual-list-contents
|
<svelte-virtual-list-contents bind:this={contents} style="padding-top: {top}px; padding-bottom: {bottom}px;">
|
||||||
bind:this={contents}
|
{#each visible as row (row.index)}
|
||||||
style="padding-top: {top}px; padding-bottom: {bottom}px;"
|
<svelte-virtual-list-row>
|
||||||
>
|
<slot item={row.data} index={row.index}>Missing template</slot>
|
||||||
{#each visible as row (row.index)}
|
</svelte-virtual-list-row>
|
||||||
<svelte-virtual-list-row>
|
{/each}
|
||||||
<slot item={row.data} index={row.index}>Missing template</slot>
|
</svelte-virtual-list-contents>
|
||||||
</svelte-virtual-list-row>
|
|
||||||
{/each}
|
|
||||||
</svelte-virtual-list-contents>
|
|
||||||
</svelte-virtual-list-viewport>
|
</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}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.hovered {
|
.hovered {
|
||||||
@apply text-white !important;
|
@apply text-white !important;
|
||||||
@apply bg-primary;
|
@apply bg-primary;
|
||||||
|
|
|
@ -190,7 +190,7 @@
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetchRetry(
|
const res = await fetchRetry(
|
||||||
`${__paimon.env.API_HOST}/corsproxy`,
|
`${import.meta.env.VITE_API_HOST}/corsproxy`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
@ -527,7 +527,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="border-b border-gray-700 py-1">
|
<td class="border-b border-gray-700 py-1">
|
||||||
{#if wishes[code] !== undefined}
|
{#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} />
|
<Icon size={0.5} path={mdiClose} />
|
||||||
{numberFormat.format(wishes[code].length)}
|
{numberFormat.format(wishes[code].length)}
|
||||||
</span>
|
</span>
|
||||||
|
@ -585,10 +585,10 @@
|
||||||
{#if wishes[code] !== undefined}
|
{#if wishes[code] !== undefined}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="border-b border-gray-700 py-1">
|
<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>
|
||||||
<td class="border-b border-gray-700 py-1">
|
<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} />
|
<Icon size={0.5} path={mdiClose} />
|
||||||
{numberFormat.format(wishes[code].length)}
|
{numberFormat.format(wishes[code].length)}
|
||||||
</span>
|
</span>
|
||||||
|
@ -788,7 +788,7 @@
|
||||||
<div class="pb-16 md:pb-0" />
|
<div class="pb-16 md:pb-0" />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.pill {
|
.pill {
|
||||||
@apply rounded-2xl;
|
@apply rounded-2xl;
|
||||||
@apply border-2;
|
@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');
|
importScripts('https://www.gstatic.com/firebasejs/8.3.2/firebase-messaging.js');
|
||||||
|
|
||||||
const firebaseConfig = {
|
const firebaseConfig = {
|
||||||
apiKey: __paimon.env.FIREBASE_API_KEY,
|
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
|
||||||
authDomain: __paimon.env.FIREBASE_AUTH_DOMAIN,
|
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
|
||||||
projectId: __paimon.env.FIREBASE_PROJECT_ID,
|
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
|
||||||
storageBucket: __paimon.env.FIREBASE_STORAGE_BUCKET,
|
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
|
||||||
messagingSenderId: __paimon.env.FIREBASE_MESSAGING_SENDER_ID,
|
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
|
||||||
appId: __paimon.env.FIREBASE_APP_ID,
|
appId: import.meta.env.VITE_FIREBASE_APP_ID,
|
||||||
};
|
};
|
||||||
|
|
||||||
firebase.initializeApp(firebaseConfig);
|
firebase.initializeApp(firebaseConfig);
|
||||||
|
|
|
@ -7,7 +7,7 @@ const bannerCategories = ['beginners', 'standard', 'character-event', 'weapon-ev
|
||||||
|
|
||||||
async function sendWish(data) {
|
async function sendWish(data) {
|
||||||
try {
|
try {
|
||||||
await fetch(`${__paimon.env.API_HOST}/wish`, {
|
await fetch(`${import.meta.env.VITE_API_HOST}/wish`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
|
@ -19,7 +19,7 @@ async function sendWish(data) {
|
||||||
|
|
||||||
async function sendWishTotal(data) {
|
async function sendWishTotal(data) {
|
||||||
try {
|
try {
|
||||||
await fetch(`${__paimon.env.API_HOST}/wish/total`, {
|
await fetch(`${import.meta.env.VITE_API_HOST}/wish/total`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
|
@ -31,7 +31,7 @@ async function sendWishTotal(data) {
|
||||||
|
|
||||||
async function sendWishConstellation(data) {
|
async function sendWishConstellation(data) {
|
||||||
try {
|
try {
|
||||||
await fetch(`${__paimon.env.API_HOST}/wish/constellation`, {
|
await fetch(`${import.meta.env.VITE_API_HOST}/wish/constellation`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
|
|
67
src/i18n.js
67
src/i18n.js
|
@ -1,23 +1,22 @@
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { register, addMessages, init, getLocaleFromNavigator, locale as $locale } from 'svelte-i18n';
|
import { register, addMessages, init, getLocaleFromNavigator, locale as $locale } from 'svelte-i18n';
|
||||||
|
import { browser } from '$app/env';
|
||||||
|
|
||||||
import en from './locales/en.json';
|
import en from './locales/en.json';
|
||||||
import enItems from './locales/items/en.json';
|
import enItems from './locales/items/en.json';
|
||||||
|
|
||||||
const INIT_OPTIONS = {
|
const INIT_OPTIONS = {
|
||||||
fallbackLocale: 'en',
|
fallbackLocale: 'en',
|
||||||
initialLocale: null,
|
initialLocale: 'en',
|
||||||
};
|
};
|
||||||
|
|
||||||
let currentLocale = null;
|
let isLoaded = false;
|
||||||
|
|
||||||
$locale.subscribe((value) => {
|
$locale.subscribe((value) => {
|
||||||
if (value == null) return;
|
if (value === null) return;
|
||||||
|
|
||||||
currentLocale = value;
|
if (isLoaded) localStorage.setItem('locale', value);
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
localStorage.setItem('locale', value);
|
|
||||||
dayjsLocales[value]().then(() => dayjs.locale(value));
|
dayjsLocales[value]().then(() => dayjs.locale(value));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -66,51 +65,27 @@ const dayjsLocales = {
|
||||||
vi: () => import('dayjs/locale/vi'),
|
vi: () => import('dayjs/locale/vi'),
|
||||||
};
|
};
|
||||||
|
|
||||||
export function startClient() {
|
export async 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
init({
|
init({
|
||||||
...INIT_OPTIONS,
|
...INIT_OPTIONS,
|
||||||
initialLocale: used,
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
const DOCUMENT_REGEX = /(^([^.?#@]+)?([?#](.+)?)?|service-worker.*?\.html)$/;
|
if (browser) {
|
||||||
export function i18nMiddleware() {
|
let used = 'en';
|
||||||
init(INIT_OPTIONS);
|
const savedLocale = localStorage.getItem('locale');
|
||||||
|
const detectedLocale = getLocaleFromNavigator().substring(0, 2);
|
||||||
return (req, res, next) => {
|
if (savedLocale !== null) {
|
||||||
const isDocument = DOCUMENT_REGEX.test(req.originalUrl);
|
if (!supportedLanguage.includes(savedLocale)) {
|
||||||
if (!isDocument) {
|
localStorage.setItem('locale', 'en');
|
||||||
next();
|
} else {
|
||||||
return;
|
used = savedLocale;
|
||||||
}
|
|
||||||
|
|
||||||
let locale = 'en';
|
|
||||||
if (req.headers['accept-language']) {
|
|
||||||
const headerLang = req.headers['accept-language'].split(',')[0].trim();
|
|
||||||
if (headerLang.length > 1) {
|
|
||||||
locale = headerLang;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else if (supportedLanguage.includes(detectedLocale)) {
|
||||||
locale = INIT_OPTIONS.initialLocale || INIT_OPTIONS.fallbackLocale;
|
used = detectedLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locale != null && locale !== currentLocale) {
|
$locale.set(used);
|
||||||
$locale.set(locale.substring(0, 2));
|
isLoaded = true;
|
||||||
}
|
console.log('change i18n', used);
|
||||||
|
}
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.",
|
"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",
|
"visitor": "{count} visitors in the last 7 days",
|
||||||
"banner": {
|
"banner": {
|
||||||
"featured": [
|
|
||||||
"Eula"
|
|
||||||
],
|
|
||||||
"summoned": "Summoned",
|
"summoned": "Summoned",
|
||||||
"percentage": "from all {rarity}",
|
"percentage": "from all {rarity}",
|
||||||
"avg": "Pity average",
|
"avg": "Pity average",
|
||||||
|
@ -143,10 +140,7 @@
|
||||||
"manualButton": "Enable Manual Input",
|
"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 😅",
|
"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",
|
"globalWishTally": "Global Wish Stats",
|
||||||
"pityTooltip": [
|
"pityTooltip": ["Shows your current {rarity} pity", "{count} pulls to guaranteed {rarity}"],
|
||||||
"Shows your current {rarity} pity",
|
|
||||||
"{count} pulls to guaranteed {rarity}"
|
|
||||||
],
|
|
||||||
"import": {
|
"import": {
|
||||||
"title": "Import Wish History",
|
"title": "Import Wish History",
|
||||||
"faqsButton": "FAQ - READ FIRST",
|
"faqsButton": "FAQ - READ FIRST",
|
||||||
|
@ -182,11 +176,7 @@
|
||||||
"server": "Select your server:",
|
"server": "Select your server:",
|
||||||
"wishTallyCheck": "Submit pity for global wish stats",
|
"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.",
|
"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": [
|
"wishTallyCollected": ["What will be collected:", "and", "pity from your wish history"],
|
||||||
"What will be collected:",
|
|
||||||
"and",
|
|
||||||
"pity from your wish history"
|
|
||||||
],
|
|
||||||
"forceUpdateCheck": "Force update wish history (enable only if your wish history is not updating)",
|
"forceUpdateCheck": "Force update wish history (enable only if your wish history is not updating)",
|
||||||
"header": [
|
"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!",
|
"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!",
|
"exportFinish": "Export success, please wait until your browser downloads the file!",
|
||||||
"wishTallyTitle": "Submit Wish Stats",
|
"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.",
|
"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": [
|
"wishTallyCollected": ["What will be collected:", "and", "pity from your wish history"],
|
||||||
"What will be collected:",
|
|
||||||
"and",
|
|
||||||
"pity from your wish history"
|
|
||||||
],
|
|
||||||
"wishTallySubmit": "Submit Wish Stats",
|
"wishTallySubmit": "Submit Wish Stats",
|
||||||
"wishTallyThankyou": "Thank you for participating!",
|
"wishTallyThankyou": "Thank you for participating!",
|
||||||
"manualTitle": "Manual Input Settings",
|
"manualTitle": "Manual Input Settings",
|
||||||
|
@ -380,22 +366,13 @@
|
||||||
"subtitle": "After a 1x Wish:",
|
"subtitle": "After a 1x Wish:",
|
||||||
"pressWhenYouGet": "Press {button} when you get {rarity}★",
|
"pressWhenYouGet": "Press {button} when you get {rarity}★",
|
||||||
"p1": "It will automatically add the lifetime pulls, 5★, and 4★ pity",
|
"p1": "It will automatically add the lifetime pulls, 5★, and 4★ pity",
|
||||||
"p2": [
|
"p2": ["When the", "pity reaches 10, it will automatically be reset to 0"],
|
||||||
"When the",
|
"p3": ["When the", "pity reaches 90, it will automatically be reset to 0"],
|
||||||
"pity reaches 10, it will automatically be reset to 0"
|
|
||||||
],
|
|
||||||
"p3": [
|
|
||||||
"When the",
|
|
||||||
"pity reaches 90, it will automatically be reset to 0"
|
|
||||||
],
|
|
||||||
"p4": [
|
"p4": [
|
||||||
"After a 10x Wish, press",
|
"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."
|
"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": [
|
"p5": ["You can also press the", "button to edit the values manually!"],
|
||||||
"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."
|
"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?",
|
"calculateTalent": "Calculate Talent Material?",
|
||||||
"inputTalentLevel": "Input the 1st, 2nd & 3rd current talent level",
|
"inputTalentLevel": "Input the 1st, 2nd & 3rd current talent level",
|
||||||
"inputTalentNotice": "If it has a different color, subtract it by 3",
|
"inputTalentNotice": "If it has a different color, subtract it by 3",
|
||||||
"inputTalent": [
|
"inputTalent": ["1st talent lvl", "2nd talent lvl", "3rd talent lvl"],
|
||||||
"1st talent lvl",
|
|
||||||
"2nd talent lvl",
|
|
||||||
"3rd talent lvl"
|
|
||||||
],
|
|
||||||
"talentToLevel": "to level",
|
"talentToLevel": "to level",
|
||||||
"calculate": "Calculate",
|
"calculate": "Calculate",
|
||||||
"unknownInformation": "There are some unknown information",
|
"unknownInformation": "There are some unknown information",
|
||||||
|
@ -548,11 +521,7 @@
|
||||||
"expWasted": "EXP Wasted",
|
"expWasted": "EXP Wasted",
|
||||||
"addToTodo": "Add to Todo List",
|
"addToTodo": "Add to Todo List",
|
||||||
"addedToTodo": "Added to Todo List",
|
"addedToTodo": "Added to Todo List",
|
||||||
"talent": [
|
"talent": ["Attack", "Skill", "Burst"]
|
||||||
"Attack",
|
|
||||||
"Skill",
|
|
||||||
"Burst"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"expTable": {
|
"expTable": {
|
||||||
"level": "Level",
|
"level": "Level",
|
||||||
|
@ -644,10 +613,7 @@
|
||||||
"todo": {
|
"todo": {
|
||||||
"title": "Todo List",
|
"title": "Todo List",
|
||||||
"summary": "Summary",
|
"summary": "Summary",
|
||||||
"empty": [
|
"empty": ["Nothing to do yet 😀", "Add some from the Items page or the Calculator!"],
|
||||||
"Nothing to do yet 😀",
|
|
||||||
"Add some from the Items page or the Calculator!"
|
|
||||||
],
|
|
||||||
"farmableToday": "Farmable Today",
|
"farmableToday": "Farmable Today",
|
||||||
"resin": "Resin needed",
|
"resin": "Resin needed",
|
||||||
"based": "Based on AR:{ar} and WL:{wl}",
|
"based": "Based on AR:{ar} and WL:{wl}",
|
||||||
|
@ -962,5 +928,12 @@
|
||||||
"common": {
|
"common": {
|
||||||
"dataSynced": "Data has been synced!",
|
"dataSynced": "Data has been synced!",
|
||||||
"driveError": "Drive sync not available right now 😔"
|
"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>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
export let status;
|
export let status;
|
||||||
export let error;
|
export let error;
|
||||||
|
|
||||||
const dev = process.env.NODE_ENV === 'development';
|
const dev = import.meta.env.DEV;
|
||||||
|
|
||||||
let refreshUrl;
|
let refreshUrl;
|
||||||
|
|
||||||
|
@ -39,7 +50,7 @@
|
||||||
>
|
>
|
||||||
Click here to refresh
|
Click here to refresh
|
||||||
</a>
|
</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">
|
<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
|
You might also want to check your extension, like adblock, it sometimes wrongly block the script needed for the
|
||||||
site.
|
site.
|
|
@ -1,21 +1,17 @@
|
||||||
<script context="module">
|
|
||||||
import { waitLocale } from 'svelte-i18n';
|
|
||||||
|
|
||||||
export async function preload() {
|
|
||||||
return waitLocale();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import '../app.css';
|
||||||
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { fade } from 'svelte/transition';
|
|
||||||
import { derived } from 'svelte/store';
|
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 { t } from 'svelte-i18n';
|
||||||
|
import { startClient } from '../i18n.js';
|
||||||
|
import { navigating, page } from '$app/stores';
|
||||||
|
|
||||||
import Modal from 'svelte-simple-modal';
|
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 Sidebar from '../components/Sidebar/Sidebar.svelte';
|
||||||
import Header from '../components/Header.svelte';
|
import Header from '../components/Header.svelte';
|
||||||
import DataSync from '../components/DataSync.svelte';
|
import DataSync from '../components/DataSync.svelte';
|
||||||
|
@ -26,28 +22,35 @@
|
||||||
import SettingData from '../components/SettingData.svelte';
|
import SettingData from '../components/SettingData.svelte';
|
||||||
import Toast from '../components/Toast.svelte';
|
import Toast from '../components/Toast.svelte';
|
||||||
import Icon from '../components/Icon.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 delayedPreloading = derived(navigating, (_, set) => {
|
||||||
|
set(true);
|
||||||
const { preloading, page } = stores();
|
setTimeout(() => set(true), 250);
|
||||||
const delayedPreloading = derived(preloading, (currentPreloading, set) => {
|
});
|
||||||
setTimeout(() => set(currentPreloading), 250);
|
|
||||||
|
startClient();
|
||||||
|
|
||||||
|
page.subscribe(() => {
|
||||||
|
try {
|
||||||
|
window.reloadAdSlots();
|
||||||
|
} catch (error) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
// check local storage save on load
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await checkLocalSave();
|
console.log('localforage config');
|
||||||
|
localforage.config({
|
||||||
page.subscribe(() => {
|
driver: [localforage.INDEXEDDB, localforage.LOCALSTORAGE],
|
||||||
try {
|
name: 'paimonmoe',
|
||||||
window.reloadAdSlots();
|
version: 1.0,
|
||||||
} catch (error) {}
|
description: 'paimonmoe local storage',
|
||||||
});
|
});
|
||||||
|
window.localforage = localforage;
|
||||||
|
await checkLocalSave();
|
||||||
});
|
});
|
||||||
</script>
|
|
||||||
|
|
||||||
<Tailwind />
|
$: segment = $page.url.pathname.substring(1).split('/')[0];
|
||||||
|
</script>
|
||||||
|
|
||||||
<Header />
|
<Header />
|
||||||
<Modal>
|
<Modal>
|
||||||
|
@ -63,8 +66,9 @@
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
</DataSync>
|
</DataSync>
|
||||||
|
<ServiceWorker />
|
||||||
</Modal>
|
</Modal>
|
||||||
{#if $preloading && $delayedPreloading}
|
{#if $navigating && $delayedPreloading}
|
||||||
<div transition:fade class="loading-bar" />
|
<div transition:fade class="loading-bar" />
|
||||||
{/if}
|
{/if}
|
||||||
<div class="lg:ml-64 px-4 md:px-8 py-8 flex flex-col md:pb-24">
|
<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>
|
<span class="text-gray-500">{$t('footer.community')}</span>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<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"
|
href="https://github.com/MadeBaruna/paimon-moe"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Icon path={mdiGithub} size={1} /> {$t('footer.link.github')}
|
<Icon path={mdiGithub} size={1} />
|
||||||
|
{$t('footer.link.github')}
|
||||||
</a>
|
</a>
|
||||||
<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"
|
href="https://twitter.com/MadeBaruna"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Icon path={mdiTwitter} size={1} /> {$t('footer.link.devTwitter')}
|
<Icon path={mdiTwitter} size={1} />
|
||||||
|
{$t('footer.link.devTwitter')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -100,25 +106,28 @@
|
||||||
<span class="text-gray-500">{$t('footer.official')}</span>
|
<span class="text-gray-500">{$t('footer.official')}</span>
|
||||||
<div>
|
<div>
|
||||||
<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://discord.gg/4nbWsCGjjE"
|
href="https://discord.gg/4nbWsCGjjE"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Icon path={mdiDiscord} size={1} /> {$t('footer.link.discord')}
|
<Icon path={mdiDiscord} size={1} />
|
||||||
|
{$t('footer.link.discord')}
|
||||||
</a>
|
</a>
|
||||||
<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/"
|
href="https://www.facebook.com/Genshinimpact/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Icon path={mdiFacebook} size={1} /> {$t('footer.link.facebook')}
|
<Icon path={mdiFacebook} size={1} />
|
||||||
|
{$t('footer.link.facebook')}
|
||||||
</a>
|
</a>
|
||||||
<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/"
|
href="https://www.reddit.com/r/Genshin_Impact/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Icon path={mdiReddit} size={1} /> {$t('footer.link.reddit')}
|
<Icon path={mdiReddit} size={1} />
|
||||||
|
{$t('footer.link.reddit')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -132,7 +141,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.loading-bar {
|
.loading-bar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
|
@ -37,7 +37,7 @@
|
||||||
let user = '';
|
let user = '';
|
||||||
|
|
||||||
async function getData() {
|
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 });
|
const query = new URLSearchParams({ banner: bannerId });
|
||||||
url.search = query.toString();
|
url.search = query.toString();
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
import { characters } from '../../data/characters';
|
import { characters } from '../../data/characters';
|
||||||
import { builds } from '../../data/build';
|
|
||||||
|
|
||||||
import Icon from '../../components/Icon.svelte';
|
import Icon from '../../components/Icon.svelte';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
const promoted = ['kaedehara_kazuha', 'shikanoin_heizou'];
|
export let builds;
|
||||||
|
const promoted = Object.keys(builds);
|
||||||
let current = 0;
|
let current = 0;
|
||||||
|
|
||||||
async function change(index) {
|
async function change(index) {
|
||||||
|
@ -121,7 +121,7 @@ bg-background-secondary rounded-xl py-2 px-4 hover:bg-background transition-colo
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.pill {
|
.pill {
|
||||||
@apply rounded-2xl;
|
@apply rounded-2xl;
|
||||||
@apply border-2;
|
@apply border-2;
|
||||||
|
|
|
@ -84,7 +84,7 @@
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
{#each upcoming as item}
|
{#each upcoming as item}
|
||||||
<div class="pl-2 pr-1 py-1 rounded-xl mb-1 flex" style="background: {item.color};">
|
<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}
|
{item.name}
|
||||||
</span>
|
</span>
|
||||||
<span class="bg-black bg-opacity-50 rounded-xl px-2 text-white text-sm">{item.time}</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">
|
<div class="flex flex-col">
|
||||||
{#each current as item}
|
{#each current as item}
|
||||||
<div class="pl-2 pr-1 py-1 rounded-xl mb-1 flex" style="background: {item.color};">
|
<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}
|
{item.name}
|
||||||
</span>
|
</span>
|
||||||
<span class="bg-black bg-opacity-50 rounded-xl px-2 text-white text-sm">{item.time}</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 = '...';
|
// let count = '...';
|
||||||
|
|
||||||
// async function getData() {
|
// async function getData() {
|
||||||
// const url = new URL(`${__paimon.env.API_HOST}/visitor`);
|
// const url = new URL(`${import.meta.env.VITE_API_HOST}/visitor`);
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
// const res = await fetch(url, {
|
// const res = await fetch(url, {
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import data from '../../data/achievement/en.json';
|
import achievementData from '../../data/achievement/en.json';
|
||||||
export async function preload() {
|
|
||||||
return { data };
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { locale, t } from 'svelte-i18n';
|
import { locale, t } from 'svelte-i18n';
|
||||||
import { onMount, tick } from 'svelte';
|
import { onMount, tick } from 'svelte';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash.debounce';
|
||||||
import { mdiFilter } from '@mdi/js';
|
import { mdiFilter } from '@mdi/js';
|
||||||
|
|
||||||
import Check from '../../components/Check.svelte';
|
import Check from '../../components/Check.svelte';
|
||||||
|
@ -21,10 +18,10 @@
|
||||||
import { pushToast } from '../../stores/toast';
|
import { pushToast } from '../../stores/toast';
|
||||||
import Ad from '../../components/Ad.svelte';
|
import Ad from '../../components/Ad.svelte';
|
||||||
|
|
||||||
export let data;
|
|
||||||
|
|
||||||
let achievementContainer;
|
let achievementContainer;
|
||||||
|
|
||||||
|
let data = achievementData;
|
||||||
|
|
||||||
let achievement = data;
|
let achievement = data;
|
||||||
let checkList = {};
|
let checkList = {};
|
||||||
let list = [];
|
let list = [];
|
||||||
|
@ -494,7 +491,7 @@
|
||||||
<Ad type="desktop" variant="lb" id="2" />
|
<Ad type="desktop" variant="lb" id="2" />
|
||||||
<Ad type="mobile" variant="lb" id="1" />
|
<Ad type="mobile" variant="lb" id="1" />
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.category {
|
.category {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,12 +83,12 @@
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function preload(page) {
|
export async function load({ params }) {
|
||||||
const { id } = page.params;
|
const { id } = params;
|
||||||
const artifact = data[id];
|
const artifact = data[id];
|
||||||
const recommendedCharacter = getCharacter(id);
|
const recommendedCharacter = getCharacter(id);
|
||||||
|
|
||||||
return { id, artifact, recommendedCharacter };
|
return { props: { id, artifact, recommendedCharacter } };
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import data from '../../data/artifacts/en.json';
|
import dataJson from '../../data/artifacts/en.json';
|
||||||
export async function preload() {
|
|
||||||
return { data };
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -11,7 +8,7 @@
|
||||||
import TableHeader from '../../components/Table/TableHeader.svelte';
|
import TableHeader from '../../components/Table/TableHeader.svelte';
|
||||||
import { domains } from '../../data/domain.js';
|
import { domains } from '../../data/domain.js';
|
||||||
|
|
||||||
export let data;
|
let data = dataJson;
|
||||||
let artifactList = [];
|
let artifactList = [];
|
||||||
let artifacts = [];
|
let artifacts = [];
|
||||||
let sortBy = 'maxRarity';
|
let sortBy = 'maxRarity';
|
||||||
|
@ -118,7 +115,7 @@
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
<div class="lg:ml-64 pt-20 lg:pt-8">
|
<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>
|
<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">
|
<div class="px-4 md:px-8 table max-w-full">
|
||||||
<table class="w-full block p-4 bg-item rounded-xl">
|
<table class="w-full block p-4 bg-item rounded-xl">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -630,7 +630,7 @@
|
||||||
{#if currentMax.usage[i] > 0}
|
{#if currentMax.usage[i] > 0}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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]}
|
>{currentMax.usage[i]}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<Icon size={0.5} path={mdiClose} /></span
|
||||||
>
|
>
|
||||||
|
@ -652,7 +652,7 @@
|
||||||
{#if item.amount > 0}
|
{#if item.amount > 0}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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}
|
>{item.amount}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<Icon size={0.5} path={mdiClose} /></span
|
||||||
>
|
>
|
||||||
|
@ -670,7 +670,7 @@
|
||||||
{/each}
|
{/each}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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)}
|
>{numberFormat.format(moraNeeded)}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<Icon size={0.5} path={mdiClose} /></span
|
||||||
>
|
>
|
||||||
|
|
|
@ -109,7 +109,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</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="table w-full">
|
||||||
<div class="bg-item rounded-xl p-4 w-full">
|
<div class="bg-item rounded-xl p-4 w-full">
|
||||||
<table>
|
<table>
|
||||||
|
@ -126,7 +126,7 @@
|
||||||
><Icon className="mb-1 text-gray-400" path={mdiArrowRight} size={0.7} /></td
|
><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="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}
|
{#each resources as res, j}
|
||||||
{#if row.usage[j] > 0}
|
{#if row.usage[j] > 0}
|
||||||
<span class="mr-2">
|
<span class="mr-2">
|
||||||
|
@ -145,7 +145,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
td,
|
td,
|
||||||
th {
|
th {
|
||||||
@apply py-1;
|
@apply py-1;
|
||||||
|
|
|
@ -6,18 +6,28 @@
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
let fateValues = [
|
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: 'interwinedFate',
|
||||||
{ id: "stardust", name: $t('calculator.fateCount.stardust'), image: "/images/stardust.png", amount: 0 },
|
name: $t('calculator.fateCount.interwinedFate'),
|
||||||
{ id: "primogem", name: $t('calculator.fateCount.primogem'), image: "/images/primogem.png", amount: 0 },
|
image: '/images/intertwined_fate.png',
|
||||||
{ id: "genesisCrystal", name: $t('calculator.fateCount.genesisCrystal'), image: "/images/genesis_crystal.png", amount: 0 },
|
amount: 0,
|
||||||
{ id: "welkinMoon", name: $t('calculator.fateCount.welkinMoon'), image: "/images/welkin_moon.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 = [
|
let parameters = [
|
||||||
{ name: "Days until pull", amount: 0 },
|
{ name: 'Days until pull', amount: 0 },
|
||||||
{ name: "Stardust Wishes (left this month)", amount: 5 }
|
{ name: 'Stardust Wishes (left this month)', amount: 5 },
|
||||||
]
|
];
|
||||||
|
|
||||||
let result = null;
|
let result = null;
|
||||||
let totalPrimogem = 0;
|
let totalPrimogem = 0;
|
||||||
|
@ -29,39 +39,44 @@
|
||||||
if (value.amount >= 0) {
|
if (value.amount >= 0) {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
switch (value.id) {
|
switch (value.id) {
|
||||||
case "interwinedFate":
|
case 'interwinedFate':
|
||||||
total = value.amount*160;
|
total = value.amount * 160;
|
||||||
break;
|
break;
|
||||||
case "starglitter":
|
case 'starglitter':
|
||||||
total = Math.floor(value.amount/5)*160;
|
total = Math.floor(value.amount / 5) * 160;
|
||||||
break;
|
break;
|
||||||
case "stardust":
|
case 'stardust':
|
||||||
let dateNow = dayjs();
|
let dateNow = dayjs();
|
||||||
let monthPull = dateNow.add(parameters[0].amount, 'day').startOf('month');
|
let monthPull = dateNow.add(parameters[0].amount, 'day').startOf('month');
|
||||||
let monthDiff = monthPull.diff(dateNow, 'month');
|
let monthDiff = monthPull.diff(dateNow, 'month');
|
||||||
let maxStardustFate = monthDiff*5+parameters[1].amount;
|
let maxStardustFate = monthDiff * 5 + parameters[1].amount;
|
||||||
total = Math.min(Math.floor(value.amount/75), maxStardustFate)*160;
|
total = Math.min(Math.floor(value.amount / 75), maxStardustFate) * 160;
|
||||||
break;
|
break;
|
||||||
case "primogem":
|
case 'primogem':
|
||||||
total = value.amount;
|
total = value.amount;
|
||||||
break;
|
break;
|
||||||
case "genesisCrystal":
|
case 'genesisCrystal':
|
||||||
total = value.amount;
|
total = value.amount;
|
||||||
break;
|
break;
|
||||||
case "welkinMoon":
|
case 'welkinMoon':
|
||||||
let days = Math.min(value.amount, parameters[0].amount)
|
let days = Math.min(value.amount, parameters[0].amount);
|
||||||
total = Math.floor(days/30)*300 + days*90
|
total = Math.floor(days / 30) * 300 + days * 90;
|
||||||
}
|
}
|
||||||
if (total>0) {
|
if (total > 0) {
|
||||||
totalPrimogem += total
|
totalPrimogem += total;
|
||||||
result.push({name: value.name, image: value.image, amount: value.amount, total: total })
|
result.push({ name: value.name, image: value.image, amount: value.amount, total: total });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (parameters[0].amount>0) {
|
if (parameters[0].amount > 0) {
|
||||||
let total = parameters[0].amount*60;
|
let total = parameters[0].amount * 60;
|
||||||
totalPrimogem += total;
|
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>
|
||||||
<div class="flex flex-row items-center">
|
<div class="flex flex-row items-center">
|
||||||
<div class="w-full">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -98,22 +121,28 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row items-center">
|
<div class="flex flex-row items-center">
|
||||||
<div class="w-full">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="md:col-span-2 xl:col-span-1">
|
<div class="md:col-span-2 xl:col-span-1">
|
||||||
<Button className="block w-full md:w-auto" on:click={calculate}
|
<Button className="block w-full md:w-auto" on:click={calculate}>{$t('calculator.fateCount.calculate')}</Button>
|
||||||
>{$t('calculator.fateCount.calculate')}</Button
|
|
||||||
>
|
|
||||||
{#if result !== null}
|
{#if result !== null}
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
transition:fade={{ duration: 100 }}
|
transition:fade={{ duration: 100 }}
|
||||||
class="rounded-xl bg-background p-4 block md:inline-block"
|
class="rounded-xl bg-background p-4 block md:inline-block"
|
||||||
style="height: fit-content; width: fit-content;"
|
style="height: fit-content; width: fit-content;"
|
||||||
>
|
>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -138,7 +167,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
<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.fateCount.totalPrimogem')}
|
{$t('calculator.fateCount.totalPrimogem')}
|
||||||
{totalPrimogem}
|
{totalPrimogem}
|
||||||
<img class="mr-1 w-6 inline" src="/images/primogem.png" alt="Primogem" />
|
<img class="mr-1 w-6 inline" src="/images/primogem.png" alt="Primogem" />
|
||||||
|
|
|
@ -334,7 +334,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
<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.totalGenesis')}
|
{$t('calculator.fate.totalGenesis')}
|
||||||
{numberFormat.format(resultTotal)}
|
{numberFormat.format(resultTotal)}
|
||||||
<img class="mr-1 w-6 inline" src="/images/genesis_crystal.png" alt="Genesis" />
|
<img class="mr-1 w-6 inline" src="/images/genesis_crystal.png" alt="Genesis" />
|
||||||
|
@ -343,7 +343,7 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<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')}
|
{$t('calculator.fate.totalPrice')}
|
||||||
{currencyLabel}{numberFormat.format(resultTotalPrice)}
|
{currencyLabel}{numberFormat.format(resultTotalPrice)}
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -84,13 +84,13 @@
|
||||||
<p class="block text-center text-gray-400">{$t('calculator.friendship.based', { values: { ar: $ar } })}</p>
|
<p class="block text-center text-gray-400">{$t('calculator.friendship.based', { values: { ar: $ar } })}</p>
|
||||||
<table class="text-gray-200">
|
<table class="text-gray-200">
|
||||||
<tr>
|
<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 } })}
|
{$t('calculator.friendship.resultDay', { values: { result } })}
|
||||||
</td>
|
</td>
|
||||||
<td class="border-b border-gray-700 pb-1">{$t('calculator.friendship.result')}</td>
|
<td class="border-b border-gray-700 pb-1">{$t('calculator.friendship.result')}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<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 } })}
|
{$t('calculator.friendship.resultDay', { values: { result: resultSerenitea } })}
|
||||||
</td>
|
</td>
|
||||||
<td class="pt-1">{$t('calculator.friendship.resultSerenitea')}</td>
|
<td class="pt-1">{$t('calculator.friendship.resultSerenitea')}</td>
|
||||||
|
@ -102,7 +102,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.slider {
|
.slider {
|
||||||
@apply w-full h-4 rounded-xl;
|
@apply w-full h-4 rounded-xl;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
|
|
|
@ -132,7 +132,7 @@
|
||||||
<table class="w-full">
|
<table class="w-full">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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}
|
>{resinOutput.resin}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<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 colspan="2" class="text-white text-center pt-2">{$t('calculator.resin.or')}</td></tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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}
|
>{resinOutput.condensed.resin}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<Icon size={0.5} path={mdiClose} /></span
|
||||||
>
|
>
|
||||||
|
@ -166,7 +166,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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}
|
>{resinOutput.condensed.condensedResin}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<Icon size={0.5} path={mdiClose} /></span
|
||||||
>
|
>
|
||||||
|
@ -184,7 +184,9 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-red-400" colspan="2">
|
<td class="text-red-400" colspan="2">
|
||||||
{$t('calculator.resin.fullTime')}:
|
{$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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
counTimeRelative();
|
counTimeRelative();
|
||||||
</script>
|
</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="table w-full">
|
||||||
<div class="bg-item rounded-xl p-4 w-full">
|
<div class="bg-item rounded-xl p-4 w-full">
|
||||||
<table class="w-full">
|
<table class="w-full">
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
td,
|
td,
|
||||||
th {
|
th {
|
||||||
@apply py-1;
|
@apply py-1;
|
||||||
|
|
|
@ -441,7 +441,7 @@
|
||||||
{#if currentMax.usage[i] > 0}
|
{#if currentMax.usage[i] > 0}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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]}
|
>{currentMax.usage[i]}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<Icon size={0.5} path={mdiClose} /></span
|
||||||
>
|
>
|
||||||
|
@ -463,7 +463,7 @@
|
||||||
{#if item.amount > 0}
|
{#if item.amount > 0}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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}
|
>{item.amount}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<Icon size={0.5} path={mdiClose} /></span
|
||||||
>
|
>
|
||||||
|
@ -481,7 +481,7 @@
|
||||||
{/each}
|
{/each}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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)}
|
>{numberFormat.format(moraNeeded)}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<Icon size={0.5} path={mdiClose} /></span
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import { builds as buildsJson } from '../../data/build';
|
|
||||||
import artifactData from '../../data/artifacts/en.json';
|
import artifactData from '../../data/artifacts/en.json';
|
||||||
import weaponData from '../../data/weapons/en.json';
|
import weaponData from '../../data/weapons/en.json';
|
||||||
|
|
||||||
export async function preload(page) {
|
export async function load({ params, fetch }) {
|
||||||
const { id } = page.params;
|
const { id } = params;
|
||||||
const data = await import(`../../data/characterData/${id}.json`);
|
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>
|
</script>
|
||||||
|
|
||||||
|
@ -16,8 +15,6 @@
|
||||||
export let id;
|
export let id;
|
||||||
export let data;
|
export let data;
|
||||||
export let buildData;
|
export let buildData;
|
||||||
export let artifactData;
|
|
||||||
export let weaponData;
|
|
||||||
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t, locale } from 'svelte-i18n';
|
import { t, locale } from 'svelte-i18n';
|
||||||
|
@ -340,34 +337,34 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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="px-4" style="width: min-content;">
|
||||||
<div class="table max-w-full rounded-xl border border-gray-200 border-opacity-25">
|
<div class="table max-w-full rounded-xl border border-gray-200 border-opacity-25">
|
||||||
<table class="text-gray-200 w-full">
|
<table class="text-gray-200 w-full">
|
||||||
<tr>
|
<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')}
|
{$t('characters.asc')}
|
||||||
</td>
|
</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')}
|
{$t('characters.lvl')}
|
||||||
</td>
|
</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')}
|
{$t('characters.hp')}
|
||||||
</td>
|
</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')}
|
{$t('characters.atk')}
|
||||||
</td>
|
</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')}
|
{$t('characters.def')}
|
||||||
</td>
|
</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')}
|
>{$t('characters.critRate')}
|
||||||
</td>
|
</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')}
|
>{$t('characters.critDamage')}
|
||||||
</td>
|
</td>
|
||||||
{#if data.statGrow !== 'critRate' && data.statGrow !== 'critDamage'}
|
{#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}`)}
|
{$t(`characters.${data.statGrow}`)}
|
||||||
</td>
|
</td>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -556,7 +553,7 @@
|
||||||
class="flex items-center justify-center bg-background rounded-md px-2 py-1 mb-1 mr-1"
|
class="flex items-center justify-center bg-background rounded-md px-2 py-1 mb-1 mr-1"
|
||||||
style="height: 40px;"
|
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')}
|
{$t('artifact.choose2')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -735,7 +732,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.pill {
|
.pill {
|
||||||
@apply rounded-2xl;
|
@apply rounded-2xl;
|
||||||
@apply border-2;
|
@apply border-2;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { afterUpdate, onMount, tick } from 'svelte';
|
import { onMount, tick } from 'svelte';
|
||||||
|
|
||||||
export let id;
|
export let id;
|
||||||
export let char;
|
export let char;
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.small {
|
.small {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
@ -75,8 +75,6 @@
|
||||||
.cell {
|
.cell {
|
||||||
width: calc(33.33333% - 1rem);
|
width: calc(33.33333% - 1rem);
|
||||||
|
|
||||||
@screen md {
|
@apply md:w-24;
|
||||||
@apply w-24;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -107,7 +107,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
td:not(:last-child) {
|
td:not(:last-child) {
|
||||||
@apply border-r;
|
@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">
|
<p class="text-gray-400 px-4 md:px-8 font-medium pb-2 mt-4">
|
||||||
※ {$t('characters.subtitle')}
|
※ {$t('characters.subtitle')}
|
||||||
</p>
|
</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">
|
<div class="px-4 md:px-8 table">
|
||||||
<table class="w-full block p-4 bg-item rounded-xl">
|
<table class="w-full block p-4 bg-item rounded-xl">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -521,7 +521,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
tr.rare:hover {
|
tr.rare:hover {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
90deg,
|
90deg,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import artifacts from '../../data/artifacts/en.json';
|
import artifactsJson from '../../data/artifacts/en.json';
|
||||||
import { domains } from '../../data/domain.js';
|
import { domains } from '../../data/domain.js';
|
||||||
export async function preload(page) {
|
export async function load({ params }) {
|
||||||
const { id } = page.params;
|
const { id } = params;
|
||||||
const domain = domains[id];
|
const domain = domains[id];
|
||||||
|
|
||||||
return { id, artifacts, domain };
|
return { props: { id, domain } };
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@
|
||||||
import Button from '../../components/Button.svelte';
|
import Button from '../../components/Button.svelte';
|
||||||
|
|
||||||
export let id;
|
export let id;
|
||||||
export let artifacts;
|
|
||||||
export let domain;
|
export let domain;
|
||||||
|
let artifacts = artifactsJson;
|
||||||
|
|
||||||
let currentArtifacts = [];
|
let currentArtifacts = [];
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import data from '../../data/fishing/en.json';
|
import dataJson from '../../data/fishing/en.json';
|
||||||
import locations from '../../data/fishing/location.json';
|
import locations from '../../data/fishing/location.json';
|
||||||
|
|
||||||
let spots = {
|
let spots = {
|
||||||
|
@ -13,8 +13,8 @@
|
||||||
spots[location.location].push({ ...location, id });
|
spots[location.location].push({ ...location, id });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function preload() {
|
export async function load() {
|
||||||
return { data, spots };
|
return { props: { spots } };
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
const { open: openModal, close: closeModal } = getContext('simple-modal');
|
const { open: openModal, close: closeModal } = getContext('simple-modal');
|
||||||
|
|
||||||
export let data;
|
let data = dataJson;
|
||||||
export let spots;
|
export let spots;
|
||||||
|
|
||||||
let fishList = data;
|
let fishList = data;
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
{#each result as [item, amount], i}
|
{#each result as [item, amount], i}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-gray-700 py-1 {i === 0 ? '' : 'border-t'}">
|
<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}
|
{amount}
|
||||||
<Icon size={0.5} path={mdiClose} />
|
<Icon size={0.5} path={mdiClose} />
|
||||||
</span>
|
</span>
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
{#if coins > 0}
|
{#if coins > 0}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-t border-gray-700 py-1">
|
<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}
|
{coins}
|
||||||
<Icon size={0.5} path={mdiClose} />
|
<Icon size={0.5} path={mdiClose} />
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import setsData from '../../data/furnishing/sets/en.json';
|
import setsDataJson from '../../data/furnishing/sets/en.json';
|
||||||
import data from '../../data/furnishing/en.json';
|
import furnishingDataJson from '../../data/furnishing/en.json';
|
||||||
export async function preload() {
|
|
||||||
return { data, setsData };
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { locale, t } from 'svelte-i18n';
|
import { locale, t } from 'svelte-i18n';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash.debounce';
|
||||||
import { mdiCheckCircleOutline, mdiClose } from '@mdi/js';
|
import { mdiCheckCircleOutline, mdiClose } from '@mdi/js';
|
||||||
|
|
||||||
import Button from '../../components/Button.svelte';
|
import Button from '../../components/Button.svelte';
|
||||||
|
@ -21,8 +18,8 @@
|
||||||
|
|
||||||
const { open: openModal } = getContext('simple-modal');
|
const { open: openModal } = getContext('simple-modal');
|
||||||
|
|
||||||
export let data;
|
let data = furnishingDataJson;
|
||||||
export let setsData;
|
let setsData = setsDataJson;
|
||||||
|
|
||||||
let loading = true;
|
let loading = true;
|
||||||
let furnishing = {};
|
let furnishing = {};
|
||||||
|
@ -277,7 +274,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.popup {
|
.popup {
|
||||||
@apply text-sm pt-1 hidden p-2 rounded-xl;
|
@apply text-sm pt-1 hidden p-2 rounded-xl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,20 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import data from '../../data/furnishing/en.json';
|
import dataJson from '../../data/furnishing/en.json';
|
||||||
import categories from '../../data/furnishing/category/en.json';
|
import categoriesJson from '../../data/furnishing/category/en.json';
|
||||||
export async function preload() {
|
|
||||||
return { data, categories };
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { locale, t } from 'svelte-i18n';
|
import { locale, t } from 'svelte-i18n';
|
||||||
import { onMount, tick } from 'svelte';
|
import { onMount, tick } from 'svelte';
|
||||||
import { mdiMinus, mdiPlus } from '@mdi/js';
|
import { mdiMinus, mdiPlus } from '@mdi/js';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash.debounce';
|
||||||
import Icon from '../../components/Icon.svelte';
|
import Icon from '../../components/Icon.svelte';
|
||||||
import { readSave, updateSave } from '../../stores/saveManager';
|
import { readSave, updateSave } from '../../stores/saveManager';
|
||||||
import { getAccountPrefix } from '../../stores/account';
|
import { getAccountPrefix } from '../../stores/account';
|
||||||
import Button from '../../components/Button.svelte';
|
import Button from '../../components/Button.svelte';
|
||||||
|
|
||||||
export let data;
|
let data = dataJson;
|
||||||
export let categories;
|
let categories = categoriesJson;
|
||||||
|
|
||||||
let loading = true;
|
let loading = true;
|
||||||
let active = {
|
let active = {
|
||||||
|
@ -221,7 +218,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.category {
|
.category {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import data from '../../data/furnishing/en.json';
|
import dataJson from '../../data/furnishing/en.json';
|
||||||
export async function preload() {
|
|
||||||
return { data };
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { locale, t } from 'svelte-i18n';
|
import { locale, t } from 'svelte-i18n';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash.debounce';
|
||||||
import { mdiInformationOutline, mdiMinus, mdiPlus } from '@mdi/js';
|
import { mdiInformationOutline, mdiMinus, mdiPlus } from '@mdi/js';
|
||||||
|
|
||||||
import TableHeader from '../../components/Table/TableHeader.svelte';
|
import TableHeader from '../../components/Table/TableHeader.svelte';
|
||||||
|
@ -17,7 +14,7 @@
|
||||||
import { getAccountPrefix } from '../../stores/account';
|
import { getAccountPrefix } from '../../stores/account';
|
||||||
import { readSave, updateSave } from '../../stores/saveManager';
|
import { readSave, updateSave } from '../../stores/saveManager';
|
||||||
|
|
||||||
export let data;
|
let data = dataJson;
|
||||||
|
|
||||||
let type = 'hall';
|
let type = 'hall';
|
||||||
let items = [];
|
let items = [];
|
||||||
|
@ -259,7 +256,7 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex mt-4 wrapper">
|
<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">
|
<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">
|
<table class="w-full block pl-4 pr-4 py-2 md:pl-8 md:py-4 bg-item rounded-xl">
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -363,7 +360,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.pill {
|
.pill {
|
||||||
@apply rounded-2xl;
|
@apply rounded-2xl;
|
||||||
@apply border-2;
|
@apply border-2;
|
||||||
|
@ -375,7 +372,7 @@
|
||||||
@apply outline-none;
|
@apply outline-none;
|
||||||
@apply transition;
|
@apply transition;
|
||||||
@apply duration-100;
|
@apply duration-100;
|
||||||
@apply whitespace-no-wrap;
|
@apply whitespace-nowrap;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@apply border-primary;
|
@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>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash.debounce';
|
||||||
import { locale } from 'svelte-i18n';
|
import { locale } from 'svelte-i18n';
|
||||||
|
|
||||||
import Masonry from '../components/Masonry.svelte';
|
import Masonry from '../components/Masonry.svelte';
|
||||||
|
@ -19,6 +35,8 @@
|
||||||
import Build from './_index/build.svelte';
|
import Build from './_index/build.svelte';
|
||||||
import Ad from '../components/Ad.svelte';
|
import Ad from '../components/Ad.svelte';
|
||||||
|
|
||||||
|
export let builds;
|
||||||
|
|
||||||
let refreshLayout;
|
let refreshLayout;
|
||||||
let isMobile = false;
|
let isMobile = false;
|
||||||
|
|
||||||
|
@ -64,7 +82,7 @@
|
||||||
<Ad type="mobile" variant="mpu" id="1" />
|
<Ad type="mobile" variant="mpu" id="1" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<Build on:done={onDone} />
|
<Build on:done={onDone} {builds} />
|
||||||
<Event on:done={onDone} />
|
<Event on:done={onDone} />
|
||||||
<Item on:done={onDone} />
|
<Item on:done={onDone} />
|
||||||
<Discord on:done={onDone} />
|
<Discord on:done={onDone} />
|
||||||
|
|
|
@ -169,7 +169,7 @@
|
||||||
<CharacterSelect bind:selected={selectedCharacter} placeholder={$t('items.searchCharacter')} />
|
<CharacterSelect bind:selected={selectedCharacter} placeholder={$t('items.searchCharacter')} />
|
||||||
<WeaponSelect bind:selected={selectedWeapon} placeholder={$t('items.searchWeapon')} />
|
<WeaponSelect bind:selected={selectedWeapon} placeholder={$t('items.searchWeapon')} />
|
||||||
</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">
|
<div class="px-4 md:px-8 table max-w-full">
|
||||||
<table class="w-full block p-4 bg-item rounded-xl">
|
<table class="w-full block p-4 bg-item rounded-xl">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -283,7 +283,7 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="px-4 md:px-8 table max-w-full">
|
||||||
<table class="w-full block p-4 bg-item rounded-xl">
|
<table class="w-full block p-4 bg-item rounded-xl">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -338,7 +338,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
td {
|
td {
|
||||||
@apply text-white;
|
@apply text-white;
|
||||||
@apply px-4;
|
@apply px-4;
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import data from '../../data/radiantSpincrystal/en.json';
|
import dataJson from '../../data/radiantSpincrystal/en.json';
|
||||||
export async function preload() {
|
|
||||||
return { data };
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { locale, t } from 'svelte-i18n';
|
import { locale, t } from 'svelte-i18n';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash.debounce';
|
||||||
import { mdiMapMarker, mdiMusic, mdiOpenInNew } from '@mdi/js';
|
import { mdiMapMarker, mdiMusic, mdiOpenInNew } from '@mdi/js';
|
||||||
import Icon from '../../components/Icon.svelte';
|
import Icon from '../../components/Icon.svelte';
|
||||||
import Check from '../../components/Check.svelte';
|
import Check from '../../components/Check.svelte';
|
||||||
|
@ -16,7 +13,7 @@
|
||||||
import { readSave, updateSave } from '../../stores/saveManager';
|
import { readSave, updateSave } from '../../stores/saveManager';
|
||||||
import Ad from '../../components/Ad.svelte';
|
import Ad from '../../components/Ad.svelte';
|
||||||
|
|
||||||
export let data;
|
let data = dataJson;
|
||||||
|
|
||||||
let spincrystals = data;
|
let spincrystals = data;
|
||||||
let checkList = {};
|
let checkList = {};
|
||||||
|
@ -136,7 +133,7 @@
|
||||||
<Ad type="desktop" variant="lb" id="2" />
|
<Ad type="desktop" variant="lb" id="2" />
|
||||||
<Ad type="mobile" variant="lb" id="1" />
|
<Ad type="mobile" variant="lb" id="1" />
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.text {
|
.text {
|
||||||
line-height: initial;
|
line-height: initial;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
if ($firebaseToken === '') return;
|
if ($firebaseToken === '') return;
|
||||||
|
|
||||||
console.log('get reminder');
|
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' });
|
const query = new URLSearchParams({ token: $firebaseToken, type: 'hoyolab' });
|
||||||
url.search = query.toString();
|
url.search = query.toString();
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
async function deleteCurrentReminder() {
|
async function deleteCurrentReminder() {
|
||||||
console.log('delete reminder');
|
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' });
|
const query = new URLSearchParams({ token: $firebaseToken, type: 'hoyolab' });
|
||||||
url.search = query.toString();
|
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');
|
const reminderTime = dayjs(time, 'HH:mm').utc().year(2000).month(0).date(1).format('YYYY-MM-DD HH:mm:ssZ');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${__paimon.env.API_HOST}/reminder`, {
|
const res = await fetch(`${import.meta.env.VITE_API_HOST}/reminder`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
if ($firebaseToken === '') return;
|
if ($firebaseToken === '') return;
|
||||||
|
|
||||||
console.log('get reminder');
|
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' });
|
const query = new URLSearchParams({ token: $firebaseToken, type: 'transformer' });
|
||||||
url.search = query.toString();
|
url.search = query.toString();
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
|
|
||||||
async function deleteCurrentReminder() {
|
async function deleteCurrentReminder() {
|
||||||
console.log('delete reminder');
|
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' });
|
const query = new URLSearchParams({ token: $firebaseToken, type: 'transformer' });
|
||||||
url.search = query.toString();
|
url.search = query.toString();
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${__paimon.env.API_HOST}/reminder`, {
|
const res = await fetch(`${import.meta.env.VITE_API_HOST}/reminder`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
@screen md {
|
@screen md {
|
||||||
.not-supported {
|
.not-supported {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
<p class="text-red-400 mb-2">{$t('settings.importWarning')}</p>
|
<p class="text-red-400 mb-2">{$t('settings.importWarning')}</p>
|
||||||
{#if !loading}
|
{#if !loading}
|
||||||
<div class="flex">
|
<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')}
|
{files !== null && files[0] ? files[0].name : $t('settings.selectFile')}
|
||||||
</Button>
|
</Button>
|
||||||
{#if files !== null && files[0]}
|
{#if files !== null && files[0]}
|
||||||
|
|
|
@ -475,14 +475,14 @@
|
||||||
<a
|
<a
|
||||||
href="https://discord.gg/tPURAYgHV9"
|
href="https://discord.gg/tPURAYgHV9"
|
||||||
target="_blank"
|
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
|
><Icon path={mdiDiscord} /> Discord</a
|
||||||
>
|
>
|
||||||
{$t('settings.or')}
|
{$t('settings.or')}
|
||||||
<a
|
<a
|
||||||
href="https://github.com/MadeBaruna/paimon-moe/issues"
|
href="https://github.com/MadeBaruna/paimon-moe/issues"
|
||||||
target="_blank"
|
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
|
><Icon path={mdiGithub} /> Github Issues</a
|
||||||
>
|
>
|
||||||
{$t('settings.thanks')}
|
{$t('settings.thanks')}
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
$: prevEnded = prev !== null && now.isAfter(prev.end);
|
$: prevEnded = prev !== null && now.isAfter(prev.end);
|
||||||
$: shouldShowHourStart = diffStart <= 86400000 || event.duration > 6.5 || !prevNearby;
|
$: shouldShowHourStart = diffStart <= 86400000 || event.duration > 6.5 || !prevNearby;
|
||||||
$: shouldShowHourEnd = diffEnd <= 86400000 || event.duration > 6.5 || !prevNearby;
|
$: shouldShowHourEnd = diffEnd <= 86400000 || event.duration > 6.5 || !prevNearby;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -43,7 +42,7 @@
|
||||||
>
|
>
|
||||||
<div class="event-item {nextDiff < 1 ? '' : 'rounded-xl'}" />
|
<div class="event-item {nextDiff < 1 ? '' : 'rounded-xl'}" />
|
||||||
<span
|
<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}
|
{event.name}
|
||||||
</span>
|
</span>
|
||||||
|
@ -82,7 +81,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
div.event-item {
|
div.event-item {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
@ -102,5 +101,4 @@
|
||||||
text-shadow: var(--color) -1px -1px 4px, var(--color) 1px -1px 4px, var(--color) -1px 1px 4px,
|
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;
|
var(--color) 1px 1px 4px, var(--color) 0 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -332,7 +332,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
height: 8px;
|
height: 8px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,7 +270,6 @@
|
||||||
|
|
||||||
$: $todos, updateSummary();
|
$: $todos, updateSummary();
|
||||||
$: columnCount, updateId();
|
$: columnCount, updateId();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
@ -304,7 +303,7 @@
|
||||||
{#each Object.entries(todayOnlyItems) as [id, amount]}
|
{#each Object.entries(todayOnlyItems) as [id, amount]}
|
||||||
<tr class="today-only">
|
<tr class="today-only">
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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)}
|
{numberFormat.format(amount)}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<Icon size={0.5} path={mdiClose} /></span
|
||||||
>
|
>
|
||||||
|
@ -339,7 +338,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<td class="text-right border-b border-gray-700 py-1">
|
||||||
<div class="flex justify-end items-center">
|
<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)}
|
{numberFormat.format(amount)}
|
||||||
</span>
|
</span>
|
||||||
<img src="/images/resin.png" alt="resin" class="w-6 h-6 mr-2" />
|
<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]}
|
{#each Object.entries(summary) as [id, amount]}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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)}
|
{numberFormat.format(amount)}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<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]}
|
{#each Object.entries(todo.resources).sort((a, b) => b[1] - a[1]) as [id, amount]}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right border-b border-gray-700 py-1">
|
<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)}
|
{numberFormat.format(amount)}
|
||||||
<Icon size={0.5} path={mdiClose} /></span
|
<Icon size={0.5} path={mdiClose} /></span
|
||||||
>
|
>
|
||||||
|
@ -491,11 +490,10 @@
|
||||||
</Masonry>
|
</Masonry>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
tr.today-only:last-child {
|
tr.today-only:last-child {
|
||||||
td {
|
td {
|
||||||
@apply border-b-0;
|
@apply border-b-0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -35,13 +35,13 @@
|
||||||
return Object.values(collection).sort((a, b) => a.id.localeCompare(b.id));
|
return Object.values(collection).sort((a, b) => a.id.localeCompare(b.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function preload(page) {
|
export async function load({ params }) {
|
||||||
const { id } = page.params;
|
const { id } = params;
|
||||||
const weapon = data[id];
|
const weapon = data[id];
|
||||||
const materials = weaponList[id].ascension[0].items;
|
const materials = weaponList[id].ascension[0].items;
|
||||||
const recommendedCharacter = getCharacter(id);
|
const recommendedCharacter = getCharacter(id);
|
||||||
|
|
||||||
return { id, weapon, materials, recommendedCharacter };
|
return { props: { id, weapon, materials, recommendedCharacter } };
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -137,22 +137,22 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/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 style="width: min-content;">
|
||||||
<div class="table max-w-full rounded-xl border border-gray-200 border-opacity-25">
|
<div class="table max-w-full rounded-xl border border-gray-200 border-opacity-25">
|
||||||
<table class="text-gray-200 w-full">
|
<table class="text-gray-200 w-full">
|
||||||
<tr>
|
<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')}
|
{$t('weapon.asc')}
|
||||||
</td>
|
</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')}
|
{$t('weapon.lvl')}
|
||||||
</td>
|
</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')}
|
{$t('weapon.baseAtk')}
|
||||||
</td>
|
</td>
|
||||||
{#if weapon.secondary.name}
|
{#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}`)}
|
{$t(`weapon.${weapon.secondary.name}`)}
|
||||||
</td>
|
</td>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -185,7 +185,7 @@
|
||||||
<Ad type="mobile" variant="lb" id="1" />
|
<Ad type="mobile" variant="lb" id="1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
td:not(:last-child) {
|
td:not(:last-child) {
|
||||||
@apply border-r;
|
@apply border-r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import data from '../../data/weapons/en.json';
|
import data from '../../data/weapons/en.json';
|
||||||
export async function preload() {
|
|
||||||
return { data };
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -12,7 +9,7 @@
|
||||||
import { formatStat } from '../../helper';
|
import { formatStat } from '../../helper';
|
||||||
import Ad from '../../components/Ad.svelte';
|
import Ad from '../../components/Ad.svelte';
|
||||||
|
|
||||||
export let data;
|
let weaponData = data;
|
||||||
let weaponList = [];
|
let weaponList = [];
|
||||||
let sortBy = 'name';
|
let sortBy = 'name';
|
||||||
let sortOrder = true;
|
let sortOrder = true;
|
||||||
|
@ -34,7 +31,7 @@
|
||||||
|
|
||||||
function process() {
|
function process() {
|
||||||
const _weapons = [];
|
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;
|
if (['amber_bead', 'ebony_bow', 'quartz', 'the_flagstaff'].includes(id)) continue;
|
||||||
|
|
||||||
_weapons.push({
|
_weapons.push({
|
||||||
|
@ -94,7 +91,7 @@
|
||||||
|
|
||||||
async function changeLocale(locale) {
|
async function changeLocale(locale) {
|
||||||
const _data = await import(`../../data/weapons/${locale}.json`);
|
const _data = await import(`../../data/weapons/${locale}.json`);
|
||||||
data = _data.default;
|
weaponData = _data.default;
|
||||||
process();
|
process();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +112,7 @@
|
||||||
<p class="text-gray-400 px-4 md:px-8 font-medium pb-4" style="margin-top: -1rem;">
|
<p class="text-gray-400 px-4 md:px-8 font-medium pb-4" style="margin-top: -1rem;">
|
||||||
※ {$t('weapon.subtitle')}
|
※ {$t('weapon.subtitle')}
|
||||||
</p>
|
</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;" />
|
<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">
|
<div class="px-4 md:px-8 table max-w-full">
|
||||||
<table class="w-full block p-4 bg-item rounded-xl">
|
<table class="w-full block p-4 bg-item rounded-xl">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
export async function preload(page) {
|
export async function load({ params }) {
|
||||||
const { id } = page.params;
|
const { id } = params;
|
||||||
return { id };
|
return { props: { id } };
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -510,7 +510,7 @@
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex mt-4 wrapper">
|
<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">
|
<div class="flex pl-4 md:pl-8 mb-2">
|
||||||
<button on:click={() => toggleShowRarity(0)} class={`pill legendary ${showRarity[0] ? 'active' : ''}`}>
|
<button on:click={() => toggleShowRarity(0)} class={`pill legendary ${showRarity[0] ? 'active' : ''}`}>
|
||||||
5 <Icon path={mdiStar} size={0.75} className="mb-1" />
|
5 <Icon path={mdiStar} size={0.75} className="mb-1" />
|
||||||
|
@ -600,7 +600,7 @@
|
||||||
: ''}"
|
: ''}"
|
||||||
>
|
>
|
||||||
<td
|
<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;"
|
style="font-family: monospace;"
|
||||||
>
|
>
|
||||||
{pull.formattedTime}
|
{pull.formattedTime}
|
||||||
|
@ -710,19 +710,18 @@
|
||||||
<Ad type="mobile" variant="lb" id="1" />
|
<Ad type="mobile" variant="lb" id="1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.wrapper {
|
.wrapper {
|
||||||
@apply flex-col-reverse;
|
@apply flex-col-reverse;
|
||||||
|
|
||||||
.chart-area {
|
.chart-area {
|
||||||
@apply px-4;
|
@apply px-4;
|
||||||
|
@apply md:px-8;
|
||||||
@screen md {
|
|
||||||
@apply px-8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 1920px) {
|
@media (min-width: 1920px) {
|
||||||
|
.wrapper {
|
||||||
@apply flex-row;
|
@apply flex-row;
|
||||||
|
|
||||||
.chart-area {
|
.chart-area {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import { onMount, getContext, createEventDispatcher } from 'svelte';
|
import { onMount, getContext, createEventDispatcher } from 'svelte';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
import { mdiPencil, mdiStar, mdiChevronDown, mdiTableOfContents, mdiArrowUpCircle } from '@mdi/js';
|
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');
|
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'
|
isEdit ? 'bg-item flex-col py-2' : 'bg-background flex-row items-center justify-center mb-2 p-4'
|
||||||
} rounded-xl flex relative`}
|
} 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 />
|
{$t('wish.lifetimePulls')}<br />
|
||||||
<span class="flex items-center text-gray-600">
|
<span class="flex items-center text-gray-600">
|
||||||
<img class="w-4 h-4 mr-2" src="/images/primogem.png" alt="primogem" />
|
<img class="w-4 h-4 mr-2" src="/images/primogem.png" alt="primogem" />
|
||||||
|
@ -345,7 +345,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<span class="text-gray-200 whitespace-no-wrap flex-1">
|
<span class="text-gray-200 whitespace-nowrap flex-1">
|
||||||
5★ {$t('wish.pity')}
|
5★ {$t('wish.pity')}
|
||||||
<br /><span class="text-gray-600">{$t('wish.guarantee', { values: { pity: legendaryPity } })}</span>
|
<br /><span class="text-gray-600">{$t('wish.guarantee', { values: { pity: legendaryPity } })}</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -374,7 +374,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<span class="text-gray-200 whitespace-no-wrap flex-1">
|
<span class="text-gray-200 whitespace-nowrap flex-1">
|
||||||
4★ {$t('wish.pity')}
|
4★ {$t('wish.pity')}
|
||||||
<br /><span class="text-gray-600">{$t('wish.guarantee', { values: { pity: 10 } })}</span>
|
<br /><span class="text-gray-600">{$t('wish.guarantee', { values: { pity: 10 } })}</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -476,7 +476,7 @@
|
||||||
{:else if pull.type === 'unknown_3_star'}
|
{:else if pull.type === 'unknown_3_star'}
|
||||||
<td class="border-b border-gray-700 py-1 pl-2 font-semibold text-primary">Unknown</td>
|
<td class="border-b border-gray-700 py-1 pl-2 font-semibold text-primary">Unknown</td>
|
||||||
{/if}
|
{/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}
|
{pull.time}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right border-b border-gray-700 py-1">{pull.pity}</td>
|
<td class="text-right border-b border-gray-700 py-1">{pull.pity}</td>
|
||||||
|
@ -487,7 +487,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.pill {
|
.pill {
|
||||||
@apply rounded-2xl;
|
@apply rounded-2xl;
|
||||||
@apply border-2;
|
@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-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.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 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>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-legendary-from font-semibold pr-2 md:pr-4 border-t border-gray-700">
|
<td class="text-legendary-from font-semibold pr-2 md:pr-4 border-t border-gray-700">
|
||||||
|
@ -101,7 +101,7 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<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')}
|
└ {$t('wish.detail.character')}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-rare-from font-semibold pr-2 md:pr-4 text-right border-t border-gray-700">
|
<td class="text-rare-from font-semibold pr-2 md:pr-4 text-right border-t border-gray-700">
|
||||||
|
@ -115,7 +115,7 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<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')}
|
└ {$t('wish.detail.weapon')}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-rare-from font-semibold pr-2 md:pr-4 text-right border-t border-gray-700">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
span.pity {
|
span.pity {
|
||||||
@apply rounded-xl;
|
@apply rounded-xl;
|
||||||
@apply text-gray-400;
|
@apply text-gray-400;
|
||||||
@apply border;
|
@apply border;
|
||||||
@apply border-legendary-from;
|
@apply border-legendary-from;
|
||||||
@apply whitespace-no-wrap;
|
@apply whitespace-nowrap;
|
||||||
@apply px-2;
|
@apply px-2;
|
||||||
@apply mb-1;
|
@apply mb-1;
|
||||||
@apply mr-1;
|
@apply mr-1;
|
||||||
|
|
|
@ -703,7 +703,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.pill {
|
.pill {
|
||||||
@apply rounded-2xl;
|
@apply rounded-2xl;
|
||||||
@apply border-2;
|
@apply border-2;
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
</p>
|
</p>
|
||||||
<p class="mb-2">
|
<p class="mb-2">
|
||||||
{$t('wish.welcomeStart1')}
|
{$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')}
|
{$t('wish.welcomeStart2')}
|
||||||
<Icon path={mdiArrowUp} size={1.2} />
|
<Icon path={mdiArrowUp} size={1.2} />
|
||||||
</p>
|
</p>
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.bubble::after {
|
.bubble::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
if (wishCount === 0) return;
|
if (wishCount === 0) return;
|
||||||
|
|
||||||
try {
|
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 });
|
const query = new URLSearchParams({ banner: current });
|
||||||
url.search = query.toString();
|
url.search = query.toString();
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
if (percentages[current] === undefined) return;
|
if (percentages[current] === undefined) return;
|
||||||
|
|
||||||
try {
|
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 });
|
const query = new URLSearchParams({ banner: current, rarity });
|
||||||
url.search = query.toString();
|
url.search = query.toString();
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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 });
|
const query = new URLSearchParams({ banner: current, rarity });
|
||||||
url.search = query.toString();
|
url.search = query.toString();
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.pill {
|
.pill {
|
||||||
@apply text-sm;
|
@apply text-sm;
|
||||||
@apply rounded-2xl;
|
@apply rounded-2xl;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash.debounce';
|
||||||
|
|
||||||
import { characters } from '../../data/characters';
|
import { characters } from '../../data/characters';
|
||||||
import { weaponList } from '../../data/weaponList';
|
import { weaponList } from '../../data/weaponList';
|
||||||
|
@ -304,7 +304,7 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.container {
|
.container {
|
||||||
@apply flex flex-col gap-4;
|
@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-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.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 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>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-legendary-from font-semibold pr-2 md:pr-4 border-t border-gray-700">
|
<td class="text-legendary-from font-semibold pr-2 md:pr-4 border-t border-gray-700">
|
||||||
|
@ -131,13 +131,13 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
span.pity {
|
span.pity {
|
||||||
@apply rounded-xl;
|
@apply rounded-xl;
|
||||||
@apply text-gray-400;
|
@apply text-gray-400;
|
||||||
@apply border;
|
@apply border;
|
||||||
@apply border-legendary-from;
|
@apply border-legendary-from;
|
||||||
@apply whitespace-no-wrap;
|
@apply whitespace-nowrap;
|
||||||
@apply px-2;
|
@apply px-2;
|
||||||
@apply mb-1;
|
@apply mb-1;
|
||||||
@apply mr-1;
|
@apply mr-1;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext, onMount } from 'svelte';
|
import { getContext, onMount } from 'svelte';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
import { goto } from '@sapper/app';
|
import { goto } from '$app/navigation';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import {
|
import {
|
||||||
mdiCheckBold,
|
mdiCheckBold,
|
||||||
|
@ -251,7 +251,7 @@
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetchRetry(
|
const res = await fetchRetry(
|
||||||
`${__paimon.env.API_HOST}/corsproxy`,
|
`${import.meta.env.VITE_API_HOST}/corsproxy`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
@ -286,7 +286,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastCount < fetchSize && dat.data.list.length > 0) {
|
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;
|
fetchSize = 6;
|
||||||
lastCount = fetchSize;
|
lastCount = fetchSize;
|
||||||
error = $t('wish.import.invalidData');
|
error = $t('wish.import.invalidData');
|
||||||
|
@ -828,7 +828,7 @@
|
||||||
|
|
||||||
async function getNews() {
|
async function getNews() {
|
||||||
try {
|
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) {
|
if (res.status === 200) {
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
news = json.message;
|
news = json.message;
|
||||||
|
@ -1037,9 +1037,10 @@
|
||||||
<p class="text-white">{$t('wish.import.guide.pc2.3')}</p>
|
<p class="text-white">{$t('wish.import.guide.pc2.3')}</p>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<pre
|
<pre
|
||||||
class="bg-black text-white bg-opacity-50 whitespace-pre-wrap break-all p-2 rounded-xl text-xs select-all flex-1">
|
class="bg-black text-white bg-opacity-50 whitespace-pre-wrap break-all p-2 rounded-xl text-xs select-all flex-1">{$server ===
|
||||||
{$server === 'China' ? powershellScriptChina : powershellScript}
|
'China'
|
||||||
</pre>
|
? powershellScriptChina
|
||||||
|
: powershellScript}</pre>
|
||||||
<button
|
<button
|
||||||
on:click={copyScript}
|
on:click={copyScript}
|
||||||
class="bg-black bg-opacity-50 hover:bg-opacity-25 text-white px-2 ml-1 rounded-xl"
|
class="bg-black bg-opacity-50 hover:bg-opacity-25 text-white px-2 ml-1 rounded-xl"
|
||||||
|
@ -1101,9 +1102,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="content flex-col items-center pb-2">
|
<div class="content flex-col items-center pb-2">
|
||||||
<p class="text-white">{$t('wish.import.guide.pclog.2')}</p>
|
<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">
|
<pre
|
||||||
{$server === 'China' ? $t('wish.import.logLocation.china') : $t('wish.import.logLocation.global')}
|
class="bg-black text-white bg-opacity-50 whitespace-pre-wrap break-all p-2 rounded-xl text-xs select-all">{$server ===
|
||||||
</pre>
|
'China'
|
||||||
|
? $t('wish.import.logLocation.china')
|
||||||
|
: $t('wish.import.logLocation.global')}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex space-x-3 mb-2">
|
<div class="flex space-x-3 mb-2">
|
||||||
|
@ -1363,10 +1366,10 @@
|
||||||
{#if wishes[code] !== undefined}
|
{#if wishes[code] !== undefined}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-2 py-1">
|
<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>
|
||||||
<td class="pr-2 py-1">
|
<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} />
|
<Icon size={0.5} path={mdiClose} />
|
||||||
{numberFormat.format(wishes[code].length)}
|
{numberFormat.format(wishes[code].length)}
|
||||||
</span>
|
</span>
|
||||||
|
@ -1416,7 +1419,7 @@
|
||||||
<Ad class="ml-4" type="desktop" variant="mpu" id="1" />
|
<Ad class="ml-4" type="desktop" variant="mpu" id="1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
.step-number {
|
.step-number {
|
||||||
min-height: 2rem;
|
min-height: 2rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,7 +255,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
@media (min-width: 1920px) {
|
@media (min-width: 1920px) {
|
||||||
.top-header {
|
.top-header {
|
||||||
@apply flex-row;
|
@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>
|
|
|
@ -106,9 +106,9 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const rareInclude = {
|
const rareInclude = {
|
||||||
300011: ['rosaria'],
|
300011: ['rosaria'],
|
||||||
300012: ['yanfei', 'noelle', 'diona'],
|
300012: ['yanfei', 'noelle', 'diona'],
|
||||||
};
|
};
|
||||||
let promotedRarePercentage = 0;
|
let promotedRarePercentage = 0;
|
||||||
|
|
||||||
let legendaryList = [];
|
let legendaryList = [];
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getData() {
|
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 });
|
const query = new URLSearchParams({ banner: id });
|
||||||
url.search = query.toString();
|
url.search = query.toString();
|
||||||
|
|
||||||
|
@ -173,19 +173,22 @@
|
||||||
|
|
||||||
// only for zhongli banner upward
|
// only for zhongli banner upward
|
||||||
if (id > 300011 && id < 400000) {
|
if (id > 300011 && id < 400000) {
|
||||||
const totalRare = data.list.reduce((prev, current) => {
|
const totalRare = data.list.reduce(
|
||||||
if (rareInclude[id].includes(current.name)) {
|
(prev, current) => {
|
||||||
prev.total += current.count;
|
if (rareInclude[id].includes(current.name)) {
|
||||||
}
|
prev.total += current.count;
|
||||||
if (featured[1] === current.name) {
|
}
|
||||||
prev.featured = current.count;
|
if (featured[1] === current.name) {
|
||||||
}
|
prev.featured = current.count;
|
||||||
return prev;
|
}
|
||||||
}, {
|
return prev;
|
||||||
total: 0,
|
},
|
||||||
featured: 0,
|
{
|
||||||
});
|
total: 0,
|
||||||
promotedRarePercentage = totalRare.featured / totalRare.total * 100
|
featured: 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
promotedRarePercentage = (totalRare.featured / totalRare.total) * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
legendary = {
|
legendary = {
|
||||||
|
@ -340,7 +343,7 @@
|
||||||
100,
|
100,
|
||||||
)}%
|
)}%
|
||||||
{$t('wish.tally.wonFiftyFifty')}
|
{$t('wish.tally.wonFiftyFifty')}
|
||||||
{:else if id > 300011 && id < 400000 && i === 1}
|
{:else if id > 300011 && id < 400000 && i === 1}
|
||||||
{numberFormat.format(promotedRarePercentage)}%
|
{numberFormat.format(promotedRarePercentage)}%
|
||||||
{$t('wish.tally.fromFourStarFeatured')}
|
{$t('wish.tally.fromFourStarFeatured')}
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -365,7 +368,7 @@
|
||||||
{numberFormat.format(legendary.percentage)}%
|
{numberFormat.format(legendary.percentage)}%
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col flex-1">
|
<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} />
|
<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)}%
|
{numberFormatSecondary.format(rare.percentage)}%
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col flex-1">
|
<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} />
|
<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">
|
<table class="text-white w-full table-fixed text-sm">
|
||||||
<tr>
|
<tr>
|
||||||
<td
|
<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')}
|
5★<br />{$t('wish.tally.pity')}
|
||||||
</td>
|
</td>
|
||||||
|
@ -535,11 +538,14 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap">
|
<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">
|
<table class="text-white text-sm">
|
||||||
<tr>
|
<tr>
|
||||||
<td
|
<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')}
|
4★ {$t('wish.tally.pity')}
|
||||||
</td>
|
</td>
|
||||||
|
@ -578,20 +584,20 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap text-white -mt-2 mb-2">
|
<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="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>
|
{$t('wish.tally.wishTotal')} <span class="font-semibold ml-2">{numberFormat.format(data.total.all)}</span>
|
||||||
</div>
|
</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" />
|
{$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>
|
<span class="font-semibold">{numberFormat.format(data.total.all * 160)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2 flex flex-col flex-wrap mt-2">
|
<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')}
|
{$t('wish.tally.median')}
|
||||||
<span class="font-semibold ml-2">{numberFormat.format(data.median.legendary)}</span>
|
<span class="font-semibold ml-2">{numberFormat.format(data.median.legendary)}</span>
|
||||||
</div>
|
</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>
|
{$t('wish.tally.user')} <span class="font-semibold ml-2">{numberFormat.format(data.total.users)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -603,7 +609,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
@screen xl {
|
@screen xl {
|
||||||
.pity-summary {
|
.pity-summary {
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getData() {
|
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 });
|
const query = new URLSearchParams({ banner: id });
|
||||||
url.search = query.toString();
|
url.search = query.toString();
|
||||||
|
|
||||||
|
@ -381,7 +381,7 @@
|
||||||
{numberFormat.format(legendary.percentage)}%
|
{numberFormat.format(legendary.percentage)}%
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col flex-1">
|
<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} />
|
<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)}%
|
{numberFormatSecondary.format(rare.percentage)}%
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col flex-1">
|
<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} />
|
<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">
|
<table class="text-white w-full table-fixed text-sm">
|
||||||
<tr>
|
<tr>
|
||||||
<td
|
<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')}
|
5★<br />{$t('wish.tally.pity')}
|
||||||
</td>
|
</td>
|
||||||
|
@ -560,7 +560,7 @@
|
||||||
<table class="text-white text-sm">
|
<table class="text-white text-sm">
|
||||||
<tr>
|
<tr>
|
||||||
<td
|
<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')}
|
4★ {$t('wish.tally.pity')}
|
||||||
</td>
|
</td>
|
||||||
|
@ -599,27 +599,27 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap text-white -mt-2 mb-2">
|
<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="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>
|
{$t('wish.tally.wishTotal')} <span class="font-semibold ml-2">{numberFormat.format(data.total.all)}</span>
|
||||||
</div>
|
</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" />
|
{$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>
|
<span class="font-semibold">{numberFormat.format(data.total.all * 160)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2 flex flex-col flex-wrap mr-2 mt-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.median')}
|
{$t('wish.tally.median')}
|
||||||
<span class="font-semibold ml-2">{numberFormat.format(data.median.legendary)}</span>
|
<span class="font-semibold ml-2">{numberFormat.format(data.median.legendary)}</span>
|
||||||
</div>
|
</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>
|
{$t('wish.tally.user')} <span class="font-semibold ml-2">{numberFormat.format(data.total.users)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2 flex flex-col flex-wrap mt-2">
|
<div class="space-y-2 flex flex-col flex-wrap mt-2">
|
||||||
<a
|
<a
|
||||||
href="/wish/tally/{id}"
|
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')}
|
{$t('wish.tally.detail')}
|
||||||
</a>
|
</a>
|
||||||
|
@ -632,7 +632,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
@screen xl {
|
@screen xl {
|
||||||
.pity-summary {
|
.pity-summary {
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
|
|
|
@ -142,7 +142,7 @@
|
||||||
loading = true;
|
loading = true;
|
||||||
loadingCons = 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 });
|
const query = new URLSearchParams({ banner: id });
|
||||||
url.search = query.toString();
|
url.search = query.toString();
|
||||||
|
|
||||||
|
@ -626,7 +626,7 @@
|
||||||
{numberFormat.format(legendary.percentage)}%
|
{numberFormat.format(legendary.percentage)}%
|
||||||
</td>
|
</td>
|
||||||
<td class="bg-background rounded-r-xl py-4 pr-4 text-legendary-from">
|
<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} />
|
<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)}%
|
{numberFormat.format(rare.percentage)}%
|
||||||
</td>
|
</td>
|
||||||
<td class="bg-background rounded-r-xl py-4 pr-4 text-rare-from">
|
<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} />
|
<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" />
|
<Ad type="mobile" variant="lb" id="2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style lang="postcss">
|
||||||
@screen md {
|
@screen md {
|
||||||
.select-name {
|
.select-name {
|
||||||
width: 100%;
|
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,
|
self.addEventListener('install', (event) => {
|
||||||
// `files` is an array of everything in the `static` directory
|
event.waitUntil(self.skipWaiting());
|
||||||
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('activate', event => {
|
async function fetchAddCache(url) {
|
||||||
event.waitUntil(
|
try {
|
||||||
caches.keys().then(async keys => {
|
const cache = await caches.open(CACHE);
|
||||||
// delete old caches
|
const cachedRes = await cache.match(url);
|
||||||
for (const key of keys) {
|
|
||||||
if (key !== ASSETS) await caches.delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.clients.claim();
|
if (cachedRes) return;
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const res = await fetch(url);
|
||||||
/**
|
cache.put(url, res.clone());
|
||||||
* Fetch the asset from the network and store it in the cache.
|
} catch (err) {
|
||||||
* Fall back to the cache if the user is offline.
|
console.error(err);
|
||||||
*/
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addEventListener('fetch', event => {
|
self.addEventListener('activate', (event) => {
|
||||||
if (event.request.method !== 'GET' || event.request.headers.has('range')) return;
|
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
|
fetchAddCache('/');
|
||||||
const isHttp = url.protocol.startsWith('http');
|
channel.addEventListener('message', (event) => {
|
||||||
const isDevServerRequest = url.hostname === self.location.hostname && url.port !== self.location.port;
|
if (event.data.type === 'fetch-doc') {
|
||||||
const isStaticAsset = url.host === self.location.host && staticAssets.has(url.pathname);
|
fetchAddCache(event.data.path);
|
||||||
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,
|
self.addEventListener('fetch', async (event) => {
|
||||||
// set this variable to true for them and they will only be fetched once.
|
if (!event.request.url.startsWith(self.location.origin) || event.request.method !== 'GET') return;
|
||||||
const cachedAsset = isStaticAsset && await caches.match(event.request);
|
|
||||||
|
event.respondWith(
|
||||||
// for pages, you might want to serve a shell `service-worker-index.html` file,
|
(async () => {
|
||||||
// which Sapper has generated for you. It's not right for every
|
const cache = await caches.open(CACHE);
|
||||||
// app, but if it's right for yours then uncomment this section
|
const cachedRes = await cache.match(event.request);
|
||||||
/*
|
|
||||||
if (!cachedAsset && url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
|
if (cachedRes) {
|
||||||
return caches.match('/service-worker-index.html');
|
return cachedRes;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
const res = await fetch(event.request);
|
||||||
return cachedAsset || fetchAndCache(event.request);
|
cache.put(event.request, res.clone());
|
||||||
})()
|
return res;
|
||||||
);
|
})(),
|
||||||
}
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,12 +7,12 @@ export const notificationSupported = writable(false);
|
||||||
export const notificationAllowed = writable(true);
|
export const notificationAllowed = writable(true);
|
||||||
|
|
||||||
const firebaseConfig = {
|
const firebaseConfig = {
|
||||||
apiKey: __paimon.env.FIREBASE_API_KEY,
|
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
|
||||||
authDomain: __paimon.env.FIREBASE_AUTH_DOMAIN,
|
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
|
||||||
projectId: __paimon.env.FIREBASE_PROJECT_ID,
|
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
|
||||||
storageBucket: __paimon.env.FIREBASE_STORAGE_BUCKET,
|
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
|
||||||
messagingSenderId: __paimon.env.FIREBASE_MESSAGING_SENDER_ID,
|
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
|
||||||
appId: __paimon.env.FIREBASE_APP_ID,
|
appId: import.meta.env.VITE_FIREBASE_APP_ID,
|
||||||
};
|
};
|
||||||
|
|
||||||
let messaging;
|
let messaging;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash.debounce';
|
||||||
import localforage from 'localforage';
|
import localforage from 'localforage';
|
||||||
import { t as $t } from 'svelte-i18n';
|
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 sveltePreprocess = require('svelte-preprocess');
|
||||||
const postcss = require('./postcss.config');
|
// const postcss = require('./postcss.config');
|
||||||
|
|
||||||
const preprocess = sveltePreprocess({
|
// const preprocess = sveltePreprocess({
|
||||||
defaults: {
|
// defaults: {
|
||||||
style: 'postcss',
|
// 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