mirror of
https://github.com/jcreek/LivingDexTracker.git
synced 2026-07-15 20:13:45 +00:00
Compare commits
191 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c5a47439d9 | |||
| 19e4d7b727 | |||
| 8255fb4c67 | |||
| 069f7f41fa | |||
| 955cba1aaa | |||
| c5a503f5b5 | |||
| 71cfbce7e3 | |||
| 4f2fe5e333 | |||
| 575aafbc28 | |||
| 6ecaa0f30f | |||
| e55d511141 | |||
| 86e8d6f5e6 | |||
| 8141bd624b | |||
| ab82f75dc6 | |||
| 3f5c14a8bc | |||
| 8775e05ba7 | |||
| c5c63ab8ef | |||
| dd9ced17d8 | |||
| 606fcbb201 | |||
| dfa0569119 | |||
| e819929898 | |||
| decf6ca1fb | |||
| 6d54c93700 | |||
| 07ce2b3421 | |||
| 0c25bba236 | |||
| eba34158fe | |||
| 71df0de3df | |||
| 46351c9af0 | |||
| 479b3ae7a0 | |||
| a26f38bca1 | |||
| f302721119 | |||
| a604fe2526 | |||
| 88d8344706 | |||
| bfef2fd4a7 | |||
| ee73c01afe | |||
| 3f0003b006 | |||
| 874a6bd78e | |||
| d40d4aa4e1 | |||
| bde3d71e6c | |||
| a871da5d59 | |||
| d437c05770 | |||
| 9d14b2d2f1 | |||
| ad8c8a847d | |||
| 23e8382bd1 | |||
| d50417ffef | |||
| ad66b874e9 | |||
| a7d878fffd | |||
| c10b526b3e | |||
| 1614ff52be | |||
| 75f7161b7a | |||
| 5657c2b2ab | |||
| f17b350e4e | |||
| 68cc2a0712 | |||
| 7c68d121ce | |||
| adc96baa90 | |||
| 463ab88545 | |||
| fb8dbdda3e | |||
| ee03ffc11f | |||
| 070604fb89 | |||
| b30be24fd5 | |||
| b1b6e63b6f | |||
| 845cc1c739 | |||
| 84c6de6b62 | |||
| fc09b5f2f1 | |||
| 789321ce03 | |||
| cb0773b03e | |||
| cbece0ec22 | |||
| 8fa394f102 | |||
| bd3f266a4a | |||
| 35ee92df0c | |||
| ca6831d10a | |||
| 2c2ab8b99c | |||
| 07af29e6e6 | |||
| 28bb39d558 | |||
| b9a49686c1 | |||
| 19a571e315 | |||
| 578df57a45 | |||
| 6ec40056e1 | |||
| d18b231ac6 | |||
| 0e2d7f7792 | |||
| 78c3230b92 | |||
| 2f5c0d68be | |||
| 073ba77dee | |||
| 31eb551c8a | |||
| 5e0e45494f | |||
| 852c6c3f34 | |||
| c063e9d2cd | |||
| c2c8fd1fb4 | |||
| 5b7fe52dc4 | |||
| 31e8a0d686 | |||
| 120f936eb7 | |||
| 8459ecf3fe | |||
| dd31a8d040 | |||
| ebfe2413f0 | |||
| 389f73d164 | |||
| fa38fa69ca | |||
| bc9ce84615 | |||
| 70f7bbdffc | |||
| 3aa716b941 | |||
| a4269259f9 | |||
| bfde0c49f5 | |||
| 02a2160f08 | |||
| 4d9d5e74d7 | |||
| e4ca722de7 | |||
| ad13540879 | |||
| 6c9ec0239c | |||
| 1c207455fb | |||
| c071dca26a | |||
| 8b32bca11c | |||
| 5bdf88b735 | |||
| f62b18b0ee | |||
| 5468515d4b | |||
| 6f4847f126 | |||
| 2ad7e219a2 | |||
| d3b7e7f5a9 | |||
| 7b5a948910 | |||
| bc25ab0e38 | |||
| 0285725b6d | |||
| 62c03f41eb | |||
| 80fb0d7414 | |||
| 1c9a9bcf8f | |||
| ed1ea42e50 | |||
| 0edc7f0974 | |||
| 7467a4425f | |||
| 90f6bd6e75 | |||
| 953524cecf | |||
| 308753d2e5 | |||
| 2cf3a03f8f | |||
| 8d86d93bc0 | |||
| 0e3be214ba | |||
| 704e618f84 | |||
| 64c5f375ac | |||
| e512c63e0b | |||
| e7f1930eff | |||
| 0e8af37309 | |||
| 6aac4c5985 | |||
| 212f674b44 | |||
| 7deb4632bc | |||
| 70f85be9b9 | |||
| 24792331db | |||
| d59d970812 | |||
| ff43601b1a | |||
| 425d66a9ce | |||
| 4761bdf31a | |||
| 6a4c6d81b2 | |||
| cdab9b4ab5 | |||
| c17dc6090c | |||
| 3a72225e16 | |||
| 046b956882 | |||
| 43c7dab2ee | |||
| 5bbe8b9abe | |||
| ec6aa1a5cf | |||
| e6b4cc84bc | |||
| 548e918fd9 | |||
| 5285d5d84d | |||
| 63de9c82a4 | |||
| 6213c773c3 | |||
| 99ed144a34 | |||
| 6db13fff6d | |||
| 499ee75c6a | |||
| 580dd83c69 | |||
| d80da3e415 | |||
| 2a4a4a1414 | |||
| f6bf7a7a85 | |||
| 0204870f5a | |||
| 454259d9e7 | |||
| 23385d2c44 | |||
| 44fa581ecd | |||
| b15889d6af | |||
| 16a067cd5d | |||
| 335f5c9046 | |||
| d66ac7ae4b | |||
| 22b9af0bbe | |||
| db5ae6fdc1 | |||
| 4ff4243125 | |||
| 59ff274a44 | |||
| 88b4d92905 | |||
| e699298a82 | |||
| ee191aa7cf | |||
| d708de8b2c | |||
| 93db09d669 | |||
| 1475e06b8e | |||
| 496cdb6666 | |||
| d55dcb066d | |||
| 7518579047 | |||
| aaf60f9634 | |||
| 4ca2ddb181 | |||
| 49e39c2742 | |||
| 26c552e994 | |||
| e3420d6e02 | |||
| bf087bd77b |
+9
-3
@@ -1,3 +1,9 @@
|
||||
MONGO_URL=""
|
||||
PUBLIC_SUPABASE_URL=""
|
||||
PUBLIC_SUPABASE_ANON_KEY=""
|
||||
PUBLIC_SUPABASE_URL="your-supabase-project-url"
|
||||
PUBLIC_SUPABASE_ANON_KEY="your-supabase-anon-key"
|
||||
SUPABASE_SERVICE_ROLE_KEY="your-supabase-service-role-key"
|
||||
PUBLIC_USE_LOCAL_POKEMON_SPRITE_FOLDER="false"
|
||||
|
||||
GOOGLE_OAUTH_CLIENT_ID="your-google-client-id"
|
||||
GOOGLE_OAUTH_CLIENT_SECRET="your-google-client-secret"
|
||||
DROPBOX_OAUTH_CLIENT_ID="your-dropbox-client-id"
|
||||
DROPBOX_OAUTH_CLIENT_SECRET="your-dropbox-client-secret"
|
||||
|
||||
@@ -4,18 +4,24 @@ A web app to track completion of a living Pokédex.
|
||||
|
||||
## Developing
|
||||
|
||||
Cloned the repository you can install the dependencies with `npm install`, and start a development server:
|
||||
1. Clone the repository
|
||||
2. Install the dependencies with `npm install`
|
||||
3. Ensure that Docker is running
|
||||
4. An example `.env` file is provided in the repository. You will need to copy `.env.example` to `.env` and fill in the values with your own credentials. For local development with Supabase running in Docker, you can use the following values:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
- The `PUBLIC_SUPABASE_URL` will be `"http://127.0.0.1:54321"`
|
||||
- The `PUBLIC_SUPABASE_ANON_KEY` will be the 'Publishable' authentication key displayed when you run Supabase in the terminal
|
||||
- The `SUPABASE_SERVICE_ROLE_KEY` will be the 'Secret' authentication key displayed when you run Supabase in the terminal
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
5. Start local Supabase and a development server with `npm run dev:supabase`
|
||||
6. The Pokédex data is automatically seeded via database migrations when Supabase starts
|
||||
7. Create an account using the sign-up form and access the email it sends in [MailPit](http://127.0.0.1:54324/) to verify your email address.
|
||||
N.B. All local emails are captured by MailPit when running Supabase in Docker.
|
||||
8. You can now use [the app](http://localhost:5173/).
|
||||
|
||||
An example `.env` file is provided in the repository. You will need to copy `.env.example` to `.env` and fill in the values with your own credentials.
|
||||
## Reference Data Updates
|
||||
|
||||
Once you have done this, you can seed the Pokédex data using the /api/seed endpoint. You will need to comment out the `return;` at the beginning of the `GET` function in `/src/routes/api/seed.ts` to do this. Make sure you remember to uncomment it afterwards.
|
||||
The seed data lives in `supabase/migrations/20260118001000_seed_reference_data.sql`. Update that migration directly when new data is added. You can access a local copy of [Supabase](http://localhost:54323/) to check it.
|
||||
|
||||
## Building
|
||||
|
||||
@@ -27,14 +33,28 @@ npm run build
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
## Sprites
|
||||
|
||||
The app uses WebP sprites from `static/sprites-small`. During builds we generate this folder from the
|
||||
full-resolution PNGs in `static/sprites`:
|
||||
|
||||
```bash
|
||||
npm run sprites:build
|
||||
```
|
||||
|
||||
If you want to serve sprites locally, set `PUBLIC_USE_LOCAL_POKEMON_SPRITE_FOLDER="true"` in `.env`.
|
||||
Otherwise the app defaults to GitHub raw for `static/sprites-small`.
|
||||
|
||||
## Hosting
|
||||
|
||||
The app is hosted on [Netlify](https://www.netlify.com/) at [pokedex.jcreek.co.uk](https://pokedex.jcreek.co.uk/).
|
||||
|
||||
The Pokédex data is stored in a [MongoDB](https://www.mongodb.com/) database hosted on [MongoDB Cloud](https://cloud.mongodb.com/).
|
||||
The Pokédex data is stored in a [Supabase](https://supabase.com/) database.
|
||||
|
||||
User authentication is handled by [Supabase Auth](https://supabase.com/auth).
|
||||
|
||||
## Dependencies
|
||||
|
||||
The living dex tracker's sprite collection is taken from [PokéAPI Sprites](https://github.com/PokeAPI/sprites), which is licensed under [the Creative Commons CC0 1.0 Universal license](https://github.com/PokeAPI/sprites/blob/master/LICENCE.txt).
|
||||
The living dex tracker's sprite collection is derived from [PokéAPI Sprites](https://github.com/PokeAPI/sprites)
|
||||
and converted to smaller WebP files in `static/sprites-small`. PokéAPI sprites are licensed under
|
||||
[the Creative Commons CC0 1.0 Universal license](https://github.com/PokeAPI/sprites/blob/master/LICENCE.txt).
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
dexId,gameDisplayName,dexDisplayName,sortOrder,isDlc,parentDexId,file
|
||||
red-kanto,Red,Kanto,1,false,,native-game-dexes/red-blue-yellow.csv
|
||||
blue-kanto,Blue,Kanto,1,false,,native-game-dexes/red-blue-yellow.csv
|
||||
yellow-kanto,Yellow,Kanto,1,false,,native-game-dexes/red-blue-yellow.csv
|
||||
gold-johto,Gold,Johto,1,false,,native-game-dexes/gold-silver-crystal.csv
|
||||
silver-johto,Silver,Johto,1,false,,native-game-dexes/gold-silver-crystal.csv
|
||||
crystal-johto,Crystal,Johto,1,false,,native-game-dexes/gold-silver-crystal.csv
|
||||
ruby-hoenn,Ruby,Hoenn,1,false,,native-game-dexes/ruby-sapphire-emerald.csv
|
||||
sapphire-hoenn,Sapphire,Hoenn,1,false,,native-game-dexes/ruby-sapphire-emerald.csv
|
||||
emerald-hoenn,Emerald,Hoenn,1,false,,native-game-dexes/ruby-sapphire-emerald.csv
|
||||
firered-kanto,FireRed,Kanto,1,false,,native-game-dexes/fire-red-leaf-green.csv
|
||||
leafgreen-kanto,LeafGreen,Kanto,1,false,,native-game-dexes/fire-red-leaf-green.csv
|
||||
diamond-sinnoh,Diamond,Sinnoh,1,false,,native-game-dexes/diamond-pearl.csv
|
||||
pearl-sinnoh,Pearl,Sinnoh,1,false,,native-game-dexes/diamond-pearl.csv
|
||||
platinum-sinnoh,Platinum,Sinnoh,1,false,,native-game-dexes/platinum.csv
|
||||
heart-gold-johto,Heart Gold,Johto,1,false,,native-game-dexes/heart-gold-soul-silver.csv
|
||||
soul-silver-johto,Soul Silver,Johto,1,false,,native-game-dexes/heart-gold-soul-silver.csv
|
||||
black-unova,Black,Unova,1,false,,native-game-dexes/black-white.csv
|
||||
white-unova,White,Unova,1,false,,native-game-dexes/black-white.csv
|
||||
black-2-unova,Black 2,Unova,1,false,,native-game-dexes/black-2-white-2.csv
|
||||
white-2-unova,White 2,Unova,1,false,,native-game-dexes/black-2-white-2.csv
|
||||
x-central-kalos,X,Central Kalos,1,false,,native-game-dexes/x-y-central-kalos.csv
|
||||
x-coastal-kalos,X,Coastal Kalos,2,false,,native-game-dexes/x-y-coastal-kalos.csv
|
||||
x-mountain-kalos,X,Mountain Kalos,3,false,,native-game-dexes/x-y-mountain-kalos.csv
|
||||
y-central-kalos,Y,Central Kalos,1,false,,native-game-dexes/x-y-central-kalos.csv
|
||||
y-coastal-kalos,Y,Coastal Kalos,2,false,,native-game-dexes/x-y-coastal-kalos.csv
|
||||
y-mountain-kalos,Y,Mountain Kalos,3,false,,native-game-dexes/x-y-mountain-kalos.csv
|
||||
omega-ruby-hoenn,Omega Ruby,Hoenn,1,false,,native-game-dexes/omega-ruby-alpha-sapphire.csv
|
||||
alpha-sapphire-hoenn,Alpha Sapphire,Hoenn,1,false,,native-game-dexes/omega-ruby-alpha-sapphire.csv
|
||||
sun-alola,Sun,Alola,1,false,,native-game-dexes/sun-moon-alola.csv
|
||||
moon-alola,Moon,Alola,1,false,,native-game-dexes/sun-moon-alola.csv
|
||||
ultra-sun-alola,Ultra Sun,Alola,1,false,,native-game-dexes/ultra-sun-ultra-moon-alola.csv
|
||||
ultra-moon-alola,Ultra Moon,Alola,1,false,,native-game-dexes/ultra-sun-ultra-moon-alola.csv
|
||||
lg-pikachu-kanto,LG: Pikachu,Kanto,1,false,,native-game-dexes/lets-go-pikachu-eevee.csv
|
||||
lg-eevee-kanto,LG: Eevee,Kanto,1,false,,native-game-dexes/lets-go-pikachu-eevee.csv
|
||||
sword-galar,Sword,Galar,1,false,,native-game-dexes/sword-shield.csv
|
||||
sword-isle-armor,Sword,Isle of Armor,2,true,sword-galar,native-game-dexes/sword-shield-isle-armor.csv
|
||||
sword-crown-tundra,Sword,Crown Tundra,3,true,sword-galar,native-game-dexes/sword-shield-crown-tundra.csv
|
||||
shield-galar,Shield,Galar,1,false,,native-game-dexes/sword-shield.csv
|
||||
shield-isle-armor,Shield,Isle of Armor,2,true,shield-galar,native-game-dexes/sword-shield-isle-armor.csv
|
||||
shield-crown-tundra,Shield,Crown Tundra,3,true,shield-galar,native-game-dexes/sword-shield-crown-tundra.csv
|
||||
brilliant-diamond-sinnoh,Brilliant Diamond,Sinnoh,1,false,,native-game-dexes/brilliant-diamond-shining-pearl.csv
|
||||
shining-pearl-sinnoh,Shining Pearl,Sinnoh,1,false,,native-game-dexes/brilliant-diamond-shining-pearl.csv
|
||||
legends-arceus-hisui,Legends: Arceus,Hisui,1,false,,native-game-dexes/legends-arceus.csv
|
||||
scarlet-paldea,Scarlet,Paldea,1,false,,native-game-dexes/scarlet-violet.csv
|
||||
scarlet-kitakami,Scarlet,Kitakami,2,true,scarlet-paldea,native-game-dexes/scarlet-violet-kitakami.csv
|
||||
scarlet-blueberry,Scarlet,Blueberry,3,true,scarlet-paldea,native-game-dexes/scarlet-violet-blueberry.csv
|
||||
violet-paldea,Violet,Paldea,1,false,,native-game-dexes/scarlet-violet.csv
|
||||
violet-kitakami,Violet,Kitakami,2,true,violet-paldea,native-game-dexes/scarlet-violet-kitakami.csv
|
||||
violet-blueberry,Violet,Blueberry,3,true,violet-paldea,native-game-dexes/scarlet-violet-blueberry.csv
|
||||
legends-z-a-kalos,Legends: Z-A,Kalos,1,false,,native-game-dexes/legends-z-a.csv
|
||||
legends-z-a-mega-dimension,Legends: Z-A,Mega Dimension,2,true,legends-z-a-kalos,native-game-dexes/legends-z-a-mega-dimension.csv
|
||||
|
@@ -0,0 +1,46 @@
|
||||
game,region,releaseYear
|
||||
Red,Kanto,1996
|
||||
Blue,Kanto,1996
|
||||
Yellow,Kanto,1998
|
||||
Gold,Johto,1999
|
||||
Silver,Johto,1999
|
||||
Crystal,Johto,2000
|
||||
Ruby,Hoenn,2002
|
||||
Sapphire,Hoenn,2002
|
||||
Colosseum,Orre,2003
|
||||
Emerald,Hoenn,2004
|
||||
FireRed,Kanto,2004
|
||||
LeafGreen,Kanto,2004
|
||||
XD: Gale of Darkness,Orre,2005
|
||||
Diamond,Sinnoh,2006
|
||||
Pearl,Sinnoh,2006
|
||||
Platinum,Sinnoh,2008
|
||||
Ranch,Ranch,2008
|
||||
Heart Gold,Johto,2009
|
||||
Soul Silver,Johto,2009
|
||||
Black,Unova,2010
|
||||
White,Unova,2010
|
||||
Black 2,Unova,2012
|
||||
White 2,Unova,2012
|
||||
Dream Radar,Unova,2012
|
||||
X,Kalos,2013
|
||||
Y,Kalos,2013
|
||||
Omega Ruby,Hoenn,2014
|
||||
Alpha Sapphire,Hoenn,2014
|
||||
Sun,Alola,2016
|
||||
Moon,Alola,2016
|
||||
Moon (demo),Alola,2016
|
||||
Go,Go,2016
|
||||
Ultra Sun,Alola,2017
|
||||
Ultra Moon,Alola,2017
|
||||
LG: Pikachu,Kanto,2018
|
||||
LG: Eevee,Kanto,2018
|
||||
Sword,Galar,2019
|
||||
Shield,Galar,2019
|
||||
Home,Home,2020
|
||||
Brilliant Diamond,Sinnoh,2021
|
||||
Shining Pearl,Sinnoh,2021
|
||||
Legends: Arceus,Hisui,2022
|
||||
Scarlet,Paldea,2022
|
||||
Violet,Paldea,2022
|
||||
Legends: Z-A,Kalos,2025
|
||||
|
@@ -0,0 +1,302 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
0,Victini,,
|
||||
1,Snivy,,
|
||||
2,Servine,,
|
||||
3,Serperior,,
|
||||
4,Tepig,,
|
||||
5,Pignite,,
|
||||
6,Emboar,,
|
||||
7,Oshawott,,
|
||||
8,Dewott,,
|
||||
9,Samurott,,
|
||||
10,Patrat,,
|
||||
11,Watchog,,
|
||||
12,Purrloin,,
|
||||
13,Liepard,,
|
||||
14,Pidove,,
|
||||
15,Tranquill,,
|
||||
16,Unfezant,,
|
||||
17,Sewaddle,,
|
||||
18,Swadloon,,
|
||||
19,Leavanny,,
|
||||
20,Sunkern,,
|
||||
21,Sunflora,,
|
||||
22,Lillipup,,
|
||||
23,Herdier,,
|
||||
24,Stoutland,,
|
||||
25,Mareep,,
|
||||
26,Flaaffy,,
|
||||
27,Ampharos,,
|
||||
28,Psyduck,,
|
||||
29,Golduck,,
|
||||
30,Azurill,,
|
||||
31,Marill,,
|
||||
32,Azumarill,,
|
||||
33,Riolu,,
|
||||
34,Lucario,,
|
||||
35,Dunsparce,,
|
||||
36,Audino,,
|
||||
37,Pansage,,
|
||||
38,Simisage,,
|
||||
39,Pansear,,
|
||||
40,Simisear,,
|
||||
41,Panpour,,
|
||||
42,Simipour,,
|
||||
43,Venipede,,
|
||||
44,Whirlipede,,
|
||||
45,Scolipede,,
|
||||
46,Koffing,,
|
||||
47,Weezing,,
|
||||
48,Magnemite,,
|
||||
49,Magneton,,
|
||||
50,Magnezone,,
|
||||
51,Growlithe,,
|
||||
52,Arcanine,,
|
||||
53,Magby,,
|
||||
54,Magmar,,
|
||||
55,Magmortar,,
|
||||
56,Elekid,,
|
||||
57,Electabuzz,,
|
||||
58,Electivire,,
|
||||
59,Rattata,,
|
||||
60,Raticate,,
|
||||
61,Zubat,,
|
||||
62,Golbat,,
|
||||
63,Crobat,,
|
||||
64,Grimer,,
|
||||
65,Muk,,
|
||||
66,Woobat,,
|
||||
67,Swoobat,,
|
||||
68,Roggenrola,,
|
||||
69,Boldore,,
|
||||
70,Gigalith,,
|
||||
71,Onix,,
|
||||
72,Steelix,,
|
||||
73,Timburr,,
|
||||
74,Gurdurr,,
|
||||
75,Conkeldurr,,
|
||||
76,Drilbur,,
|
||||
77,Excadrill,,
|
||||
78,Skitty,,
|
||||
79,Delcatty,,
|
||||
80,Buneary,,
|
||||
81,Lopunny,,
|
||||
82,Cottonee,,
|
||||
83,Whimsicott,,
|
||||
84,Petilil,,
|
||||
85,Lilligant,,
|
||||
86,Munna,,
|
||||
87,Musharna,,
|
||||
88,Cleffa,,
|
||||
89,Clefairy,,
|
||||
90,Clefable,,
|
||||
91,Eevee,,
|
||||
92,Vaporeon,,
|
||||
93,Jolteon,,
|
||||
94,Flareon,,
|
||||
95,Espeon,,
|
||||
96,Umbreon,,
|
||||
97,Leafeon,,
|
||||
98,Glaceon,,
|
||||
99,Sandile,,
|
||||
100,Krokorok,,
|
||||
101,Krookodile,,
|
||||
102,Darumaka,,
|
||||
103,Darmanitan,,
|
||||
104,Basculin,,
|
||||
105,Trubbish,,
|
||||
106,Garbodor,,
|
||||
107,Minccino,,
|
||||
108,Cinccino,,
|
||||
109,Rufflet,,
|
||||
110,Braviary,,
|
||||
111,Vullaby,,
|
||||
112,Mandibuzz,,
|
||||
113,Sandshrew,,
|
||||
114,Sandslash,,
|
||||
115,Dwebble,,
|
||||
116,Crustle,,
|
||||
117,Scraggy,,
|
||||
118,Scrafty,,
|
||||
119,Maractus,,
|
||||
120,Sigilyph,,
|
||||
121,Trapinch,,
|
||||
122,Vibrava,,
|
||||
123,Flygon,,
|
||||
124,Yamask,,
|
||||
125,Cofagrigus,,
|
||||
126,Tirtouga,,
|
||||
127,Carracosta,,
|
||||
128,Archen,,
|
||||
129,Archeops,,
|
||||
130,Klink,,
|
||||
131,Klang,,
|
||||
132,Klinklang,,
|
||||
133,Budew,,
|
||||
134,Roselia,,
|
||||
135,Roserade,,
|
||||
136,Gothita,,
|
||||
137,Gothorita,,
|
||||
138,Gothitelle,,
|
||||
139,Solosis,,
|
||||
140,Duosion,,
|
||||
141,Reuniclus,,
|
||||
142,Combee,,
|
||||
143,Vespiquen,,
|
||||
144,Emolga,,
|
||||
145,Heracross,,
|
||||
146,Pinsir,,
|
||||
147,Blitzle,,
|
||||
148,Zebstrika,,
|
||||
149,Buizel,,
|
||||
150,Floatzel,,
|
||||
151,Zorua,,
|
||||
152,Zoroark,,
|
||||
153,Ducklett,,
|
||||
154,Swanna,,
|
||||
155,Karrablast,,
|
||||
156,Escavalier,,
|
||||
157,Shelmet,,
|
||||
158,Accelgor,,
|
||||
159,Deerling,,
|
||||
160,Sawsbuck,,
|
||||
161,Foongus,,
|
||||
162,Amoonguss,,
|
||||
163,Castform,,
|
||||
164,Nosepass,,
|
||||
165,Probopass,,
|
||||
166,Aron,,
|
||||
167,Lairon,,
|
||||
168,Aggron,,
|
||||
169,Baltoy,,
|
||||
170,Claydol,,
|
||||
171,Larvesta,,
|
||||
172,Volcarona,,
|
||||
173,Joltik,,
|
||||
174,Galvantula,,
|
||||
175,Ferroseed,,
|
||||
176,Ferrothorn,,
|
||||
177,Tynamo,,
|
||||
178,Eelektrik,,
|
||||
179,Eelektross,,
|
||||
180,Frillish,,
|
||||
181,Jellicent,,
|
||||
182,Alomomola,,
|
||||
183,Axew,,
|
||||
184,Fraxure,,
|
||||
185,Haxorus,,
|
||||
186,Zangoose,,
|
||||
187,Seviper,,
|
||||
188,Elgyem,,
|
||||
189,Beheeyem,,
|
||||
190,Litwick,,
|
||||
191,Lampent,,
|
||||
192,Chandelure,,
|
||||
193,Heatmor,,
|
||||
194,Durant,,
|
||||
195,Cubchoo,,
|
||||
196,Beartic,,
|
||||
197,Cryogonal,,
|
||||
198,Tornadus,,
|
||||
199,Thundurus,,
|
||||
200,Landorus,,
|
||||
201,Skorupi,,
|
||||
202,Drapion,,
|
||||
203,Skarmory,,
|
||||
204,Numel,,
|
||||
205,Camerupt,,
|
||||
206,Spoink,,
|
||||
207,Grumpig,,
|
||||
208,Drifloon,,
|
||||
209,Drifblim,,
|
||||
210,Shuppet,,
|
||||
211,Banette,,
|
||||
212,Wingull,,
|
||||
213,Pelipper,,
|
||||
214,Lunatone,,
|
||||
215,Solrock,,
|
||||
216,Absol,,
|
||||
217,Tangela,,
|
||||
218,Tangrowth,,
|
||||
219,Mienfoo,,
|
||||
220,Mienshao,,
|
||||
221,Gligar,,
|
||||
222,Gliscor,,
|
||||
223,Pawniard,,
|
||||
224,Bisharp,,
|
||||
225,Cobalion,,
|
||||
226,Terrakion,,
|
||||
227,Virizion,,
|
||||
228,Tympole,,
|
||||
229,Palpitoad,,
|
||||
230,Seismitoad,,
|
||||
231,Stunfisk,,
|
||||
232,Shuckle,,
|
||||
233,Mantyke,,
|
||||
234,Mantine,,
|
||||
235,Remoraid,,
|
||||
236,Octillery,,
|
||||
237,Corsola,,
|
||||
238,Staryu,,
|
||||
239,Starmie,,
|
||||
240,Wailmer,,
|
||||
241,Wailord,,
|
||||
242,Lapras,,
|
||||
243,Spheal,,
|
||||
244,Sealeo,,
|
||||
245,Walrein,,
|
||||
246,Swablu,,
|
||||
247,Altaria,,
|
||||
248,Vulpix,,
|
||||
249,Ninetales,,
|
||||
250,Bronzor,,
|
||||
251,Bronzong,,
|
||||
252,Sneasel,,
|
||||
253,Weavile,,
|
||||
254,Delibird,,
|
||||
255,Vanillite,,
|
||||
256,Vanillish,,
|
||||
257,Vanilluxe,,
|
||||
258,Swinub,,
|
||||
259,Piloswine,,
|
||||
260,Mamoswine,,
|
||||
261,Ditto,,
|
||||
262,Beldum,,
|
||||
263,Metang,,
|
||||
264,Metagross,,
|
||||
265,Seel,,
|
||||
266,Dewgong,,
|
||||
267,Throh,,
|
||||
268,Sawk,,
|
||||
269,Bouffalant,,
|
||||
270,Druddigon,,
|
||||
271,Golett,,
|
||||
272,Golurk,,
|
||||
273,Deino,,
|
||||
274,Zweilous,,
|
||||
275,Hydreigon,,
|
||||
276,Slakoth,,
|
||||
277,Vigoroth,,
|
||||
278,Slaking,,
|
||||
279,Corphish,,
|
||||
280,Crawdaunt,,
|
||||
281,Igglybuff,,
|
||||
282,Jigglypuff,,
|
||||
283,Wigglytuff,,
|
||||
284,Lickitung,,
|
||||
285,Lickilicky,,
|
||||
286,Yanma,,
|
||||
287,Yanmega,,
|
||||
288,Tropius,,
|
||||
289,Carnivine,,
|
||||
290,Croagunk,,
|
||||
291,Toxicroak,,
|
||||
292,Larvitar,,
|
||||
293,Pupitar,,
|
||||
294,Tyranitar,,
|
||||
295,Reshiram,,
|
||||
296,Zekrom,,
|
||||
297,Kyurem,,
|
||||
298,Keldeo,,
|
||||
299,Meloetta,,
|
||||
300,Genesect,,
|
||||
|
@@ -0,0 +1,157 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
0,Victini,,
|
||||
1,Snivy,,
|
||||
2,Servine,,
|
||||
3,Serperior,,
|
||||
4,Tepig,,
|
||||
5,Pignite,,
|
||||
6,Emboar,,
|
||||
7,Oshawott,,
|
||||
8,Dewott,,
|
||||
9,Samurott,,
|
||||
10,Patrat,,
|
||||
11,Watchog,,
|
||||
12,Lillipup,,
|
||||
13,Herdier,,
|
||||
14,Stoutland,,
|
||||
15,Purrloin,,
|
||||
16,Liepard,,
|
||||
17,Pansage,,
|
||||
18,Simisage,,
|
||||
19,Pansear,,
|
||||
20,Simisear,,
|
||||
21,Panpour,,
|
||||
22,Simipour,,
|
||||
23,Munna,,
|
||||
24,Musharna,,
|
||||
25,Pidove,,
|
||||
26,Tranquill,,
|
||||
27,Unfezant,,
|
||||
28,Blitzle,,
|
||||
29,Zebstrika,,
|
||||
30,Roggenrola,,
|
||||
31,Boldore,,
|
||||
32,Gigalith,,
|
||||
33,Woobat,,
|
||||
34,Swoobat,,
|
||||
35,Drilbur,,
|
||||
36,Excadrill,,
|
||||
37,Audino,,
|
||||
38,Timburr,,
|
||||
39,Gurdurr,,
|
||||
40,Conkeldurr,,
|
||||
41,Tympole,,
|
||||
42,Palpitoad,,
|
||||
43,Seismitoad,,
|
||||
44,Throh,,
|
||||
45,Sawk,,
|
||||
46,Sewaddle,,
|
||||
47,Swadloon,,
|
||||
48,Leavanny,,
|
||||
49,Venipede,,
|
||||
50,Whirlipede,,
|
||||
51,Scolipede,,
|
||||
52,Cottonee,,
|
||||
53,Whimsicott,,
|
||||
54,Petilil,,
|
||||
55,Lilligant,,
|
||||
56,Basculin,,
|
||||
57,Sandile,,
|
||||
58,Krokorok,,
|
||||
59,Krookodile,,
|
||||
60,Darumaka,,
|
||||
61,Darmanitan,,
|
||||
62,Maractus,,
|
||||
63,Dwebble,,
|
||||
64,Crustle,,
|
||||
65,Scraggy,,
|
||||
66,Scrafty,,
|
||||
67,Sigilyph,,
|
||||
68,Yamask,,
|
||||
69,Cofagrigus,,
|
||||
70,Tirtouga,,
|
||||
71,Carracosta,,
|
||||
72,Archen,,
|
||||
73,Archeops,,
|
||||
74,Trubbish,,
|
||||
75,Garbodor,,
|
||||
76,Zorua,,
|
||||
77,Zoroark,,
|
||||
78,Minccino,,
|
||||
79,Cinccino,,
|
||||
80,Gothita,,
|
||||
81,Gothorita,,
|
||||
82,Gothitelle,,
|
||||
83,Solosis,,
|
||||
84,Duosion,,
|
||||
85,Reuniclus,,
|
||||
86,Ducklett,,
|
||||
87,Swanna,,
|
||||
88,Vanillite,,
|
||||
89,Vanillish,,
|
||||
90,Vanilluxe,,
|
||||
91,Deerling,,
|
||||
92,Sawsbuck,,
|
||||
93,Emolga,,
|
||||
94,Karrablast,,
|
||||
95,Escavalier,,
|
||||
96,Foongus,,
|
||||
97,Amoonguss,,
|
||||
98,Frillish,,
|
||||
99,Jellicent,,
|
||||
100,Alomomola,,
|
||||
101,Joltik,,
|
||||
102,Galvantula,,
|
||||
103,Ferroseed,,
|
||||
104,Ferrothorn,,
|
||||
105,Klink,,
|
||||
106,Klang,,
|
||||
107,Klinklang,,
|
||||
108,Tynamo,,
|
||||
109,Eelektrik,,
|
||||
110,Eelektross,,
|
||||
111,Elgyem,,
|
||||
112,Beheeyem,,
|
||||
113,Litwick,,
|
||||
114,Lampent,,
|
||||
115,Chandelure,,
|
||||
116,Axew,,
|
||||
117,Fraxure,,
|
||||
118,Haxorus,,
|
||||
119,Cubchoo,,
|
||||
120,Beartic,,
|
||||
121,Cryogonal,,
|
||||
122,Shelmet,,
|
||||
123,Accelgor,,
|
||||
124,Stunfisk,,
|
||||
125,Mienfoo,,
|
||||
126,Mienshao,,
|
||||
127,Druddigon,,
|
||||
128,Golett,,
|
||||
129,Golurk,,
|
||||
130,Pawniard,,
|
||||
131,Bisharp,,
|
||||
132,Bouffalant,,
|
||||
133,Rufflet,,
|
||||
134,Braviary,,
|
||||
135,Vullaby,,
|
||||
136,Mandibuzz,,
|
||||
137,Heatmor,,
|
||||
138,Durant,,
|
||||
139,Deino,,
|
||||
140,Zweilous,,
|
||||
141,Hydreigon,,
|
||||
142,Larvesta,,
|
||||
143,Volcarona,,
|
||||
144,Cobalion,,
|
||||
145,Terrakion,,
|
||||
146,Virizion,,
|
||||
147,Tornadus,,
|
||||
148,Thundurus,,
|
||||
149,Reshiram,,
|
||||
150,Zekrom,,
|
||||
151,Landorus,,
|
||||
152,Kyurem,,
|
||||
153,Keldeo,,
|
||||
154,Meloetta,,
|
||||
155,Genesect,,
|
||||
|
@@ -0,0 +1,152 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Turtwig,,
|
||||
2,Grotle,,
|
||||
3,Torterra,,
|
||||
4,Chimchar,,
|
||||
5,Monferno,,
|
||||
6,Infernape,,
|
||||
7,Piplup,,
|
||||
8,Prinplup,,
|
||||
9,Empoleon,,
|
||||
10,Starly,,
|
||||
11,Staravia,,
|
||||
12,Staraptor,,
|
||||
13,Bidoof,,
|
||||
14,Bibarel,,
|
||||
15,Kricketot,,
|
||||
16,Kricketune,,
|
||||
17,Shinx,,
|
||||
18,Luxio,,
|
||||
19,Luxray,,
|
||||
20,Abra,,
|
||||
21,Kadabra,,
|
||||
22,Alakazam,,
|
||||
23,Magikarp,,
|
||||
24,Gyarados,,
|
||||
25,Budew,,
|
||||
26,Roselia,,
|
||||
27,Roserade,,
|
||||
28,Zubat,,
|
||||
29,Golbat,,
|
||||
30,Crobat,,
|
||||
31,Geodude,,
|
||||
32,Graveler,,
|
||||
33,Golem,,
|
||||
34,Onix,,
|
||||
35,Steelix,,
|
||||
36,Cranidos,,
|
||||
37,Rampardos,,
|
||||
38,Shieldon,,
|
||||
39,Bastiodon,,
|
||||
40,Machop,,
|
||||
41,Machoke,,
|
||||
42,Machamp,,
|
||||
43,Psyduck,,
|
||||
44,Golduck,,
|
||||
45,Burmy,,
|
||||
46,Wormadam,,
|
||||
47,Mothim,,
|
||||
48,Wurmple,,
|
||||
49,Silcoon,,
|
||||
50,Beautifly,,
|
||||
51,Cascoon,,
|
||||
52,Dustox,,
|
||||
53,Combee,,
|
||||
54,Vespiquen,,
|
||||
55,Pachirisu,,
|
||||
56,Buizel,,
|
||||
57,Floatzel,,
|
||||
58,Cherubi,,
|
||||
59,Cherrim,,
|
||||
60,Shellos,,
|
||||
61,Gastrodon,,
|
||||
62,Heracross,,
|
||||
63,Aipom,,
|
||||
64,Ambipom,,
|
||||
65,Drifloon,,
|
||||
66,Drifblim,,
|
||||
67,Buneary,,
|
||||
68,Lopunny,,
|
||||
69,Gastly,,
|
||||
70,Haunter,,
|
||||
71,Gengar,,
|
||||
72,Misdreavus,,
|
||||
73,Mismagius,,
|
||||
74,Murkrow,,
|
||||
75,Honchkrow,,
|
||||
76,Glameow,,
|
||||
77,Purugly,,
|
||||
78,Goldeen,,
|
||||
79,Seaking,,
|
||||
80,Barboach,,
|
||||
81,Whiscash,,
|
||||
82,Chingling,,
|
||||
83,Chimecho,,
|
||||
84,Stunky,,
|
||||
85,Skuntank,,
|
||||
86,Meditite,,
|
||||
87,Medicham,,
|
||||
88,Bronzor,,
|
||||
89,Bronzong,,
|
||||
90,Ponyta,,
|
||||
91,Rapidash,,
|
||||
92,Bonsly,,
|
||||
93,Sudowoodo,,
|
||||
94,Mime Jr.,,
|
||||
95,Mr. Mime,,
|
||||
96,Happiny,,
|
||||
97,Chansey,,
|
||||
98,Blissey,,
|
||||
99,Cleffa,,
|
||||
100,Clefairy,,
|
||||
101,Clefable,,
|
||||
102,Chatot,,
|
||||
103,Pichu,,
|
||||
104,Pikachu,,
|
||||
105,Raichu,,
|
||||
106,Hoothoot,,
|
||||
107,Noctowl,,
|
||||
108,Spiritomb,,
|
||||
109,Gible,,
|
||||
110,Gabite,,
|
||||
111,Garchomp,,
|
||||
112,Munchlax,,
|
||||
113,Snorlax,,
|
||||
114,Unown,,
|
||||
115,Riolu,,
|
||||
116,Lucario,,
|
||||
117,Wooper,,
|
||||
118,Quagsire,,
|
||||
119,Wingull,,
|
||||
120,Pelipper,,
|
||||
121,Girafarig,,
|
||||
122,Hippopotas,,
|
||||
123,Hippowdon,,
|
||||
124,Azurill,,
|
||||
125,Marill,,
|
||||
126,Azumarill,,
|
||||
127,Skorupi,,
|
||||
128,Drapion,,
|
||||
129,Croagunk,,
|
||||
130,Toxicroak,,
|
||||
131,Carnivine,,
|
||||
132,Remoraid,,
|
||||
133,Octillery,,
|
||||
134,Finneon,,
|
||||
135,Lumineon,,
|
||||
136,Tentacool,,
|
||||
137,Tentacruel,,
|
||||
138,Feebas,,
|
||||
139,Milotic,,
|
||||
140,Mantyke,,
|
||||
141,Mantine,,
|
||||
142,Snover,,
|
||||
143,Abomasnow,,
|
||||
144,Sneasel,,
|
||||
145,Weavile,,
|
||||
146,Uxie,,
|
||||
147,Mesprit,,
|
||||
148,Azelf,,
|
||||
149,Dialga,,
|
||||
150,Palkia,,
|
||||
151,Manaphy,,
|
||||
|
@@ -0,0 +1,152 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Turtwig,,
|
||||
2,Grotle,,
|
||||
3,Torterra,,
|
||||
4,Chimchar,,
|
||||
5,Monferno,,
|
||||
6,Infernape,,
|
||||
7,Piplup,,
|
||||
8,Prinplup,,
|
||||
9,Empoleon,,
|
||||
10,Starly,,
|
||||
11,Staravia,,
|
||||
12,Staraptor,,
|
||||
13,Bidoof,,
|
||||
14,Bibarel,,
|
||||
15,Kricketot,,
|
||||
16,Kricketune,,
|
||||
17,Shinx,,
|
||||
18,Luxio,,
|
||||
19,Luxray,,
|
||||
20,Abra,,
|
||||
21,Kadabra,,
|
||||
22,Alakazam,,
|
||||
23,Magikarp,,
|
||||
24,Gyarados,,
|
||||
25,Budew,,
|
||||
26,Roselia,,
|
||||
27,Roserade,,
|
||||
28,Zubat,,
|
||||
29,Golbat,,
|
||||
30,Crobat,,
|
||||
31,Geodude,,
|
||||
32,Graveler,,
|
||||
33,Golem,,
|
||||
34,Onix,,
|
||||
35,Steelix,,
|
||||
36,Cranidos,,
|
||||
37,Rampardos,,
|
||||
38,Shieldon,,
|
||||
39,Bastiodon,,
|
||||
40,Machop,,
|
||||
41,Machoke,,
|
||||
42,Machamp,,
|
||||
43,Psyduck,,
|
||||
44,Golduck,,
|
||||
45,Burmy,,
|
||||
46,Wormadam,,
|
||||
47,Mothim,,
|
||||
48,Wurmple,,
|
||||
49,Silcoon,,
|
||||
50,Beautifly,,
|
||||
51,Cascoon,,
|
||||
52,Dustox,,
|
||||
53,Combee,,
|
||||
54,Vespiquen,,
|
||||
55,Pachirisu,,
|
||||
56,Buizel,,
|
||||
57,Floatzel,,
|
||||
58,Cherubi,,
|
||||
59,Cherrim,,
|
||||
60,Shellos,,
|
||||
61,Gastrodon,,
|
||||
62,Heracross,,
|
||||
63,Aipom,,
|
||||
64,Ambipom,,
|
||||
65,Drifloon,,
|
||||
66,Drifblim,,
|
||||
67,Buneary,,
|
||||
68,Lopunny,,
|
||||
69,Gastly,,
|
||||
70,Haunter,,
|
||||
71,Gengar,,
|
||||
72,Misdreavus,,
|
||||
73,Mismagius,,
|
||||
74,Murkrow,,
|
||||
75,Honchkrow,,
|
||||
76,Glameow,,
|
||||
77,Purugly,,
|
||||
78,Goldeen,,
|
||||
79,Seaking,,
|
||||
80,Barboach,,
|
||||
81,Whiscash,,
|
||||
82,Chingling,,
|
||||
83,Chimecho,,
|
||||
84,Stunky,,
|
||||
85,Skuntank,,
|
||||
86,Meditite,,
|
||||
87,Medicham,,
|
||||
88,Bronzor,,
|
||||
89,Bronzong,,
|
||||
90,Ponyta,,
|
||||
91,Rapidash,,
|
||||
92,Bonsly,,
|
||||
93,Sudowoodo,,
|
||||
94,Mime Jr.,,
|
||||
95,Mr. Mime,,
|
||||
96,Happiny,,
|
||||
97,Chansey,,
|
||||
98,Blissey,,
|
||||
99,Cleffa,,
|
||||
100,Clefairy,,
|
||||
101,Clefable,,
|
||||
102,Chatot,,
|
||||
103,Pichu,,
|
||||
104,Pikachu,,
|
||||
105,Raichu,,
|
||||
106,Hoothoot,,
|
||||
107,Noctowl,,
|
||||
108,Spiritomb,,
|
||||
109,Gible,,
|
||||
110,Gabite,,
|
||||
111,Garchomp,,
|
||||
112,Munchlax,,
|
||||
113,Snorlax,,
|
||||
114,Unown,,
|
||||
115,Riolu,,
|
||||
116,Lucario,,
|
||||
117,Wooper,,
|
||||
118,Quagsire,,
|
||||
119,Wingull,,
|
||||
120,Pelipper,,
|
||||
121,Girafarig,,
|
||||
122,Hippopotas,,
|
||||
123,Hippowdon,,
|
||||
124,Azurill,,
|
||||
125,Marill,,
|
||||
126,Azumarill,,
|
||||
127,Skorupi,,
|
||||
128,Drapion,,
|
||||
129,Croagunk,,
|
||||
130,Toxicroak,,
|
||||
131,Carnivine,,
|
||||
132,Remoraid,,
|
||||
133,Octillery,,
|
||||
134,Finneon,,
|
||||
135,Lumineon,,
|
||||
136,Tentacool,,
|
||||
137,Tentacruel,,
|
||||
138,Feebas,,
|
||||
139,Milotic,,
|
||||
140,Mantyke,,
|
||||
141,Mantine,,
|
||||
142,Snover,,
|
||||
143,Abomasnow,,
|
||||
144,Sneasel,,
|
||||
145,Weavile,,
|
||||
146,Uxie,,
|
||||
147,Mesprit,,
|
||||
148,Azelf,,
|
||||
149,Dialga,,
|
||||
150,Palkia,,
|
||||
151,Manaphy,,
|
||||
|
@@ -0,0 +1,152 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Bulbasaur,,
|
||||
2,Ivysaur,,
|
||||
3,Venusaur,,
|
||||
4,Charmander,,
|
||||
5,Charmeleon,,
|
||||
6,Charizard,,
|
||||
7,Squirtle,,
|
||||
8,Wartortle,,
|
||||
9,Blastoise,,
|
||||
10,Caterpie,,
|
||||
11,Metapod,,
|
||||
12,Butterfree,,
|
||||
13,Weedle,,
|
||||
14,Kakuna,,
|
||||
15,Beedrill,,
|
||||
16,Pidgey,,
|
||||
17,Pidgeotto,,
|
||||
18,Pidgeot,,
|
||||
19,Rattata,,
|
||||
20,Raticate,,
|
||||
21,Spearow,,
|
||||
22,Fearow,,
|
||||
23,Ekans,,
|
||||
24,Arbok,,
|
||||
25,Pikachu,,
|
||||
26,Raichu,,
|
||||
27,Sandshrew,,
|
||||
28,Sandslash,,
|
||||
29,Nidoran♀,,
|
||||
30,Nidorina,,
|
||||
31,Nidoqueen,,
|
||||
32,Nidoran♂,,
|
||||
33,Nidorino,,
|
||||
34,Nidoking,,
|
||||
35,Clefairy,,
|
||||
36,Clefable,,
|
||||
37,Vulpix,,
|
||||
38,Ninetales,,
|
||||
39,Jigglypuff,,
|
||||
40,Wigglytuff,,
|
||||
41,Zubat,,
|
||||
42,Golbat,,
|
||||
43,Oddish,,
|
||||
44,Gloom,,
|
||||
45,Vileplume,,
|
||||
46,Paras,,
|
||||
47,Parasect,,
|
||||
48,Venonat,,
|
||||
49,Venomoth,,
|
||||
50,Diglett,,
|
||||
51,Dugtrio,,
|
||||
52,Meowth,,
|
||||
53,Persian,,
|
||||
54,Psyduck,,
|
||||
55,Golduck,,
|
||||
56,Mankey,,
|
||||
57,Primeape,,
|
||||
58,Growlithe,,
|
||||
59,Arcanine,,
|
||||
60,Poliwag,,
|
||||
61,Poliwhirl,,
|
||||
62,Poliwrath,,
|
||||
63,Abra,,
|
||||
64,Kadabra,,
|
||||
65,Alakazam,,
|
||||
66,Machop,,
|
||||
67,Machoke,,
|
||||
68,Machamp,,
|
||||
69,Bellsprout,,
|
||||
70,Weepinbell,,
|
||||
71,Victreebel,,
|
||||
72,Tentacool,,
|
||||
73,Tentacruel,,
|
||||
74,Geodude,,
|
||||
75,Graveler,,
|
||||
76,Golem,,
|
||||
77,Ponyta,,
|
||||
78,Rapidash,,
|
||||
79,Slowpoke,,
|
||||
80,Slowbro,,
|
||||
81,Magnemite,,
|
||||
82,Magneton,,
|
||||
83,Farfetch’d,,
|
||||
84,Doduo,,
|
||||
85,Dodrio,,
|
||||
86,Seel,,
|
||||
87,Dewgong,,
|
||||
88,Grimer,,
|
||||
89,Muk,,
|
||||
90,Shellder,,
|
||||
91,Cloyster,,
|
||||
92,Gastly,,
|
||||
93,Haunter,,
|
||||
94,Gengar,,
|
||||
95,Onix,,
|
||||
96,Drowzee,,
|
||||
97,Hypno,,
|
||||
98,Krabby,,
|
||||
99,Kingler,,
|
||||
100,Voltorb,,
|
||||
101,Electrode,,
|
||||
102,Exeggcute,,
|
||||
103,Exeggutor,,
|
||||
104,Cubone,,
|
||||
105,Marowak,,
|
||||
106,Hitmonlee,,
|
||||
107,Hitmonchan,,
|
||||
108,Lickitung,,
|
||||
109,Koffing,,
|
||||
110,Weezing,,
|
||||
111,Rhyhorn,,
|
||||
112,Rhydon,,
|
||||
113,Chansey,,
|
||||
114,Tangela,,
|
||||
115,Kangaskhan,,
|
||||
116,Horsea,,
|
||||
117,Seadra,,
|
||||
118,Goldeen,,
|
||||
119,Seaking,,
|
||||
120,Staryu,,
|
||||
121,Starmie,,
|
||||
122,Mr. Mime,,
|
||||
123,Scyther,,
|
||||
124,Jynx,,
|
||||
125,Electabuzz,,
|
||||
126,Magmar,,
|
||||
127,Pinsir,,
|
||||
128,Tauros,,
|
||||
129,Magikarp,,
|
||||
130,Gyarados,,
|
||||
131,Lapras,,
|
||||
132,Ditto,,
|
||||
133,Eevee,,
|
||||
134,Vaporeon,,
|
||||
135,Jolteon,,
|
||||
136,Flareon,,
|
||||
137,Porygon,,
|
||||
138,Omanyte,,
|
||||
139,Omastar,,
|
||||
140,Kabuto,,
|
||||
141,Kabutops,,
|
||||
142,Aerodactyl,,
|
||||
143,Snorlax,,
|
||||
144,Articuno,,
|
||||
145,Zapdos,,
|
||||
146,Moltres,,
|
||||
147,Dratini,,
|
||||
148,Dragonair,,
|
||||
149,Dragonite,,
|
||||
150,Mewtwo,,
|
||||
151,Mew,,
|
||||
|
@@ -0,0 +1,252 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Chikorita,,
|
||||
2,Bayleef,,
|
||||
3,Meganium,,
|
||||
4,Cyndaquil,,
|
||||
5,Quilava,,
|
||||
6,Typhlosion,,
|
||||
7,Totodile,,
|
||||
8,Croconaw,,
|
||||
9,Feraligatr,,
|
||||
10,Pidgey,,
|
||||
11,Pidgeotto,,
|
||||
12,Pidgeot,,
|
||||
13,Spearow,,
|
||||
14,Fearow,,
|
||||
15,Hoothoot,,
|
||||
16,Noctowl,,
|
||||
17,Rattata,,
|
||||
18,Raticate,,
|
||||
19,Sentret,,
|
||||
20,Furret,,
|
||||
21,Pichu,,
|
||||
22,Pikachu,,
|
||||
23,Raichu,,
|
||||
24,Caterpie,,
|
||||
25,Metapod,,
|
||||
26,Butterfree,,
|
||||
27,Weedle,,
|
||||
28,Kakuna,,
|
||||
29,Beedrill,,
|
||||
30,Ledyba,,
|
||||
31,Ledian,,
|
||||
32,Spinarak,,
|
||||
33,Ariados,,
|
||||
34,Geodude,,
|
||||
35,Graveler,,
|
||||
36,Golem,,
|
||||
37,Zubat,,
|
||||
38,Golbat,,
|
||||
39,Crobat,,
|
||||
40,Cleffa,,
|
||||
41,Clefairy,,
|
||||
42,Clefable,,
|
||||
43,Igglybuff,,
|
||||
44,Jigglypuff,,
|
||||
45,Wigglytuff,,
|
||||
46,Togepi,,
|
||||
47,Togetic,,
|
||||
48,Sandshrew,,
|
||||
49,Sandslash,,
|
||||
50,Ekans,,
|
||||
51,Arbok,,
|
||||
52,Dunsparce,,
|
||||
53,Mareep,,
|
||||
54,Flaaffy,,
|
||||
55,Ampharos,,
|
||||
56,Wooper,,
|
||||
57,Quagsire,,
|
||||
58,Gastly,,
|
||||
59,Haunter,,
|
||||
60,Gengar,,
|
||||
61,Unown,,
|
||||
62,Onix,,
|
||||
63,Steelix,,
|
||||
64,Bellsprout,,
|
||||
65,Weepinbell,,
|
||||
66,Victreebel,,
|
||||
67,Hoppip,,
|
||||
68,Skiploom,,
|
||||
69,Jumpluff,,
|
||||
70,Paras,,
|
||||
71,Parasect,,
|
||||
72,Poliwag,,
|
||||
73,Poliwhirl,,
|
||||
74,Poliwrath,,
|
||||
75,Politoed,,
|
||||
76,Magikarp,,
|
||||
77,Gyarados,,
|
||||
78,Goldeen,,
|
||||
79,Seaking,,
|
||||
80,Slowpoke,,
|
||||
81,Slowbro,,
|
||||
82,Slowking,,
|
||||
83,Oddish,,
|
||||
84,Gloom,,
|
||||
85,Vileplume,,
|
||||
86,Bellossom,,
|
||||
87,Drowzee,,
|
||||
88,Hypno,,
|
||||
89,Abra,,
|
||||
90,Kadabra,,
|
||||
91,Alakazam,,
|
||||
92,Ditto,,
|
||||
93,Pineco,,
|
||||
94,Forretress,,
|
||||
95,Nidoran♀,,
|
||||
96,Nidorina,,
|
||||
97,Nidoqueen,,
|
||||
98,Nidoran♂,,
|
||||
99,Nidorino,,
|
||||
100,Nidoking,,
|
||||
101,Yanma,,
|
||||
102,Sunkern,,
|
||||
103,Sunflora,,
|
||||
104,Exeggcute,,
|
||||
105,Exeggutor,,
|
||||
106,Sudowoodo,,
|
||||
107,Wobbuffet,,
|
||||
108,Venonat,,
|
||||
109,Venomoth,,
|
||||
110,Scyther,,
|
||||
111,Scizor,,
|
||||
112,Pinsir,,
|
||||
113,Heracross,,
|
||||
114,Koffing,,
|
||||
115,Weezing,,
|
||||
116,Grimer,,
|
||||
117,Muk,,
|
||||
118,Magnemite,,
|
||||
119,Magneton,,
|
||||
120,Voltorb,,
|
||||
121,Electrode,,
|
||||
122,Aipom,,
|
||||
123,Snubbull,,
|
||||
124,Granbull,,
|
||||
125,Vulpix,,
|
||||
126,Ninetales,,
|
||||
127,Growlithe,,
|
||||
128,Arcanine,,
|
||||
129,Stantler,,
|
||||
130,Marill,,
|
||||
131,Azumarill,,
|
||||
132,Diglett,,
|
||||
133,Dugtrio,,
|
||||
134,Mankey,,
|
||||
135,Primeape,,
|
||||
136,Meowth,,
|
||||
137,Persian,,
|
||||
138,Psyduck,,
|
||||
139,Golduck,,
|
||||
140,Machop,,
|
||||
141,Machoke,,
|
||||
142,Machamp,,
|
||||
143,Tyrogue,,
|
||||
144,Hitmonlee,,
|
||||
145,Hitmonchan,,
|
||||
146,Hitmontop,,
|
||||
147,Girafarig,,
|
||||
148,Tauros,,
|
||||
149,Miltank,,
|
||||
150,Magby,,
|
||||
151,Magmar,,
|
||||
152,Smoochum,,
|
||||
153,Jynx,,
|
||||
154,Elekid,,
|
||||
155,Electabuzz,,
|
||||
156,Mr. Mime,,
|
||||
157,Smeargle,,
|
||||
158,Farfetch’d,,
|
||||
159,Natu,,
|
||||
160,Xatu,,
|
||||
161,Qwilfish,,
|
||||
162,Tentacool,,
|
||||
163,Tentacruel,,
|
||||
164,Krabby,,
|
||||
165,Kingler,,
|
||||
166,Shuckle,,
|
||||
167,Staryu,,
|
||||
168,Starmie,,
|
||||
169,Shellder,,
|
||||
170,Cloyster,,
|
||||
171,Corsola,,
|
||||
172,Remoraid,,
|
||||
173,Octillery,,
|
||||
174,Chinchou,,
|
||||
175,Lanturn,,
|
||||
176,Seel,,
|
||||
177,Dewgong,,
|
||||
178,Lickitung,,
|
||||
179,Tangela,,
|
||||
180,Eevee,,
|
||||
181,Vaporeon,,
|
||||
182,Jolteon,,
|
||||
183,Flareon,,
|
||||
184,Espeon,,
|
||||
185,Umbreon,,
|
||||
186,Horsea,,
|
||||
187,Seadra,,
|
||||
188,Kingdra,,
|
||||
189,Gligar,,
|
||||
190,Delibird,,
|
||||
191,Swinub,,
|
||||
192,Piloswine,,
|
||||
193,Teddiursa,,
|
||||
194,Ursaring,,
|
||||
195,Phanpy,,
|
||||
196,Donphan,,
|
||||
197,Mantine,,
|
||||
198,Skarmory,,
|
||||
199,Doduo,,
|
||||
200,Dodrio,,
|
||||
201,Ponyta,,
|
||||
202,Rapidash,,
|
||||
203,Cubone,,
|
||||
204,Marowak,,
|
||||
205,Kangaskhan,,
|
||||
206,Rhyhorn,,
|
||||
207,Rhydon,,
|
||||
208,Murkrow,,
|
||||
209,Houndour,,
|
||||
210,Houndoom,,
|
||||
211,Slugma,,
|
||||
212,Magcargo,,
|
||||
213,Sneasel,,
|
||||
214,Misdreavus,,
|
||||
215,Porygon,,
|
||||
216,Porygon2,,
|
||||
217,Chansey,,
|
||||
218,Blissey,,
|
||||
219,Lapras,,
|
||||
220,Omanyte,,
|
||||
221,Omastar,,
|
||||
222,Kabuto,,
|
||||
223,Kabutops,,
|
||||
224,Aerodactyl,,
|
||||
225,Snorlax,,
|
||||
226,Bulbasaur,,
|
||||
227,Ivysaur,,
|
||||
228,Venusaur,,
|
||||
229,Charmander,,
|
||||
230,Charmeleon,,
|
||||
231,Charizard,,
|
||||
232,Squirtle,,
|
||||
233,Wartortle,,
|
||||
234,Blastoise,,
|
||||
235,Articuno,,
|
||||
236,Zapdos,,
|
||||
237,Moltres,,
|
||||
238,Raikou,,
|
||||
239,Entei,,
|
||||
240,Suicune,,
|
||||
241,Dratini,,
|
||||
242,Dragonair,,
|
||||
243,Dragonite,,
|
||||
244,Larvitar,,
|
||||
245,Pupitar,,
|
||||
246,Tyranitar,,
|
||||
247,Lugia,,
|
||||
248,Ho-Oh,,
|
||||
249,Mewtwo,,
|
||||
250,Mew,,
|
||||
251,Celebi,,
|
||||
|
@@ -0,0 +1,257 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Chikorita,,
|
||||
2,Bayleef,,
|
||||
3,Meganium,,
|
||||
4,Cyndaquil,,
|
||||
5,Quilava,,
|
||||
6,Typhlosion,,
|
||||
7,Totodile,,
|
||||
8,Croconaw,,
|
||||
9,Feraligatr,,
|
||||
10,Pidgey,,
|
||||
11,Pidgeotto,,
|
||||
12,Pidgeot,,
|
||||
13,Spearow,,
|
||||
14,Fearow,,
|
||||
15,Hoothoot,,
|
||||
16,Noctowl,,
|
||||
17,Rattata,,
|
||||
18,Raticate,,
|
||||
19,Sentret,,
|
||||
20,Furret,,
|
||||
21,Pichu,,
|
||||
22,Pikachu,,
|
||||
23,Raichu,,
|
||||
24,Caterpie,,
|
||||
25,Metapod,,
|
||||
26,Butterfree,,
|
||||
27,Weedle,,
|
||||
28,Kakuna,,
|
||||
29,Beedrill,,
|
||||
30,Ledyba,,
|
||||
31,Ledian,,
|
||||
32,Spinarak,,
|
||||
33,Ariados,,
|
||||
34,Geodude,,
|
||||
35,Graveler,,
|
||||
36,Golem,,
|
||||
37,Zubat,,
|
||||
38,Golbat,,
|
||||
39,Crobat,,
|
||||
40,Cleffa,,
|
||||
41,Clefairy,,
|
||||
42,Clefable,,
|
||||
43,Igglybuff,,
|
||||
44,Jigglypuff,,
|
||||
45,Wigglytuff,,
|
||||
46,Togepi,,
|
||||
47,Togetic,,
|
||||
48,Sandshrew,,
|
||||
49,Sandslash,,
|
||||
50,Ekans,,
|
||||
51,Arbok,,
|
||||
52,Dunsparce,,
|
||||
53,Mareep,,
|
||||
54,Flaaffy,,
|
||||
55,Ampharos,,
|
||||
56,Wooper,,
|
||||
57,Quagsire,,
|
||||
58,Gastly,,
|
||||
59,Haunter,,
|
||||
60,Gengar,,
|
||||
61,Unown,,
|
||||
62,Onix,,
|
||||
63,Steelix,,
|
||||
64,Bellsprout,,
|
||||
65,Weepinbell,,
|
||||
66,Victreebel,,
|
||||
67,Hoppip,,
|
||||
68,Skiploom,,
|
||||
69,Jumpluff,,
|
||||
70,Paras,,
|
||||
71,Parasect,,
|
||||
72,Poliwag,,
|
||||
73,Poliwhirl,,
|
||||
74,Poliwrath,,
|
||||
75,Politoed,,
|
||||
76,Magikarp,,
|
||||
77,Gyarados,,
|
||||
78,Goldeen,,
|
||||
79,Seaking,,
|
||||
80,Slowpoke,,
|
||||
81,Slowbro,,
|
||||
82,Slowking,,
|
||||
83,Oddish,,
|
||||
84,Gloom,,
|
||||
85,Vileplume,,
|
||||
86,Bellossom,,
|
||||
87,Drowzee,,
|
||||
88,Hypno,,
|
||||
89,Abra,,
|
||||
90,Kadabra,,
|
||||
91,Alakazam,,
|
||||
92,Ditto,,
|
||||
93,Pineco,,
|
||||
94,Forretress,,
|
||||
95,Nidoran♀,,
|
||||
96,Nidorina,,
|
||||
97,Nidoqueen,,
|
||||
98,Nidoran♂,,
|
||||
99,Nidorino,,
|
||||
100,Nidoking,,
|
||||
101,Yanma,,
|
||||
102,Yanmega,,
|
||||
103,Sunkern,,
|
||||
104,Sunflora,,
|
||||
105,Exeggcute,,
|
||||
106,Exeggutor,,
|
||||
107,Sudowoodo,,
|
||||
108,Wobbuffet,,
|
||||
109,Venonat,,
|
||||
110,Venomoth,,
|
||||
111,Scyther,,
|
||||
112,Scizor,,
|
||||
113,Pinsir,,
|
||||
114,Heracross,,
|
||||
115,Koffing,,
|
||||
116,Weezing,,
|
||||
117,Grimer,,
|
||||
118,Muk,,
|
||||
119,Magnemite,,
|
||||
120,Magneton,,
|
||||
121,Voltorb,,
|
||||
122,Electrode,,
|
||||
123,Aipom,,
|
||||
124,Ambipom,,
|
||||
125,Snubbull,,
|
||||
126,Granbull,,
|
||||
127,Vulpix,,
|
||||
128,Ninetales,,
|
||||
129,Growlithe,,
|
||||
130,Arcanine,,
|
||||
131,Stantler,,
|
||||
132,Marill,,
|
||||
133,Azumarill,,
|
||||
134,Diglett,,
|
||||
135,Dugtrio,,
|
||||
136,Mankey,,
|
||||
137,Primeape,,
|
||||
138,Meowth,,
|
||||
139,Persian,,
|
||||
140,Psyduck,,
|
||||
141,Golduck,,
|
||||
142,Machop,,
|
||||
143,Machoke,,
|
||||
144,Machamp,,
|
||||
145,Tyrogue,,
|
||||
146,Hitmonlee,,
|
||||
147,Hitmonchan,,
|
||||
148,Hitmontop,,
|
||||
149,Girafarig,,
|
||||
150,Tauros,,
|
||||
151,Miltank,,
|
||||
152,Magby,,
|
||||
153,Magmar,,
|
||||
154,Smoochum,,
|
||||
155,Jynx,,
|
||||
156,Elekid,,
|
||||
157,Electabuzz,,
|
||||
158,Mr. Mime,,
|
||||
159,Smeargle,,
|
||||
160,Farfetch’d,,
|
||||
161,Natu,,
|
||||
162,Xatu,,
|
||||
163,Qwilfish,,
|
||||
164,Tentacool,,
|
||||
165,Tentacruel,,
|
||||
166,Krabby,,
|
||||
167,Kingler,,
|
||||
168,Shuckle,,
|
||||
169,Staryu,,
|
||||
170,Starmie,,
|
||||
171,Shellder,,
|
||||
172,Cloyster,,
|
||||
173,Corsola,,
|
||||
174,Remoraid,,
|
||||
175,Octillery,,
|
||||
176,Chinchou,,
|
||||
177,Lanturn,,
|
||||
178,Seel,,
|
||||
179,Dewgong,,
|
||||
180,Lickitung,,
|
||||
181,Lickilicky,,
|
||||
182,Tangela,,
|
||||
183,Tangrowth,,
|
||||
184,Eevee,,
|
||||
185,Vaporeon,,
|
||||
186,Jolteon,,
|
||||
187,Flareon,,
|
||||
188,Espeon,,
|
||||
189,Umbreon,,
|
||||
190,Horsea,,
|
||||
191,Seadra,,
|
||||
192,Kingdra,,
|
||||
193,Gligar,,
|
||||
194,Delibird,,
|
||||
195,Swinub,,
|
||||
196,Piloswine,,
|
||||
197,Mamoswine,,
|
||||
198,Teddiursa,,
|
||||
199,Ursaring,,
|
||||
200,Phanpy,,
|
||||
201,Donphan,,
|
||||
202,Mantine,,
|
||||
203,Skarmory,,
|
||||
204,Doduo,,
|
||||
205,Dodrio,,
|
||||
206,Ponyta,,
|
||||
207,Rapidash,,
|
||||
208,Cubone,,
|
||||
209,Marowak,,
|
||||
210,Kangaskhan,,
|
||||
211,Rhyhorn,,
|
||||
212,Rhydon,,
|
||||
213,Murkrow,,
|
||||
214,Houndour,,
|
||||
215,Houndoom,,
|
||||
216,Slugma,,
|
||||
217,Magcargo,,
|
||||
218,Sneasel,,
|
||||
219,Misdreavus,,
|
||||
220,Porygon,,
|
||||
221,Porygon2,,
|
||||
222,Chansey,,
|
||||
223,Blissey,,
|
||||
224,Lapras,,
|
||||
225,Omanyte,,
|
||||
226,Omastar,,
|
||||
227,Kabuto,,
|
||||
228,Kabutops,,
|
||||
229,Aerodactyl,,
|
||||
230,Snorlax,,
|
||||
231,Bulbasaur,,
|
||||
232,Ivysaur,,
|
||||
233,Venusaur,,
|
||||
234,Charmander,,
|
||||
235,Charmeleon,,
|
||||
236,Charizard,,
|
||||
237,Squirtle,,
|
||||
238,Wartortle,,
|
||||
239,Blastoise,,
|
||||
240,Articuno,,
|
||||
241,Zapdos,,
|
||||
242,Moltres,,
|
||||
243,Raikou,,
|
||||
244,Entei,,
|
||||
245,Suicune,,
|
||||
246,Dratini,,
|
||||
247,Dragonair,,
|
||||
248,Dragonite,,
|
||||
249,Larvitar,,
|
||||
250,Pupitar,,
|
||||
251,Tyranitar,,
|
||||
252,Lugia,,
|
||||
253,Ho-Oh,,
|
||||
254,Mewtwo,,
|
||||
255,Mew,,
|
||||
256,Celebi,,
|
||||
|
@@ -0,0 +1,243 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Rowlet,,
|
||||
2,Dartrix,,
|
||||
3,Decidueye,,
|
||||
4,Cyndaquil,,
|
||||
5,Quilava,,
|
||||
6,Typhlosion,,
|
||||
7,Oshawott,,
|
||||
8,Dewott,,
|
||||
9,Samurott,,
|
||||
10,Bidoof,,
|
||||
11,Bibarel,,
|
||||
12,Starly,,
|
||||
13,Staravia,,
|
||||
14,Staraptor,,
|
||||
15,Shinx,,
|
||||
16,Luxio,,
|
||||
17,Luxray,,
|
||||
18,Wurmple,,
|
||||
19,Silcoon,,
|
||||
20,Beautifly,,
|
||||
21,Cascoon,,
|
||||
22,Dustox,,
|
||||
23,Ponyta,,
|
||||
24,Rapidash,,
|
||||
25,Eevee,,
|
||||
26,Vaporeon,,
|
||||
27,Jolteon,,
|
||||
28,Flareon,,
|
||||
29,Espeon,,
|
||||
30,Umbreon,,
|
||||
31,Leafeon,,
|
||||
32,Glaceon,,
|
||||
33,Sylveon,,
|
||||
34,Zubat,,
|
||||
35,Golbat,,
|
||||
36,Crobat,,
|
||||
37,Drifloon,,
|
||||
38,Drifblim,,
|
||||
39,Kricketot,,
|
||||
40,Kricketune,,
|
||||
41,Buizel,,
|
||||
42,Floatzel,,
|
||||
43,Burmy,,
|
||||
44,Wormadam,,
|
||||
45,Mothim,,
|
||||
46,Geodude,,
|
||||
47,Graveler,,
|
||||
48,Golem,,
|
||||
49,Stantler,,
|
||||
50,Wyrdeer,,
|
||||
51,Munchlax,,
|
||||
52,Snorlax,,
|
||||
53,Paras,,
|
||||
54,Parasect,,
|
||||
55,Pichu,,
|
||||
56,Pikachu,,
|
||||
57,Raichu,,
|
||||
58,Abra,,
|
||||
59,Kadabra,,
|
||||
60,Alakazam,,
|
||||
61,Chimchar,,
|
||||
62,Monferno,,
|
||||
63,Infernape,,
|
||||
64,Buneary,,
|
||||
65,Lopunny,,
|
||||
66,Cherubi,,
|
||||
67,Cherrim,,
|
||||
68,Psyduck,,
|
||||
69,Golduck,,
|
||||
70,Combee,,
|
||||
71,Vespiquen,,
|
||||
72,Scyther,,
|
||||
73,Kleavor,,
|
||||
74,Scizor,,
|
||||
75,Heracross,,
|
||||
76,Mime Jr.,,
|
||||
77,Mr. Mime,,
|
||||
78,Aipom,,
|
||||
79,Ambipom,,
|
||||
80,Magikarp,,
|
||||
81,Gyarados,,
|
||||
82,Shellos,,
|
||||
83,Gastrodon,,
|
||||
84,Qwilfish,,
|
||||
85,Overqwil,,
|
||||
86,Happiny,,
|
||||
87,Chansey,,
|
||||
88,Blissey,,
|
||||
89,Budew,,
|
||||
90,Roselia,,
|
||||
91,Roserade,,
|
||||
92,Carnivine,,
|
||||
93,Petilil,,
|
||||
94,Lilligant,,
|
||||
95,Tangela,,
|
||||
96,Tangrowth,,
|
||||
97,Barboach,,
|
||||
98,Whiscash,,
|
||||
99,Croagunk,,
|
||||
100,Toxicroak,,
|
||||
101,Ralts,,
|
||||
102,Kirlia,,
|
||||
103,Gardevoir,,
|
||||
104,Gallade,,
|
||||
105,Yanma,,
|
||||
106,Yanmega,,
|
||||
107,Hippopotas,,
|
||||
108,Hippowdon,,
|
||||
109,Pachirisu,,
|
||||
110,Stunky,,
|
||||
111,Skuntank,,
|
||||
112,Teddiursa,,
|
||||
113,Ursaring,,
|
||||
114,Ursaluna,,
|
||||
115,Goomy,,
|
||||
116,Sliggoo,,
|
||||
117,Goodra,,
|
||||
118,Onix,,
|
||||
119,Steelix,,
|
||||
120,Rhyhorn,,
|
||||
121,Rhydon,,
|
||||
122,Rhyperior,,
|
||||
123,Bonsly,,
|
||||
124,Sudowoodo,,
|
||||
125,Lickitung,,
|
||||
126,Lickilicky,,
|
||||
127,Togepi,,
|
||||
128,Togetic,,
|
||||
129,Togekiss,,
|
||||
130,Turtwig,,
|
||||
131,Grotle,,
|
||||
132,Torterra,,
|
||||
133,Porygon,,
|
||||
134,Porygon2,,
|
||||
135,Porygon-Z,,
|
||||
136,Gastly,,
|
||||
137,Haunter,,
|
||||
138,Gengar,,
|
||||
139,Spiritomb,,
|
||||
140,Murkrow,,
|
||||
141,Honchkrow,,
|
||||
142,Unown,,
|
||||
143,Spheal,,
|
||||
144,Sealeo,,
|
||||
145,Walrein,,
|
||||
146,Remoraid,,
|
||||
147,Octillery,,
|
||||
148,Skorupi,,
|
||||
149,Drapion,,
|
||||
150,Growlithe,,
|
||||
151,Arcanine,,
|
||||
152,Glameow,,
|
||||
153,Purugly,,
|
||||
154,Machop,,
|
||||
155,Machoke,,
|
||||
156,Machamp,,
|
||||
157,Chatot,,
|
||||
158,Duskull,,
|
||||
159,Dusclops,,
|
||||
160,Dusknoir,,
|
||||
161,Piplup,,
|
||||
162,Prinplup,,
|
||||
163,Empoleon,,
|
||||
164,Mantyke,,
|
||||
165,Mantine,,
|
||||
166,Basculin,,
|
||||
167,Basculegion,,
|
||||
168,Vulpix,,
|
||||
169,Ninetales,,
|
||||
170,Tentacool,,
|
||||
171,Tentacruel,,
|
||||
172,Finneon,,
|
||||
173,Lumineon,,
|
||||
174,Magby,,
|
||||
175,Magmar,,
|
||||
176,Magmortar,,
|
||||
177,Magnemite,,
|
||||
178,Magneton,,
|
||||
179,Magnezone,,
|
||||
180,Bronzor,,
|
||||
181,Bronzong,,
|
||||
182,Elekid,,
|
||||
183,Electabuzz,,
|
||||
184,Electivire,,
|
||||
185,Gligar,,
|
||||
186,Gliscor,,
|
||||
187,Gible,,
|
||||
188,Gabite,,
|
||||
189,Garchomp,,
|
||||
190,Nosepass,,
|
||||
191,Probopass,,
|
||||
192,Voltorb,,
|
||||
193,Electrode,,
|
||||
194,Rotom,,
|
||||
195,Chingling,,
|
||||
196,Chimecho,,
|
||||
197,Misdreavus,,
|
||||
198,Mismagius,,
|
||||
199,Cleffa,,
|
||||
200,Clefairy,,
|
||||
201,Clefable,,
|
||||
202,Sneasel,,
|
||||
203,Sneasler,,
|
||||
204,Weavile,,
|
||||
205,Snorunt,,
|
||||
206,Glalie,,
|
||||
207,Froslass,,
|
||||
208,Cranidos,,
|
||||
209,Rampardos,,
|
||||
210,Shieldon,,
|
||||
211,Bastiodon,,
|
||||
212,Swinub,,
|
||||
213,Piloswine,,
|
||||
214,Mamoswine,,
|
||||
215,Bergmite,,
|
||||
216,Avalugg,,
|
||||
217,Snover,,
|
||||
218,Abomasnow,,
|
||||
219,Zorua,,
|
||||
220,Zoroark,,
|
||||
221,Rufflet,,
|
||||
222,Braviary,,
|
||||
223,Riolu,,
|
||||
224,Lucario,,
|
||||
225,Uxie,,
|
||||
226,Mesprit,,
|
||||
227,Azelf,,
|
||||
228,Heatran,,
|
||||
229,Regigigas,,
|
||||
230,Cresselia,,
|
||||
231,Tornadus,,
|
||||
232,Thundurus,,
|
||||
233,Landorus,,
|
||||
234,Enamorus,,
|
||||
235,Dialga,,
|
||||
236,Palkia,,
|
||||
237,Giratina,,
|
||||
238,Arceus,,
|
||||
239,Phione,,
|
||||
240,Manaphy,,
|
||||
241,Shaymin,,
|
||||
242,Darkrai,,
|
||||
|
@@ -0,0 +1,133 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Mankey,,
|
||||
2,Primeape,,
|
||||
3,Annihilape,,
|
||||
4,Meowth,,
|
||||
5,Persian,,
|
||||
6,Perrserker,,
|
||||
7,Farfetch’d,,
|
||||
8,Sirfetch’d,,
|
||||
9,Cubone,,
|
||||
10,Marowak,,
|
||||
11,Porygon,,
|
||||
12,Porygon2,,
|
||||
13,Porygon-Z,,
|
||||
14,Capsakid,,
|
||||
15,Scovillain,,
|
||||
16,Tinkatink,,
|
||||
17,Tinkatuff,,
|
||||
18,Tinkaton,,
|
||||
19,Cyclizar,,
|
||||
20,Glimmet,,
|
||||
21,Glimmora,,
|
||||
22,Rotom,,
|
||||
23,Greavard,,
|
||||
24,Houndstone,,
|
||||
25,Sandygast,,
|
||||
26,Palossand,,
|
||||
27,Kecleon,,
|
||||
28,Flamigo,,
|
||||
29,Cryogonal,,
|
||||
30,Dondozo,,
|
||||
31,Tatsugiri,,
|
||||
32,Frigibax,,
|
||||
33,Arctibax,,
|
||||
34,Baxcalibur,,
|
||||
35,Gimmighoul,,
|
||||
36,Gholdengo,,
|
||||
37,Qwilfish,,
|
||||
38,Overqwil,,
|
||||
39,Treecko,,
|
||||
40,Grovyle,,
|
||||
41,Sceptile,,
|
||||
42,Torchic,,
|
||||
43,Combusken,,
|
||||
44,Blaziken,,
|
||||
45,Mudkip,,
|
||||
46,Marshtomp,,
|
||||
47,Swampert,,
|
||||
48,Feebas,,
|
||||
49,Milotic,,
|
||||
50,Chingling,,
|
||||
51,Chimecho,,
|
||||
52,Indeedee,,
|
||||
53,Purrloin,,
|
||||
54,Liepard,,
|
||||
55,Munna,,
|
||||
56,Musharna,,
|
||||
57,Throh,,
|
||||
58,Sawk,,
|
||||
59,Yamask,,
|
||||
60,Cofagrigus,,
|
||||
61,Runerigus,,
|
||||
62,Wimpod,,
|
||||
63,Golisopod,,
|
||||
64,Nickit,,
|
||||
65,Thievul,,
|
||||
66,Clobbopus,,
|
||||
67,Grapploct,,
|
||||
68,Mimikyu,,
|
||||
69,Kleavor,,
|
||||
70,Morpeko,,
|
||||
71,Golett,,
|
||||
72,Golurk,,
|
||||
73,Rookidee,,
|
||||
74,Corvisquire,,
|
||||
75,Corviknight,,
|
||||
76,Igglybuff,,
|
||||
77,Jigglypuff,,
|
||||
78,Wigglytuff,,
|
||||
79,Fidough,,
|
||||
80,Dachsbun,,
|
||||
81,Starly,,
|
||||
82,Staravia,,
|
||||
83,Staraptor,,
|
||||
84,Spoink,,
|
||||
85,Grumpig,,
|
||||
86,Squawkabilly,,
|
||||
87,Crabrawler,,
|
||||
88,Crabominable,,
|
||||
89,Nacli,,
|
||||
90,Naclstack,,
|
||||
91,Garganacl,,
|
||||
92,Gulpin,,
|
||||
93,Swalot,,
|
||||
94,Zubat,,
|
||||
95,Golbat,,
|
||||
96,Crobat,,
|
||||
97,Charcadet,,
|
||||
98,Armarouge,,
|
||||
99,Ceruledge,,
|
||||
100,Maschiff,,
|
||||
101,Mabosstiff,,
|
||||
102,Toxel,,
|
||||
103,Toxtricity,,
|
||||
104,Shroodle,,
|
||||
105,Grafaiai,,
|
||||
106,Zangoose,,
|
||||
107,Seviper,,
|
||||
108,Mime Jr.,,
|
||||
109,Mr. Mime,,
|
||||
110,Mr. Rime,,
|
||||
111,Foongus,,
|
||||
112,Amoonguss,,
|
||||
113,Heatran,,
|
||||
114,Volcanion,,
|
||||
115,Cobalion,,
|
||||
116,Terrakion,,
|
||||
117,Virizion,,
|
||||
118,Keldeo,,
|
||||
119,Meloetta,,
|
||||
120,Genesect,,
|
||||
121,Hoopa,,
|
||||
122,Marshadow,,
|
||||
123,Meltan,,
|
||||
124,Melmetal,,
|
||||
125,Darkrai,,
|
||||
126,Latias,,
|
||||
127,Latios,,
|
||||
128,Kyogre,,
|
||||
129,Groudon,,
|
||||
130,Rayquaza,,
|
||||
131,Magearna,,
|
||||
132,Zeraora,,
|
||||
|
@@ -0,0 +1,233 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Chikorita,,
|
||||
2,Bayleef,,
|
||||
3,Meganium,,
|
||||
4,Tepig,,
|
||||
5,Pignite,,
|
||||
6,Emboar,,
|
||||
7,Totodile,,
|
||||
8,Croconaw,,
|
||||
9,Feraligatr,,
|
||||
10,Fletchling,,
|
||||
11,Fletchinder,,
|
||||
12,Talonflame,,
|
||||
13,Bunnelby,,
|
||||
14,Diggersby,,
|
||||
15,Scatterbug,,
|
||||
16,Spewpa,,
|
||||
17,Vivillon,,
|
||||
18,Weedle,,
|
||||
19,Kakuna,,
|
||||
20,Beedrill,,
|
||||
21,Pidgey,,
|
||||
22,Pidgeotto,,
|
||||
23,Pidgeot,,
|
||||
24,Mareep,,
|
||||
25,Flaaffy,,
|
||||
26,Ampharos,,
|
||||
27,Patrat,,
|
||||
28,Watchog,,
|
||||
29,Budew,,
|
||||
30,Roselia,,
|
||||
31,Roserade,,
|
||||
32,Magikarp,,
|
||||
33,Gyarados,,
|
||||
34,Binacle,,
|
||||
35,Barbaracle,,
|
||||
36,Staryu,,
|
||||
37,Starmie,,
|
||||
38,Flabébé,,
|
||||
39,Floette,,
|
||||
40,Florges,,
|
||||
41,Skiddo,,
|
||||
42,Gogoat,,
|
||||
43,Espurr,,
|
||||
44,Meowstic,,
|
||||
45,Litleo,,
|
||||
46,Pyroar,,
|
||||
47,Pancham,,
|
||||
48,Pangoro,,
|
||||
49,Trubbish,,
|
||||
50,Garbodor,,
|
||||
51,Dedenne,,
|
||||
52,Pichu,,
|
||||
53,Pikachu,,
|
||||
54,Raichu,,
|
||||
55,Cleffa,,
|
||||
56,Clefairy,,
|
||||
57,Clefable,,
|
||||
58,Spinarak,,
|
||||
59,Ariados,,
|
||||
60,Ekans,,
|
||||
61,Arbok,,
|
||||
62,Abra,,
|
||||
63,Kadabra,,
|
||||
64,Alakazam,,
|
||||
65,Gastly,,
|
||||
66,Haunter,,
|
||||
67,Gengar,,
|
||||
68,Venipede,,
|
||||
69,Whirlipede,,
|
||||
70,Scolipede,,
|
||||
71,Honedge,,
|
||||
72,Doublade,,
|
||||
73,Aegislash,,
|
||||
74,Bellsprout,,
|
||||
75,Weepinbell,,
|
||||
76,Victreebel,,
|
||||
77,Pansage,,
|
||||
78,Simisage,,
|
||||
79,Pansear,,
|
||||
80,Simisear,,
|
||||
81,Panpour,,
|
||||
82,Simipour,,
|
||||
83,Meditite,,
|
||||
84,Medicham,,
|
||||
85,Electrike,,
|
||||
86,Manectric,,
|
||||
87,Ralts,,
|
||||
88,Kirlia,,
|
||||
89,Gardevoir,,
|
||||
90,Gallade,,
|
||||
91,Houndour,,
|
||||
92,Houndoom,,
|
||||
93,Swablu,,
|
||||
94,Altaria,,
|
||||
95,Audino,,
|
||||
96,Spritzee,,
|
||||
97,Aromatisse,,
|
||||
98,Swirlix,,
|
||||
99,Slurpuff,,
|
||||
100,Eevee,,
|
||||
101,Vaporeon,,
|
||||
102,Jolteon,,
|
||||
103,Flareon,,
|
||||
104,Espeon,,
|
||||
105,Umbreon,,
|
||||
106,Leafeon,,
|
||||
107,Glaceon,,
|
||||
108,Sylveon,,
|
||||
109,Buneary,,
|
||||
110,Lopunny,,
|
||||
111,Shuppet,,
|
||||
112,Banette,,
|
||||
113,Vanillite,,
|
||||
114,Vanillish,,
|
||||
115,Vanilluxe,,
|
||||
116,Numel,,
|
||||
117,Camerupt,,
|
||||
118,Hippopotas,,
|
||||
119,Hippowdon,,
|
||||
120,Drilbur,,
|
||||
121,Excadrill,,
|
||||
122,Sandile,,
|
||||
123,Krokorok,,
|
||||
124,Krookodile,,
|
||||
125,Machop,,
|
||||
126,Machoke,,
|
||||
127,Machamp,,
|
||||
128,Gible,,
|
||||
129,Gabite,,
|
||||
130,Garchomp,,
|
||||
131,Carbink,,
|
||||
132,Sableye,,
|
||||
133,Mawile,,
|
||||
134,Absol,,
|
||||
135,Riolu,,
|
||||
136,Lucario,,
|
||||
137,Slowpoke,,
|
||||
138,Slowbro,,
|
||||
139,Slowking,,
|
||||
140,Carvanha,,
|
||||
141,Sharpedo,,
|
||||
142,Tynamo,,
|
||||
143,Eelektrik,,
|
||||
144,Eelektross,,
|
||||
145,Dratini,,
|
||||
146,Dragonair,,
|
||||
147,Dragonite,,
|
||||
148,Bulbasaur,,
|
||||
149,Ivysaur,,
|
||||
150,Venusaur,,
|
||||
151,Charmander,,
|
||||
152,Charmeleon,,
|
||||
153,Charizard,,
|
||||
154,Squirtle,,
|
||||
155,Wartortle,,
|
||||
156,Blastoise,,
|
||||
157,Stunfisk,,
|
||||
158,Furfrou,,
|
||||
159,Inkay,,
|
||||
160,Malamar,,
|
||||
161,Skrelp,,
|
||||
162,Dragalge,,
|
||||
163,Clauncher,,
|
||||
164,Clawitzer,,
|
||||
165,Goomy,,
|
||||
166,Sliggoo,,
|
||||
167,Goodra,,
|
||||
168,Delibird,,
|
||||
169,Snorunt,,
|
||||
170,Glalie,,
|
||||
171,Froslass,,
|
||||
172,Snover,,
|
||||
173,Abomasnow,,
|
||||
174,Bergmite,,
|
||||
175,Avalugg,,
|
||||
176,Scyther,,
|
||||
177,Scizor,,
|
||||
178,Pinsir,,
|
||||
179,Heracross,,
|
||||
180,Emolga,,
|
||||
181,Hawlucha,,
|
||||
182,Phantump,,
|
||||
183,Trevenant,,
|
||||
184,Scraggy,,
|
||||
185,Scrafty,,
|
||||
186,Noibat,,
|
||||
187,Noivern,,
|
||||
188,Klefki,,
|
||||
189,Litwick,,
|
||||
190,Lampent,,
|
||||
191,Chandelure,,
|
||||
192,Aerodactyl,,
|
||||
193,Tyrunt,,
|
||||
194,Tyrantrum,,
|
||||
195,Amaura,,
|
||||
196,Aurorus,,
|
||||
197,Onix,,
|
||||
198,Steelix,,
|
||||
199,Aron,,
|
||||
200,Lairon,,
|
||||
201,Aggron,,
|
||||
202,Helioptile,,
|
||||
203,Heliolisk,,
|
||||
204,Pumpkaboo,,
|
||||
205,Gourgeist,,
|
||||
206,Larvitar,,
|
||||
207,Pupitar,,
|
||||
208,Tyranitar,,
|
||||
209,Froakie,,
|
||||
210,Frogadier,,
|
||||
211,Greninja,,
|
||||
212,Falinks,,
|
||||
213,Chespin,,
|
||||
214,Quilladin,,
|
||||
215,Chesnaught,,
|
||||
216,Skarmory,,
|
||||
217,Fennekin,,
|
||||
218,Braixen,,
|
||||
219,Delphox,,
|
||||
220,Bagon,,
|
||||
221,Shelgon,,
|
||||
222,Salamence,,
|
||||
223,Kangaskhan,,
|
||||
224,Drampa,,
|
||||
225,Beldum,,
|
||||
226,Metang,,
|
||||
227,Metagross,,
|
||||
228,Xerneas,,
|
||||
229,Yveltal,,
|
||||
230,Zygarde,,
|
||||
231,Diancie,,
|
||||
232,Mewtwo,,
|
||||
|
@@ -0,0 +1,154 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Bulbasaur,,
|
||||
2,Ivysaur,,
|
||||
3,Venusaur,,
|
||||
4,Charmander,,
|
||||
5,Charmeleon,,
|
||||
6,Charizard,,
|
||||
7,Squirtle,,
|
||||
8,Wartortle,,
|
||||
9,Blastoise,,
|
||||
10,Caterpie,,
|
||||
11,Metapod,,
|
||||
12,Butterfree,,
|
||||
13,Weedle,,
|
||||
14,Kakuna,,
|
||||
15,Beedrill,,
|
||||
16,Pidgey,,
|
||||
17,Pidgeotto,,
|
||||
18,Pidgeot,,
|
||||
19,Rattata,,
|
||||
20,Raticate,,
|
||||
21,Spearow,,
|
||||
22,Fearow,,
|
||||
23,Ekans,,
|
||||
24,Arbok,,
|
||||
25,Pikachu,,
|
||||
26,Raichu,,
|
||||
27,Sandshrew,,
|
||||
28,Sandslash,,
|
||||
29,Nidoran♀,,
|
||||
30,Nidorina,,
|
||||
31,Nidoqueen,,
|
||||
32,Nidoran♂,,
|
||||
33,Nidorino,,
|
||||
34,Nidoking,,
|
||||
35,Clefairy,,
|
||||
36,Clefable,,
|
||||
37,Vulpix,,
|
||||
38,Ninetales,,
|
||||
39,Jigglypuff,,
|
||||
40,Wigglytuff,,
|
||||
41,Zubat,,
|
||||
42,Golbat,,
|
||||
43,Oddish,,
|
||||
44,Gloom,,
|
||||
45,Vileplume,,
|
||||
46,Paras,,
|
||||
47,Parasect,,
|
||||
48,Venonat,,
|
||||
49,Venomoth,,
|
||||
50,Diglett,,
|
||||
51,Dugtrio,,
|
||||
52,Meowth,,
|
||||
53,Persian,,
|
||||
54,Psyduck,,
|
||||
55,Golduck,,
|
||||
56,Mankey,,
|
||||
57,Primeape,,
|
||||
58,Growlithe,,
|
||||
59,Arcanine,,
|
||||
60,Poliwag,,
|
||||
61,Poliwhirl,,
|
||||
62,Poliwrath,,
|
||||
63,Abra,,
|
||||
64,Kadabra,,
|
||||
65,Alakazam,,
|
||||
66,Machop,,
|
||||
67,Machoke,,
|
||||
68,Machamp,,
|
||||
69,Bellsprout,,
|
||||
70,Weepinbell,,
|
||||
71,Victreebel,,
|
||||
72,Tentacool,,
|
||||
73,Tentacruel,,
|
||||
74,Geodude,,
|
||||
75,Graveler,,
|
||||
76,Golem,,
|
||||
77,Ponyta,,
|
||||
78,Rapidash,,
|
||||
79,Slowpoke,,
|
||||
80,Slowbro,,
|
||||
81,Magnemite,,
|
||||
82,Magneton,,
|
||||
83,Farfetch’d,,
|
||||
84,Doduo,,
|
||||
85,Dodrio,,
|
||||
86,Seel,,
|
||||
87,Dewgong,,
|
||||
88,Grimer,,
|
||||
89,Muk,,
|
||||
90,Shellder,,
|
||||
91,Cloyster,,
|
||||
92,Gastly,,
|
||||
93,Haunter,,
|
||||
94,Gengar,,
|
||||
95,Onix,,
|
||||
96,Drowzee,,
|
||||
97,Hypno,,
|
||||
98,Krabby,,
|
||||
99,Kingler,,
|
||||
100,Voltorb,,
|
||||
101,Electrode,,
|
||||
102,Exeggcute,,
|
||||
103,Exeggutor,,
|
||||
104,Cubone,,
|
||||
105,Marowak,,
|
||||
106,Hitmonlee,,
|
||||
107,Hitmonchan,,
|
||||
108,Lickitung,,
|
||||
109,Koffing,,
|
||||
110,Weezing,,
|
||||
111,Rhyhorn,,
|
||||
112,Rhydon,,
|
||||
113,Chansey,,
|
||||
114,Tangela,,
|
||||
115,Kangaskhan,,
|
||||
116,Horsea,,
|
||||
117,Seadra,,
|
||||
118,Goldeen,,
|
||||
119,Seaking,,
|
||||
120,Staryu,,
|
||||
121,Starmie,,
|
||||
122,Mr. Mime,,
|
||||
123,Scyther,,
|
||||
124,Jynx,,
|
||||
125,Electabuzz,,
|
||||
126,Magmar,,
|
||||
127,Pinsir,,
|
||||
128,Tauros,,
|
||||
129,Magikarp,,
|
||||
130,Gyarados,,
|
||||
131,Lapras,,
|
||||
132,Ditto,,
|
||||
133,Eevee,,
|
||||
134,Vaporeon,,
|
||||
135,Jolteon,,
|
||||
136,Flareon,,
|
||||
137,Porygon,,
|
||||
138,Omanyte,,
|
||||
139,Omastar,,
|
||||
140,Kabuto,,
|
||||
141,Kabutops,,
|
||||
142,Aerodactyl,,
|
||||
143,Snorlax,,
|
||||
144,Articuno,,
|
||||
145,Zapdos,,
|
||||
146,Moltres,,
|
||||
147,Dratini,,
|
||||
148,Dragonair,,
|
||||
149,Dragonite,,
|
||||
150,Mewtwo,,
|
||||
151,Mew,,
|
||||
152,Meltan,,
|
||||
153,Melmetal,,
|
||||
|
@@ -0,0 +1,212 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Treecko,,
|
||||
2,Grovyle,,
|
||||
3,Sceptile,,
|
||||
4,Torchic,,
|
||||
5,Combusken,,
|
||||
6,Blaziken,,
|
||||
7,Mudkip,,
|
||||
8,Marshtomp,,
|
||||
9,Swampert,,
|
||||
10,Poochyena,,
|
||||
11,Mightyena,,
|
||||
12,Zigzagoon,,
|
||||
13,Linoone,,
|
||||
14,Wurmple,,
|
||||
15,Silcoon,,
|
||||
16,Beautifly,,
|
||||
17,Cascoon,,
|
||||
18,Dustox,,
|
||||
19,Lotad,,
|
||||
20,Lombre,,
|
||||
21,Ludicolo,,
|
||||
22,Seedot,,
|
||||
23,Nuzleaf,,
|
||||
24,Shiftry,,
|
||||
25,Taillow,,
|
||||
26,Swellow,,
|
||||
27,Wingull,,
|
||||
28,Pelipper,,
|
||||
29,Ralts,,
|
||||
30,Kirlia,,
|
||||
31,Gardevoir,,
|
||||
32,Gallade,,
|
||||
33,Surskit,,
|
||||
34,Masquerain,,
|
||||
35,Shroomish,,
|
||||
36,Breloom,,
|
||||
37,Slakoth,,
|
||||
38,Vigoroth,,
|
||||
39,Slaking,,
|
||||
40,Abra,,
|
||||
41,Kadabra,,
|
||||
42,Alakazam,,
|
||||
43,Nincada,,
|
||||
44,Ninjask,,
|
||||
45,Shedinja,,
|
||||
46,Whismur,,
|
||||
47,Loudred,,
|
||||
48,Exploud,,
|
||||
49,Makuhita,,
|
||||
50,Hariyama,,
|
||||
51,Goldeen,,
|
||||
52,Seaking,,
|
||||
53,Magikarp,,
|
||||
54,Gyarados,,
|
||||
55,Azurill,,
|
||||
56,Marill,,
|
||||
57,Azumarill,,
|
||||
58,Geodude,,
|
||||
59,Graveler,,
|
||||
60,Golem,,
|
||||
61,Nosepass,,
|
||||
62,Probopass,,
|
||||
63,Skitty,,
|
||||
64,Delcatty,,
|
||||
65,Zubat,,
|
||||
66,Golbat,,
|
||||
67,Crobat,,
|
||||
68,Tentacool,,
|
||||
69,Tentacruel,,
|
||||
70,Sableye,,
|
||||
71,Mawile,,
|
||||
72,Aron,,
|
||||
73,Lairon,,
|
||||
74,Aggron,,
|
||||
75,Machop,,
|
||||
76,Machoke,,
|
||||
77,Machamp,,
|
||||
78,Meditite,,
|
||||
79,Medicham,,
|
||||
80,Electrike,,
|
||||
81,Manectric,,
|
||||
82,Plusle,,
|
||||
83,Minun,,
|
||||
84,Magnemite,,
|
||||
85,Magneton,,
|
||||
86,Magnezone,,
|
||||
87,Voltorb,,
|
||||
88,Electrode,,
|
||||
89,Volbeat,,
|
||||
90,Illumise,,
|
||||
91,Oddish,,
|
||||
92,Gloom,,
|
||||
93,Vileplume,,
|
||||
94,Bellossom,,
|
||||
95,Doduo,,
|
||||
96,Dodrio,,
|
||||
97,Budew,,
|
||||
98,Roselia,,
|
||||
99,Roserade,,
|
||||
100,Gulpin,,
|
||||
101,Swalot,,
|
||||
102,Carvanha,,
|
||||
103,Sharpedo,,
|
||||
104,Wailmer,,
|
||||
105,Wailord,,
|
||||
106,Numel,,
|
||||
107,Camerupt,,
|
||||
108,Slugma,,
|
||||
109,Magcargo,,
|
||||
110,Torkoal,,
|
||||
111,Grimer,,
|
||||
112,Muk,,
|
||||
113,Koffing,,
|
||||
114,Weezing,,
|
||||
115,Spoink,,
|
||||
116,Grumpig,,
|
||||
117,Sandshrew,,
|
||||
118,Sandslash,,
|
||||
119,Spinda,,
|
||||
120,Skarmory,,
|
||||
121,Trapinch,,
|
||||
122,Vibrava,,
|
||||
123,Flygon,,
|
||||
124,Cacnea,,
|
||||
125,Cacturne,,
|
||||
126,Swablu,,
|
||||
127,Altaria,,
|
||||
128,Zangoose,,
|
||||
129,Seviper,,
|
||||
130,Lunatone,,
|
||||
131,Solrock,,
|
||||
132,Barboach,,
|
||||
133,Whiscash,,
|
||||
134,Corphish,,
|
||||
135,Crawdaunt,,
|
||||
136,Baltoy,,
|
||||
137,Claydol,,
|
||||
138,Lileep,,
|
||||
139,Cradily,,
|
||||
140,Anorith,,
|
||||
141,Armaldo,,
|
||||
142,Igglybuff,,
|
||||
143,Jigglypuff,,
|
||||
144,Wigglytuff,,
|
||||
145,Feebas,,
|
||||
146,Milotic,,
|
||||
147,Castform,,
|
||||
148,Staryu,,
|
||||
149,Starmie,,
|
||||
150,Kecleon,,
|
||||
151,Shuppet,,
|
||||
152,Banette,,
|
||||
153,Duskull,,
|
||||
154,Dusclops,,
|
||||
155,Dusknoir,,
|
||||
156,Tropius,,
|
||||
157,Chingling,,
|
||||
158,Chimecho,,
|
||||
159,Absol,,
|
||||
160,Vulpix,,
|
||||
161,Ninetales,,
|
||||
162,Pichu,,
|
||||
163,Pikachu,,
|
||||
164,Raichu,,
|
||||
165,Psyduck,,
|
||||
166,Golduck,,
|
||||
167,Wynaut,,
|
||||
168,Wobbuffet,,
|
||||
169,Natu,,
|
||||
170,Xatu,,
|
||||
171,Girafarig,,
|
||||
172,Phanpy,,
|
||||
173,Donphan,,
|
||||
174,Pinsir,,
|
||||
175,Heracross,,
|
||||
176,Rhyhorn,,
|
||||
177,Rhydon,,
|
||||
178,Rhyperior,,
|
||||
179,Snorunt,,
|
||||
180,Glalie,,
|
||||
181,Froslass,,
|
||||
182,Spheal,,
|
||||
183,Sealeo,,
|
||||
184,Walrein,,
|
||||
185,Clamperl,,
|
||||
186,Huntail,,
|
||||
187,Gorebyss,,
|
||||
188,Relicanth,,
|
||||
189,Corsola,,
|
||||
190,Chinchou,,
|
||||
191,Lanturn,,
|
||||
192,Luvdisc,,
|
||||
193,Horsea,,
|
||||
194,Seadra,,
|
||||
195,Kingdra,,
|
||||
196,Bagon,,
|
||||
197,Shelgon,,
|
||||
198,Salamence,,
|
||||
199,Beldum,,
|
||||
200,Metang,,
|
||||
201,Metagross,,
|
||||
202,Regirock,,
|
||||
203,Regice,,
|
||||
204,Registeel,,
|
||||
205,Latias,,
|
||||
206,Latios,,
|
||||
207,Kyogre,,
|
||||
208,Groudon,,
|
||||
209,Rayquaza,,
|
||||
210,Jirachi,,
|
||||
211,Deoxys,,
|
||||
|
@@ -0,0 +1,211 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Turtwig,,
|
||||
2,Grotle,,
|
||||
3,Torterra,,
|
||||
4,Chimchar,,
|
||||
5,Monferno,,
|
||||
6,Infernape,,
|
||||
7,Piplup,,
|
||||
8,Prinplup,,
|
||||
9,Empoleon,,
|
||||
10,Starly,,
|
||||
11,Staravia,,
|
||||
12,Staraptor,,
|
||||
13,Bidoof,,
|
||||
14,Bibarel,,
|
||||
15,Kricketot,,
|
||||
16,Kricketune,,
|
||||
17,Shinx,,
|
||||
18,Luxio,,
|
||||
19,Luxray,,
|
||||
20,Abra,,
|
||||
21,Kadabra,,
|
||||
22,Alakazam,,
|
||||
23,Magikarp,,
|
||||
24,Gyarados,,
|
||||
25,Budew,,
|
||||
26,Roselia,,
|
||||
27,Roserade,,
|
||||
28,Zubat,,
|
||||
29,Golbat,,
|
||||
30,Crobat,,
|
||||
31,Geodude,,
|
||||
32,Graveler,,
|
||||
33,Golem,,
|
||||
34,Onix,,
|
||||
35,Steelix,,
|
||||
36,Cranidos,,
|
||||
37,Rampardos,,
|
||||
38,Shieldon,,
|
||||
39,Bastiodon,,
|
||||
40,Machop,,
|
||||
41,Machoke,,
|
||||
42,Machamp,,
|
||||
43,Psyduck,,
|
||||
44,Golduck,,
|
||||
45,Burmy,,
|
||||
46,Wormadam,,
|
||||
47,Mothim,,
|
||||
48,Wurmple,,
|
||||
49,Silcoon,,
|
||||
50,Beautifly,,
|
||||
51,Cascoon,,
|
||||
52,Dustox,,
|
||||
53,Combee,,
|
||||
54,Vespiquen,,
|
||||
55,Pachirisu,,
|
||||
56,Buizel,,
|
||||
57,Floatzel,,
|
||||
58,Cherubi,,
|
||||
59,Cherrim,,
|
||||
60,Shellos,,
|
||||
61,Gastrodon,,
|
||||
62,Heracross,,
|
||||
63,Aipom,,
|
||||
64,Ambipom,,
|
||||
65,Drifloon,,
|
||||
66,Drifblim,,
|
||||
67,Buneary,,
|
||||
68,Lopunny,,
|
||||
69,Gastly,,
|
||||
70,Haunter,,
|
||||
71,Gengar,,
|
||||
72,Misdreavus,,
|
||||
73,Mismagius,,
|
||||
74,Murkrow,,
|
||||
75,Honchkrow,,
|
||||
76,Glameow,,
|
||||
77,Purugly,,
|
||||
78,Goldeen,,
|
||||
79,Seaking,,
|
||||
80,Barboach,,
|
||||
81,Whiscash,,
|
||||
82,Chingling,,
|
||||
83,Chimecho,,
|
||||
84,Stunky,,
|
||||
85,Skuntank,,
|
||||
86,Meditite,,
|
||||
87,Medicham,,
|
||||
88,Bronzor,,
|
||||
89,Bronzong,,
|
||||
90,Ponyta,,
|
||||
91,Rapidash,,
|
||||
92,Bonsly,,
|
||||
93,Sudowoodo,,
|
||||
94,Mime Jr.,,
|
||||
95,Mr. Mime,,
|
||||
96,Happiny,,
|
||||
97,Chansey,,
|
||||
98,Blissey,,
|
||||
99,Cleffa,,
|
||||
100,Clefairy,,
|
||||
101,Clefable,,
|
||||
102,Chatot,,
|
||||
103,Pichu,,
|
||||
104,Pikachu,,
|
||||
105,Raichu,,
|
||||
106,Hoothoot,,
|
||||
107,Noctowl,,
|
||||
108,Spiritomb,,
|
||||
109,Gible,,
|
||||
110,Gabite,,
|
||||
111,Garchomp,,
|
||||
112,Munchlax,,
|
||||
113,Snorlax,,
|
||||
114,Unown,,
|
||||
115,Riolu,,
|
||||
116,Lucario,,
|
||||
117,Wooper,,
|
||||
118,Quagsire,,
|
||||
119,Wingull,,
|
||||
120,Pelipper,,
|
||||
121,Girafarig,,
|
||||
122,Hippopotas,,
|
||||
123,Hippowdon,,
|
||||
124,Azurill,,
|
||||
125,Marill,,
|
||||
126,Azumarill,,
|
||||
127,Skorupi,,
|
||||
128,Drapion,,
|
||||
129,Croagunk,,
|
||||
130,Toxicroak,,
|
||||
131,Carnivine,,
|
||||
132,Remoraid,,
|
||||
133,Octillery,,
|
||||
134,Finneon,,
|
||||
135,Lumineon,,
|
||||
136,Tentacool,,
|
||||
137,Tentacruel,,
|
||||
138,Feebas,,
|
||||
139,Milotic,,
|
||||
140,Mantyke,,
|
||||
141,Mantine,,
|
||||
142,Snover,,
|
||||
143,Abomasnow,,
|
||||
144,Sneasel,,
|
||||
145,Weavile,,
|
||||
146,Uxie,,
|
||||
147,Mesprit,,
|
||||
148,Azelf,,
|
||||
149,Dialga,,
|
||||
150,Palkia,,
|
||||
151,Manaphy,,
|
||||
152,Rotom,,
|
||||
153,Gligar,,
|
||||
154,Gliscor,,
|
||||
155,Nosepass,,
|
||||
156,Probopass,,
|
||||
157,Ralts,,
|
||||
158,Kirlia,,
|
||||
159,Gardevoir,,
|
||||
160,Gallade,,
|
||||
161,Lickitung,,
|
||||
162,Lickilicky,,
|
||||
163,Eevee,,
|
||||
164,Vaporeon,,
|
||||
165,Jolteon,,
|
||||
166,Flareon,,
|
||||
167,Espeon,,
|
||||
168,Umbreon,,
|
||||
169,Leafeon,,
|
||||
170,Glaceon,,
|
||||
171,Swablu,,
|
||||
172,Altaria,,
|
||||
173,Togepi,,
|
||||
174,Togetic,,
|
||||
175,Togekiss,,
|
||||
176,Houndour,,
|
||||
177,Houndoom,,
|
||||
178,Magnemite,,
|
||||
179,Magneton,,
|
||||
180,Magnezone,,
|
||||
181,Tangela,,
|
||||
182,Tangrowth,,
|
||||
183,Yanma,,
|
||||
184,Yanmega,,
|
||||
185,Tropius,,
|
||||
186,Rhyhorn,,
|
||||
187,Rhydon,,
|
||||
188,Rhyperior,,
|
||||
189,Duskull,,
|
||||
190,Dusclops,,
|
||||
191,Dusknoir,,
|
||||
192,Porygon,,
|
||||
193,Porygon2,,
|
||||
194,Porygon-Z,,
|
||||
195,Scyther,,
|
||||
196,Scizor,,
|
||||
197,Elekid,,
|
||||
198,Electabuzz,,
|
||||
199,Electivire,,
|
||||
200,Magby,,
|
||||
201,Magmar,,
|
||||
202,Magmortar,,
|
||||
203,Swinub,,
|
||||
204,Piloswine,,
|
||||
205,Mamoswine,,
|
||||
206,Snorunt,,
|
||||
207,Glalie,,
|
||||
208,Froslass,,
|
||||
209,Absol,,
|
||||
210,Giratina,,
|
||||
|
@@ -0,0 +1,152 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Bulbasaur,,
|
||||
2,Ivysaur,,
|
||||
3,Venusaur,,
|
||||
4,Charmander,,
|
||||
5,Charmeleon,,
|
||||
6,Charizard,,
|
||||
7,Squirtle,,
|
||||
8,Wartortle,,
|
||||
9,Blastoise,,
|
||||
10,Caterpie,,
|
||||
11,Metapod,,
|
||||
12,Butterfree,,
|
||||
13,Weedle,,
|
||||
14,Kakuna,,
|
||||
15,Beedrill,,
|
||||
16,Pidgey,,
|
||||
17,Pidgeotto,,
|
||||
18,Pidgeot,,
|
||||
19,Rattata,,
|
||||
20,Raticate,,
|
||||
21,Spearow,,
|
||||
22,Fearow,,
|
||||
23,Ekans,,
|
||||
24,Arbok,,
|
||||
25,Pikachu,,
|
||||
26,Raichu,,
|
||||
27,Sandshrew,,
|
||||
28,Sandslash,,
|
||||
29,Nidoran♀,,
|
||||
30,Nidorina,,
|
||||
31,Nidoqueen,,
|
||||
32,Nidoran♂,,
|
||||
33,Nidorino,,
|
||||
34,Nidoking,,
|
||||
35,Clefairy,,
|
||||
36,Clefable,,
|
||||
37,Vulpix,,
|
||||
38,Ninetales,,
|
||||
39,Jigglypuff,,
|
||||
40,Wigglytuff,,
|
||||
41,Zubat,,
|
||||
42,Golbat,,
|
||||
43,Oddish,,
|
||||
44,Gloom,,
|
||||
45,Vileplume,,
|
||||
46,Paras,,
|
||||
47,Parasect,,
|
||||
48,Venonat,,
|
||||
49,Venomoth,,
|
||||
50,Diglett,,
|
||||
51,Dugtrio,,
|
||||
52,Meowth,,
|
||||
53,Persian,,
|
||||
54,Psyduck,,
|
||||
55,Golduck,,
|
||||
56,Mankey,,
|
||||
57,Primeape,,
|
||||
58,Growlithe,,
|
||||
59,Arcanine,,
|
||||
60,Poliwag,,
|
||||
61,Poliwhirl,,
|
||||
62,Poliwrath,,
|
||||
63,Abra,,
|
||||
64,Kadabra,,
|
||||
65,Alakazam,,
|
||||
66,Machop,,
|
||||
67,Machoke,,
|
||||
68,Machamp,,
|
||||
69,Bellsprout,,
|
||||
70,Weepinbell,,
|
||||
71,Victreebel,,
|
||||
72,Tentacool,,
|
||||
73,Tentacruel,,
|
||||
74,Geodude,,
|
||||
75,Graveler,,
|
||||
76,Golem,,
|
||||
77,Ponyta,,
|
||||
78,Rapidash,,
|
||||
79,Slowpoke,,
|
||||
80,Slowbro,,
|
||||
81,Magnemite,,
|
||||
82,Magneton,,
|
||||
83,Farfetch’d,,
|
||||
84,Doduo,,
|
||||
85,Dodrio,,
|
||||
86,Seel,,
|
||||
87,Dewgong,,
|
||||
88,Grimer,,
|
||||
89,Muk,,
|
||||
90,Shellder,,
|
||||
91,Cloyster,,
|
||||
92,Gastly,,
|
||||
93,Haunter,,
|
||||
94,Gengar,,
|
||||
95,Onix,,
|
||||
96,Drowzee,,
|
||||
97,Hypno,,
|
||||
98,Krabby,,
|
||||
99,Kingler,,
|
||||
100,Voltorb,,
|
||||
101,Electrode,,
|
||||
102,Exeggcute,,
|
||||
103,Exeggutor,,
|
||||
104,Cubone,,
|
||||
105,Marowak,,
|
||||
106,Hitmonlee,,
|
||||
107,Hitmonchan,,
|
||||
108,Lickitung,,
|
||||
109,Koffing,,
|
||||
110,Weezing,,
|
||||
111,Rhyhorn,,
|
||||
112,Rhydon,,
|
||||
113,Chansey,,
|
||||
114,Tangela,,
|
||||
115,Kangaskhan,,
|
||||
116,Horsea,,
|
||||
117,Seadra,,
|
||||
118,Goldeen,,
|
||||
119,Seaking,,
|
||||
120,Staryu,,
|
||||
121,Starmie,,
|
||||
122,Mr. Mime,,
|
||||
123,Scyther,,
|
||||
124,Jynx,,
|
||||
125,Electabuzz,,
|
||||
126,Magmar,,
|
||||
127,Pinsir,,
|
||||
128,Tauros,,
|
||||
129,Magikarp,,
|
||||
130,Gyarados,,
|
||||
131,Lapras,,
|
||||
132,Ditto,,
|
||||
133,Eevee,,
|
||||
134,Vaporeon,,
|
||||
135,Jolteon,,
|
||||
136,Flareon,,
|
||||
137,Porygon,,
|
||||
138,Omanyte,,
|
||||
139,Omastar,,
|
||||
140,Kabuto,,
|
||||
141,Kabutops,,
|
||||
142,Aerodactyl,,
|
||||
143,Snorlax,,
|
||||
144,Articuno,,
|
||||
145,Zapdos,,
|
||||
146,Moltres,,
|
||||
147,Dratini,,
|
||||
148,Dragonair,,
|
||||
149,Dragonite,,
|
||||
150,Mewtwo,,
|
||||
151,Mew,,
|
||||
|
@@ -0,0 +1,203 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Treecko,,
|
||||
2,Grovyle,,
|
||||
3,Sceptile,,
|
||||
4,Torchic,,
|
||||
5,Combusken,,
|
||||
6,Blaziken,,
|
||||
7,Mudkip,,
|
||||
8,Marshtomp,,
|
||||
9,Swampert,,
|
||||
10,Poochyena,,
|
||||
11,Mightyena,,
|
||||
12,Zigzagoon,,
|
||||
13,Linoone,,
|
||||
14,Wurmple,,
|
||||
15,Silcoon,,
|
||||
16,Beautifly,,
|
||||
17,Cascoon,,
|
||||
18,Dustox,,
|
||||
19,Lotad,,
|
||||
20,Lombre,,
|
||||
21,Ludicolo,,
|
||||
22,Seedot,,
|
||||
23,Nuzleaf,,
|
||||
24,Shiftry,,
|
||||
25,Taillow,,
|
||||
26,Swellow,,
|
||||
27,Wingull,,
|
||||
28,Pelipper,,
|
||||
29,Ralts,,
|
||||
30,Kirlia,,
|
||||
31,Gardevoir,,
|
||||
32,Surskit,,
|
||||
33,Masquerain,,
|
||||
34,Shroomish,,
|
||||
35,Breloom,,
|
||||
36,Slakoth,,
|
||||
37,Vigoroth,,
|
||||
38,Slaking,,
|
||||
39,Abra,,
|
||||
40,Kadabra,,
|
||||
41,Alakazam,,
|
||||
42,Nincada,,
|
||||
43,Ninjask,,
|
||||
44,Shedinja,,
|
||||
45,Whismur,,
|
||||
46,Loudred,,
|
||||
47,Exploud,,
|
||||
48,Makuhita,,
|
||||
49,Hariyama,,
|
||||
50,Goldeen,,
|
||||
51,Seaking,,
|
||||
52,Magikarp,,
|
||||
53,Gyarados,,
|
||||
54,Azurill,,
|
||||
55,Marill,,
|
||||
56,Azumarill,,
|
||||
57,Geodude,,
|
||||
58,Graveler,,
|
||||
59,Golem,,
|
||||
60,Nosepass,,
|
||||
61,Skitty,,
|
||||
62,Delcatty,,
|
||||
63,Zubat,,
|
||||
64,Golbat,,
|
||||
65,Crobat,,
|
||||
66,Tentacool,,
|
||||
67,Tentacruel,,
|
||||
68,Sableye,,
|
||||
69,Mawile,,
|
||||
70,Aron,,
|
||||
71,Lairon,,
|
||||
72,Aggron,,
|
||||
73,Machop,,
|
||||
74,Machoke,,
|
||||
75,Machamp,,
|
||||
76,Meditite,,
|
||||
77,Medicham,,
|
||||
78,Electrike,,
|
||||
79,Manectric,,
|
||||
80,Plusle,,
|
||||
81,Minun,,
|
||||
82,Magnemite,,
|
||||
83,Magneton,,
|
||||
84,Voltorb,,
|
||||
85,Electrode,,
|
||||
86,Volbeat,,
|
||||
87,Illumise,,
|
||||
88,Oddish,,
|
||||
89,Gloom,,
|
||||
90,Vileplume,,
|
||||
91,Bellossom,,
|
||||
92,Doduo,,
|
||||
93,Dodrio,,
|
||||
94,Roselia,,
|
||||
95,Gulpin,,
|
||||
96,Swalot,,
|
||||
97,Carvanha,,
|
||||
98,Sharpedo,,
|
||||
99,Wailmer,,
|
||||
100,Wailord,,
|
||||
101,Numel,,
|
||||
102,Camerupt,,
|
||||
103,Slugma,,
|
||||
104,Magcargo,,
|
||||
105,Torkoal,,
|
||||
106,Grimer,,
|
||||
107,Muk,,
|
||||
108,Koffing,,
|
||||
109,Weezing,,
|
||||
110,Spoink,,
|
||||
111,Grumpig,,
|
||||
112,Sandshrew,,
|
||||
113,Sandslash,,
|
||||
114,Spinda,,
|
||||
115,Skarmory,,
|
||||
116,Trapinch,,
|
||||
117,Vibrava,,
|
||||
118,Flygon,,
|
||||
119,Cacnea,,
|
||||
120,Cacturne,,
|
||||
121,Swablu,,
|
||||
122,Altaria,,
|
||||
123,Zangoose,,
|
||||
124,Seviper,,
|
||||
125,Lunatone,,
|
||||
126,Solrock,,
|
||||
127,Barboach,,
|
||||
128,Whiscash,,
|
||||
129,Corphish,,
|
||||
130,Crawdaunt,,
|
||||
131,Baltoy,,
|
||||
132,Claydol,,
|
||||
133,Lileep,,
|
||||
134,Cradily,,
|
||||
135,Anorith,,
|
||||
136,Armaldo,,
|
||||
137,Igglybuff,,
|
||||
138,Jigglypuff,,
|
||||
139,Wigglytuff,,
|
||||
140,Feebas,,
|
||||
141,Milotic,,
|
||||
142,Castform,,
|
||||
143,Staryu,,
|
||||
144,Starmie,,
|
||||
145,Kecleon,,
|
||||
146,Shuppet,,
|
||||
147,Banette,,
|
||||
148,Duskull,,
|
||||
149,Dusclops,,
|
||||
150,Tropius,,
|
||||
151,Chimecho,,
|
||||
152,Absol,,
|
||||
153,Vulpix,,
|
||||
154,Ninetales,,
|
||||
155,Pichu,,
|
||||
156,Pikachu,,
|
||||
157,Raichu,,
|
||||
158,Psyduck,,
|
||||
159,Golduck,,
|
||||
160,Wynaut,,
|
||||
161,Wobbuffet,,
|
||||
162,Natu,,
|
||||
163,Xatu,,
|
||||
164,Girafarig,,
|
||||
165,Phanpy,,
|
||||
166,Donphan,,
|
||||
167,Pinsir,,
|
||||
168,Heracross,,
|
||||
169,Rhyhorn,,
|
||||
170,Rhydon,,
|
||||
171,Snorunt,,
|
||||
172,Glalie,,
|
||||
173,Spheal,,
|
||||
174,Sealeo,,
|
||||
175,Walrein,,
|
||||
176,Clamperl,,
|
||||
177,Huntail,,
|
||||
178,Gorebyss,,
|
||||
179,Relicanth,,
|
||||
180,Corsola,,
|
||||
181,Chinchou,,
|
||||
182,Lanturn,,
|
||||
183,Luvdisc,,
|
||||
184,Horsea,,
|
||||
185,Seadra,,
|
||||
186,Kingdra,,
|
||||
187,Bagon,,
|
||||
188,Shelgon,,
|
||||
189,Salamence,,
|
||||
190,Beldum,,
|
||||
191,Metang,,
|
||||
192,Metagross,,
|
||||
193,Regirock,,
|
||||
194,Regice,,
|
||||
195,Registeel,,
|
||||
196,Latias,,
|
||||
197,Latios,,
|
||||
198,Kyogre,,
|
||||
199,Groudon,,
|
||||
200,Rayquaza,,
|
||||
201,Jirachi,,
|
||||
202,Deoxys,,
|
||||
|
@@ -0,0 +1,244 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Doduo,,
|
||||
2,Dodrio,,
|
||||
3,Exeggcute,,
|
||||
4,Exeggutor,,
|
||||
5,Rhyhorn,,
|
||||
6,Rhydon,,
|
||||
7,Rhyperior,,
|
||||
8,Venonat,,
|
||||
9,Venomoth,,
|
||||
10,Elekid,,
|
||||
11,Electabuzz,,
|
||||
12,Electivire,,
|
||||
13,Magby,,
|
||||
14,Magmar,,
|
||||
15,Magmortar,,
|
||||
16,Happiny,,
|
||||
17,Chansey,,
|
||||
18,Blissey,,
|
||||
19,Scyther,,
|
||||
20,Scizor,,
|
||||
21,Kleavor,,
|
||||
22,Tauros,,
|
||||
23,Blitzle,,
|
||||
24,Zebstrika,,
|
||||
25,Girafarig,,
|
||||
26,Farigiraf,,
|
||||
27,Sandile,,
|
||||
28,Krokorok,,
|
||||
29,Krookodile,,
|
||||
30,Rellor,,
|
||||
31,Rabsca,,
|
||||
32,Rufflet,,
|
||||
33,Braviary,,
|
||||
34,Vullaby,,
|
||||
35,Mandibuzz,,
|
||||
36,Litleo,,
|
||||
37,Pyroar,,
|
||||
38,Deerling,,
|
||||
39,Sawsbuck,,
|
||||
40,Smeargle,,
|
||||
41,Rotom,,
|
||||
42,Milcery,,
|
||||
43,Alcremie,,
|
||||
44,Trapinch,,
|
||||
45,Vibrava,,
|
||||
46,Flygon,,
|
||||
47,Pikipek,,
|
||||
48,Trumbeak,,
|
||||
49,Toucannon,,
|
||||
50,Tentacool,,
|
||||
51,Tentacruel,,
|
||||
52,Horsea,,
|
||||
53,Seadra,,
|
||||
54,Kingdra,,
|
||||
55,Bruxish,,
|
||||
56,Cottonee,,
|
||||
57,Whimsicott,,
|
||||
58,Comfey,,
|
||||
59,Slakoth,,
|
||||
60,Vigoroth,,
|
||||
61,Slaking,,
|
||||
62,Oddish,,
|
||||
63,Gloom,,
|
||||
64,Vileplume,,
|
||||
65,Bellossom,,
|
||||
66,Diglett,,
|
||||
67,Dugtrio,,
|
||||
68,Grimer,,
|
||||
69,Muk,,
|
||||
70,Zangoose,,
|
||||
71,Seviper,,
|
||||
72,Crabrawler,,
|
||||
73,Crabominable,,
|
||||
74,Oricorio,,
|
||||
75,Slowpoke,,
|
||||
76,Slowbro,,
|
||||
77,Slowking,,
|
||||
78,Chinchou,,
|
||||
79,Lanturn,,
|
||||
80,Inkay,,
|
||||
81,Malamar,,
|
||||
82,Luvdisc,,
|
||||
83,Finneon,,
|
||||
84,Lumineon,,
|
||||
85,Alomomola,,
|
||||
86,Torkoal,,
|
||||
87,Fletchling,,
|
||||
88,Fletchinder,,
|
||||
89,Talonflame,,
|
||||
90,Dewpider,,
|
||||
91,Araquanid,,
|
||||
92,Tyrogue,,
|
||||
93,Hitmonlee,,
|
||||
94,Hitmonchan,,
|
||||
95,Hitmontop,,
|
||||
96,Geodude,,
|
||||
97,Graveler,,
|
||||
98,Golem,,
|
||||
99,Drilbur,,
|
||||
100,Excadrill,,
|
||||
101,Gothita,,
|
||||
102,Gothorita,,
|
||||
103,Gothitelle,,
|
||||
104,Espurr,,
|
||||
105,Meowstic,,
|
||||
106,Minior,,
|
||||
107,Cranidos,,
|
||||
108,Rampardos,,
|
||||
109,Shieldon,,
|
||||
110,Bastiodon,,
|
||||
111,Minccino,,
|
||||
112,Cinccino,,
|
||||
113,Skarmory,,
|
||||
114,Swablu,,
|
||||
115,Altaria,,
|
||||
116,Magnemite,,
|
||||
117,Magneton,,
|
||||
118,Magnezone,,
|
||||
119,Plusle,,
|
||||
120,Minun,,
|
||||
121,Scraggy,,
|
||||
122,Scrafty,,
|
||||
123,Golett,,
|
||||
124,Golurk,,
|
||||
125,Numel,,
|
||||
126,Camerupt,,
|
||||
127,Sinistea,,
|
||||
128,Polteageist,,
|
||||
129,Porygon,,
|
||||
130,Porygon2,,
|
||||
131,Porygon-Z,,
|
||||
132,Joltik,,
|
||||
133,Galvantula,,
|
||||
134,Tynamo,,
|
||||
135,Eelektrik,,
|
||||
136,Eelektross,,
|
||||
137,Beldum,,
|
||||
138,Metang,,
|
||||
139,Metagross,,
|
||||
140,Axew,,
|
||||
141,Fraxure,,
|
||||
142,Haxorus,,
|
||||
143,Seel,,
|
||||
144,Dewgong,,
|
||||
145,Lapras,,
|
||||
146,Qwilfish,,
|
||||
147,Overqwil,,
|
||||
148,Solosis,,
|
||||
149,Duosion,,
|
||||
150,Reuniclus,,
|
||||
151,Snubbull,,
|
||||
152,Granbull,,
|
||||
153,Cubchoo,,
|
||||
154,Beartic,,
|
||||
155,Sandshrew,,
|
||||
156,Sandslash,,
|
||||
157,Vulpix,,
|
||||
158,Ninetales,,
|
||||
159,Snover,,
|
||||
160,Abomasnow,,
|
||||
161,Duraludon,,
|
||||
162,Archaludon,,
|
||||
163,Hydrapple,,
|
||||
164,Bulbasaur,,
|
||||
165,Ivysaur,,
|
||||
166,Venusaur,,
|
||||
167,Charmander,,
|
||||
168,Charmeleon,,
|
||||
169,Charizard,,
|
||||
170,Squirtle,,
|
||||
171,Wartortle,,
|
||||
172,Blastoise,,
|
||||
173,Chikorita,,
|
||||
174,Bayleef,,
|
||||
175,Meganium,,
|
||||
176,Cyndaquil,,
|
||||
177,Quilava,,
|
||||
178,Typhlosion,,
|
||||
179,Totodile,,
|
||||
180,Croconaw,,
|
||||
181,Feraligatr,,
|
||||
182,Treecko,,
|
||||
183,Grovyle,,
|
||||
184,Sceptile,,
|
||||
185,Torchic,,
|
||||
186,Combusken,,
|
||||
187,Blaziken,,
|
||||
188,Mudkip,,
|
||||
189,Marshtomp,,
|
||||
190,Swampert,,
|
||||
191,Turtwig,,
|
||||
192,Grotle,,
|
||||
193,Torterra,,
|
||||
194,Chimchar,,
|
||||
195,Monferno,,
|
||||
196,Infernape,,
|
||||
197,Piplup,,
|
||||
198,Prinplup,,
|
||||
199,Empoleon,,
|
||||
200,Snivy,,
|
||||
201,Servine,,
|
||||
202,Serperior,,
|
||||
203,Tepig,,
|
||||
204,Pignite,,
|
||||
205,Emboar,,
|
||||
206,Oshawott,,
|
||||
207,Dewott,,
|
||||
208,Samurott,,
|
||||
209,Chespin,,
|
||||
210,Quilladin,,
|
||||
211,Chesnaught,,
|
||||
212,Fennekin,,
|
||||
213,Braixen,,
|
||||
214,Delphox,,
|
||||
215,Froakie,,
|
||||
216,Frogadier,,
|
||||
217,Greninja,,
|
||||
218,Rowlet,,
|
||||
219,Dartrix,,
|
||||
220,Decidueye,,
|
||||
221,Litten,,
|
||||
222,Torracat,,
|
||||
223,Incineroar,,
|
||||
224,Popplio,,
|
||||
225,Brionne,,
|
||||
226,Primarina,,
|
||||
227,Grookey,,
|
||||
228,Thwackey,,
|
||||
229,Rillaboom,,
|
||||
230,Scorbunny,,
|
||||
231,Raboot,,
|
||||
232,Cinderace,,
|
||||
233,Sobble,,
|
||||
234,Drizzile,,
|
||||
235,Inteleon,,
|
||||
236,Gouging Fire,,
|
||||
237,Raging Bolt,,
|
||||
238,Iron Crown,,
|
||||
239,Iron Boulder,,
|
||||
240,Terapagos,,
|
||||
241,Walking Wake,,
|
||||
242,Iron Leaves,,
|
||||
243,Pecharunt,,
|
||||
|
@@ -0,0 +1,201 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Spinarak,,
|
||||
2,Ariados,,
|
||||
3,Yanma,,
|
||||
4,Yanmega,,
|
||||
5,Wooper,,
|
||||
6,Quagsire,,
|
||||
7,Poochyena,,
|
||||
8,Mightyena,,
|
||||
9,Volbeat,,
|
||||
10,Illumise,,
|
||||
11,Corphish,,
|
||||
12,Crawdaunt,,
|
||||
13,Sewaddle,,
|
||||
14,Swadloon,,
|
||||
15,Leavanny,,
|
||||
16,Cutiefly,,
|
||||
17,Ribombee,,
|
||||
18,Ekans,,
|
||||
19,Arbok,,
|
||||
20,Pichu,,
|
||||
21,Pikachu,,
|
||||
22,Raichu,,
|
||||
23,Bellsprout,,
|
||||
24,Weepinbell,,
|
||||
25,Victreebel,,
|
||||
26,Sentret,,
|
||||
27,Furret,,
|
||||
28,Starly,,
|
||||
29,Staravia,,
|
||||
30,Staraptor,,
|
||||
31,Fomantis,,
|
||||
32,Lurantis,,
|
||||
33,Applin,,
|
||||
34,Flapple,,
|
||||
35,Appletun,,
|
||||
36,Dipplin,,
|
||||
37,Vulpix,,
|
||||
38,Ninetales,,
|
||||
39,Poliwag,,
|
||||
40,Poliwhirl,,
|
||||
41,Poliwrath,,
|
||||
42,Politoed,,
|
||||
43,Magikarp,,
|
||||
44,Gyarados,,
|
||||
45,Hoothoot,,
|
||||
46,Noctowl,,
|
||||
47,Aipom,,
|
||||
48,Ambipom,,
|
||||
49,Heracross,,
|
||||
50,Swinub,,
|
||||
51,Piloswine,,
|
||||
52,Mamoswine,,
|
||||
53,Stantler,,
|
||||
54,Seedot,,
|
||||
55,Nuzleaf,,
|
||||
56,Shiftry,,
|
||||
57,Ralts,,
|
||||
58,Kirlia,,
|
||||
59,Gardevoir,,
|
||||
60,Gallade,,
|
||||
61,Kricketot,,
|
||||
62,Kricketune,,
|
||||
63,Pachirisu,,
|
||||
64,Riolu,,
|
||||
65,Lucario,,
|
||||
66,Petilil,,
|
||||
67,Lilligant,,
|
||||
68,Phantump,,
|
||||
69,Trevenant,,
|
||||
70,Rockruff,,
|
||||
71,Lycanroc,,
|
||||
72,Skwovet,,
|
||||
73,Greedent,,
|
||||
74,Toedscool,,
|
||||
75,Toedscruel,,
|
||||
76,Poltchageist,,
|
||||
77,Sinistcha,,
|
||||
78,Growlithe,,
|
||||
79,Arcanine,,
|
||||
80,Geodude,,
|
||||
81,Graveler,,
|
||||
82,Golem,,
|
||||
83,Bonsly,,
|
||||
84,Sudowoodo,,
|
||||
85,Timburr,,
|
||||
86,Gurdurr,,
|
||||
87,Conkeldurr,,
|
||||
88,Noibat,,
|
||||
89,Noivern,,
|
||||
90,Arrokuda,,
|
||||
91,Barraskewda,,
|
||||
92,Hatenna,,
|
||||
93,Hattrem,,
|
||||
94,Hatterene,,
|
||||
95,Morpeko,,
|
||||
96,Orthworm,,
|
||||
97,Tandemaus,,
|
||||
98,Maushold,,
|
||||
99,Mankey,,
|
||||
100,Primeape,,
|
||||
101,Annihilape,,
|
||||
102,Munchlax,,
|
||||
103,Snorlax,,
|
||||
104,Lotad,,
|
||||
105,Lombre,,
|
||||
106,Ludicolo,,
|
||||
107,Nosepass,,
|
||||
108,Probopass,,
|
||||
109,Shinx,,
|
||||
110,Luxio,,
|
||||
111,Luxray,,
|
||||
112,Grubbin,,
|
||||
113,Charjabug,,
|
||||
114,Vikavolt,,
|
||||
115,Oricorio,,
|
||||
116,Sandshrew,,
|
||||
117,Sandslash,,
|
||||
118,Gastly,,
|
||||
119,Haunter,,
|
||||
120,Gengar,,
|
||||
121,Gligar,,
|
||||
122,Gliscor,,
|
||||
123,Houndour,,
|
||||
124,Houndoom,,
|
||||
125,Spoink,,
|
||||
126,Grumpig,,
|
||||
127,Vullaby,,
|
||||
128,Mandibuzz,,
|
||||
129,Mudbray,,
|
||||
130,Mudsdale,,
|
||||
131,Jangmo-o,,
|
||||
132,Hakamo-o,,
|
||||
133,Kommo-o,,
|
||||
134,Bombirdier,,
|
||||
135,Koffing,,
|
||||
136,Weezing,,
|
||||
137,Mienfoo,,
|
||||
138,Mienshao,,
|
||||
139,Duskull,,
|
||||
140,Dusclops,,
|
||||
141,Dusknoir,,
|
||||
142,Chingling,,
|
||||
143,Chimecho,,
|
||||
144,Slugma,,
|
||||
145,Magcargo,,
|
||||
146,Litwick,,
|
||||
147,Lampent,,
|
||||
148,Chandelure,,
|
||||
149,Surskit,,
|
||||
150,Masquerain,,
|
||||
151,Cleffa,,
|
||||
152,Clefairy,,
|
||||
153,Clefable,,
|
||||
154,Bronzor,,
|
||||
155,Bronzong,,
|
||||
156,Glimmet,,
|
||||
157,Glimmora,,
|
||||
158,Feebas,,
|
||||
159,Milotic,,
|
||||
160,Dunsparce,,
|
||||
161,Dudunsparce,,
|
||||
162,Barboach,,
|
||||
163,Whiscash,,
|
||||
164,Gible,,
|
||||
165,Gabite,,
|
||||
166,Garchomp,,
|
||||
167,Carbink,,
|
||||
168,Salandit,,
|
||||
169,Salazzle,,
|
||||
170,Sneasel,,
|
||||
171,Weavile,,
|
||||
172,Snorunt,,
|
||||
173,Glalie,,
|
||||
174,Froslass,,
|
||||
175,Tynamo,,
|
||||
176,Eelektrik,,
|
||||
177,Eelektross,,
|
||||
178,Goomy,,
|
||||
179,Sliggoo,,
|
||||
180,Goodra,,
|
||||
181,Ducklett,,
|
||||
182,Swanna,,
|
||||
183,Chewtle,,
|
||||
184,Drednaw,,
|
||||
185,Cramorant,,
|
||||
186,Pawniard,,
|
||||
187,Bisharp,,
|
||||
188,Kingambit,,
|
||||
189,Mimikyu,,
|
||||
190,Impidimp,,
|
||||
191,Morgrem,,
|
||||
192,Grimmsnarl,,
|
||||
193,Indeedee,,
|
||||
194,Basculin,,
|
||||
195,Basculegion,,
|
||||
196,Ursaluna,,
|
||||
197,Okidogi,,
|
||||
198,Munkidori,,
|
||||
199,Fezandipiti,,
|
||||
200,Ogerpon,,
|
||||
|
@@ -0,0 +1,401 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Sprigatito,,
|
||||
2,Floragato,,
|
||||
3,Meowscarada,,
|
||||
4,Fuecoco,,
|
||||
5,Crocalor,,
|
||||
6,Skeledirge,,
|
||||
7,Quaxly,,
|
||||
8,Quaxwell,,
|
||||
9,Quaquaval,,
|
||||
10,Lechonk,,
|
||||
11,Oinkologne,,
|
||||
12,Tarountula,,
|
||||
13,Spidops,,
|
||||
14,Nymble,,
|
||||
15,Lokix,,
|
||||
16,Hoppip,,
|
||||
17,Skiploom,,
|
||||
18,Jumpluff,,
|
||||
19,Fletchling,,
|
||||
20,Fletchinder,,
|
||||
21,Talonflame,,
|
||||
22,Pawmi,,
|
||||
23,Pawmo,,
|
||||
24,Pawmot,,
|
||||
25,Houndour,,
|
||||
26,Houndoom,,
|
||||
27,Yungoos,,
|
||||
28,Gumshoos,,
|
||||
29,Skwovet,,
|
||||
30,Greedent,,
|
||||
31,Sunkern,,
|
||||
32,Sunflora,,
|
||||
33,Kricketot,,
|
||||
34,Kricketune,,
|
||||
35,Scatterbug,,
|
||||
36,Spewpa,,
|
||||
37,Vivillon,,
|
||||
38,Combee,,
|
||||
39,Vespiquen,,
|
||||
40,Rookidee,,
|
||||
41,Corvisquire,,
|
||||
42,Corviknight,,
|
||||
43,Happiny,,
|
||||
44,Chansey,,
|
||||
45,Blissey,,
|
||||
46,Azurill,,
|
||||
47,Marill,,
|
||||
48,Azumarill,,
|
||||
49,Surskit,,
|
||||
50,Masquerain,,
|
||||
51,Buizel,,
|
||||
52,Floatzel,,
|
||||
53,Wooper,,
|
||||
54,Clodsire,,
|
||||
55,Psyduck,,
|
||||
56,Golduck,,
|
||||
57,Chewtle,,
|
||||
58,Drednaw,,
|
||||
59,Igglybuff,,
|
||||
60,Jigglypuff,,
|
||||
61,Wigglytuff,,
|
||||
62,Ralts,,
|
||||
63,Kirlia,,
|
||||
64,Gardevoir,,
|
||||
65,Gallade,,
|
||||
66,Drowzee,,
|
||||
67,Hypno,,
|
||||
68,Gastly,,
|
||||
69,Haunter,,
|
||||
70,Gengar,,
|
||||
71,Tandemaus,,
|
||||
72,Maushold,,
|
||||
73,Pichu,,
|
||||
74,Pikachu,,
|
||||
75,Raichu,,
|
||||
76,Fidough,,
|
||||
77,Dachsbun,,
|
||||
78,Slakoth,,
|
||||
79,Vigoroth,,
|
||||
80,Slaking,,
|
||||
81,Bounsweet,,
|
||||
82,Steenee,,
|
||||
83,Tsareena,,
|
||||
84,Smoliv,,
|
||||
85,Dolliv,,
|
||||
86,Arboliva,,
|
||||
87,Bonsly,,
|
||||
88,Sudowoodo,,
|
||||
89,Rockruff,,
|
||||
90,Lycanroc,,
|
||||
91,Rolycoly,,
|
||||
92,Carkol,,
|
||||
93,Coalossal,,
|
||||
94,Shinx,,
|
||||
95,Luxio,,
|
||||
96,Luxray,,
|
||||
97,Starly,,
|
||||
98,Staravia,,
|
||||
99,Staraptor,,
|
||||
100,Oricorio,,
|
||||
101,Mareep,,
|
||||
102,Flaaffy,,
|
||||
103,Ampharos,,
|
||||
104,Petilil,,
|
||||
105,Lilligant,,
|
||||
106,Shroomish,,
|
||||
107,Breloom,,
|
||||
108,Applin,,
|
||||
109,Flapple,,
|
||||
110,Appletun,,
|
||||
111,Spoink,,
|
||||
112,Grumpig,,
|
||||
113,Squawkabilly,,
|
||||
114,Misdreavus,,
|
||||
115,Mismagius,,
|
||||
116,Makuhita,,
|
||||
117,Hariyama,,
|
||||
118,Crabrawler,,
|
||||
119,Crabominable,,
|
||||
120,Salandit,,
|
||||
121,Salazzle,,
|
||||
122,Phanpy,,
|
||||
123,Donphan,,
|
||||
124,Cufant,,
|
||||
125,Copperajah,,
|
||||
126,Gible,,
|
||||
127,Gabite,,
|
||||
128,Garchomp,,
|
||||
129,Nacli,,
|
||||
130,Naclstack,,
|
||||
131,Garganacl,,
|
||||
132,Wingull,,
|
||||
133,Pelipper,,
|
||||
134,Magikarp,,
|
||||
135,Gyarados,,
|
||||
136,Arrokuda,,
|
||||
137,Barraskewda,,
|
||||
138,Basculin,,
|
||||
139,Gulpin,,
|
||||
140,Swalot,,
|
||||
141,Meowth,,
|
||||
142,Persian,,
|
||||
143,Drifloon,,
|
||||
144,Drifblim,,
|
||||
145,Flabébé,,
|
||||
146,Floette,,
|
||||
147,Florges,,
|
||||
148,Diglett,,
|
||||
149,Dugtrio,,
|
||||
150,Torkoal,,
|
||||
151,Numel,,
|
||||
152,Camerupt,,
|
||||
153,Bronzor,,
|
||||
154,Bronzong,,
|
||||
155,Axew,,
|
||||
156,Fraxure,,
|
||||
157,Haxorus,,
|
||||
158,Mankey,,
|
||||
159,Primeape,,
|
||||
160,Annihilape,,
|
||||
161,Meditite,,
|
||||
162,Medicham,,
|
||||
163,Riolu,,
|
||||
164,Lucario,,
|
||||
165,Charcadet,,
|
||||
166,Armarouge,,
|
||||
167,Ceruledge,,
|
||||
168,Barboach,,
|
||||
169,Whiscash,,
|
||||
170,Tadbulb,,
|
||||
171,Bellibolt,,
|
||||
172,Goomy,,
|
||||
173,Sliggoo,,
|
||||
174,Goodra,,
|
||||
175,Croagunk,,
|
||||
176,Toxicroak,,
|
||||
177,Wattrel,,
|
||||
178,Kilowattrel,,
|
||||
179,Eevee,,
|
||||
180,Vaporeon,,
|
||||
181,Jolteon,,
|
||||
182,Flareon,,
|
||||
183,Espeon,,
|
||||
184,Umbreon,,
|
||||
185,Leafeon,,
|
||||
186,Glaceon,,
|
||||
187,Sylveon,,
|
||||
188,Dunsparce,,
|
||||
189,Dudunsparce,,
|
||||
190,Deerling,,
|
||||
191,Sawsbuck,,
|
||||
192,Girafarig,,
|
||||
193,Farigiraf,,
|
||||
194,Grimer,,
|
||||
195,Muk,,
|
||||
196,Maschiff,,
|
||||
197,Mabosstiff,,
|
||||
198,Toxel,,
|
||||
199,Toxtricity,,
|
||||
200,Dedenne,,
|
||||
201,Pachirisu,,
|
||||
202,Shroodle,,
|
||||
203,Grafaiai,,
|
||||
204,Stantler,,
|
||||
205,Foongus,,
|
||||
206,Amoonguss,,
|
||||
207,Voltorb,,
|
||||
208,Electrode,,
|
||||
209,Magnemite,,
|
||||
210,Magneton,,
|
||||
211,Magnezone,,
|
||||
212,Ditto,,
|
||||
213,Growlithe,,
|
||||
214,Arcanine,,
|
||||
215,Teddiursa,,
|
||||
216,Ursaring,,
|
||||
217,Zangoose,,
|
||||
218,Seviper,,
|
||||
219,Swablu,,
|
||||
220,Altaria,,
|
||||
221,Skiddo,,
|
||||
222,Gogoat,,
|
||||
223,Tauros,,
|
||||
224,Litleo,,
|
||||
225,Pyroar,,
|
||||
226,Stunky,,
|
||||
227,Skuntank,,
|
||||
228,Zorua,,
|
||||
229,Zoroark,,
|
||||
230,Sneasel,,
|
||||
231,Weavile,,
|
||||
232,Murkrow,,
|
||||
233,Honchkrow,,
|
||||
234,Gothita,,
|
||||
235,Gothorita,,
|
||||
236,Gothitelle,,
|
||||
237,Sinistea,,
|
||||
238,Polteageist,,
|
||||
239,Mimikyu,,
|
||||
240,Klefki,,
|
||||
241,Indeedee,,
|
||||
242,Bramblin,,
|
||||
243,Brambleghast,,
|
||||
244,Toedscool,,
|
||||
245,Toedscruel,,
|
||||
246,Tropius,,
|
||||
247,Fomantis,,
|
||||
248,Lurantis,,
|
||||
249,Klawf,,
|
||||
250,Capsakid,,
|
||||
251,Scovillain,,
|
||||
252,Cacnea,,
|
||||
253,Cacturne,,
|
||||
254,Rellor,,
|
||||
255,Rabsca,,
|
||||
256,Venonat,,
|
||||
257,Venomoth,,
|
||||
258,Pineco,,
|
||||
259,Forretress,,
|
||||
260,Scyther,,
|
||||
261,Scizor,,
|
||||
262,Heracross,,
|
||||
263,Flittle,,
|
||||
264,Espathra,,
|
||||
265,Hippopotas,,
|
||||
266,Hippowdon,,
|
||||
267,Sandile,,
|
||||
268,Krokorok,,
|
||||
269,Krookodile,,
|
||||
270,Silicobra,,
|
||||
271,Sandaconda,,
|
||||
272,Mudbray,,
|
||||
273,Mudsdale,,
|
||||
274,Larvesta,,
|
||||
275,Volcarona,,
|
||||
276,Bagon,,
|
||||
277,Shelgon,,
|
||||
278,Salamence,,
|
||||
279,Tinkatink,,
|
||||
280,Tinkatuff,,
|
||||
281,Tinkaton,,
|
||||
282,Hatenna,,
|
||||
283,Hattrem,,
|
||||
284,Hatterene,,
|
||||
285,Impidimp,,
|
||||
286,Morgrem,,
|
||||
287,Grimmsnarl,,
|
||||
288,Wiglett,,
|
||||
289,Wugtrio,,
|
||||
290,Bombirdier,,
|
||||
291,Finizen,,
|
||||
292,Palafin,,
|
||||
293,Varoom,,
|
||||
294,Revavroom,,
|
||||
295,Cyclizar,,
|
||||
296,Orthworm,,
|
||||
297,Sableye,,
|
||||
298,Shuppet,,
|
||||
299,Banette,,
|
||||
300,Falinks,,
|
||||
301,Hawlucha,,
|
||||
302,Spiritomb,,
|
||||
303,Noibat,,
|
||||
304,Noivern,,
|
||||
305,Dreepy,,
|
||||
306,Drakloak,,
|
||||
307,Dragapult,,
|
||||
308,Glimmet,,
|
||||
309,Glimmora,,
|
||||
310,Rotom,,
|
||||
311,Greavard,,
|
||||
312,Houndstone,,
|
||||
313,Oranguru,,
|
||||
314,Passimian,,
|
||||
315,Komala,,
|
||||
316,Larvitar,,
|
||||
317,Pupitar,,
|
||||
318,Tyranitar,,
|
||||
319,Stonjourner,,
|
||||
320,Eiscue,,
|
||||
321,Pincurchin,,
|
||||
322,Sandygast,,
|
||||
323,Palossand,,
|
||||
324,Slowpoke,,
|
||||
325,Slowbro,,
|
||||
326,Slowking,,
|
||||
327,Shellos,,
|
||||
328,Gastrodon,,
|
||||
329,Shellder,,
|
||||
330,Cloyster,,
|
||||
331,Qwilfish,,
|
||||
332,Luvdisc,,
|
||||
333,Finneon,,
|
||||
334,Lumineon,,
|
||||
335,Bruxish,,
|
||||
336,Alomomola,,
|
||||
337,Skrelp,,
|
||||
338,Dragalge,,
|
||||
339,Clauncher,,
|
||||
340,Clawitzer,,
|
||||
341,Tynamo,,
|
||||
342,Eelektrik,,
|
||||
343,Eelektross,,
|
||||
344,Mareanie,,
|
||||
345,Toxapex,,
|
||||
346,Flamigo,,
|
||||
347,Dratini,,
|
||||
348,Dragonair,,
|
||||
349,Dragonite,,
|
||||
350,Snom,,
|
||||
351,Frosmoth,,
|
||||
352,Snover,,
|
||||
353,Abomasnow,,
|
||||
354,Delibird,,
|
||||
355,Cubchoo,,
|
||||
356,Beartic,,
|
||||
357,Snorunt,,
|
||||
358,Glalie,,
|
||||
359,Froslass,,
|
||||
360,Cryogonal,,
|
||||
361,Cetoddle,,
|
||||
362,Cetitan,,
|
||||
363,Bergmite,,
|
||||
364,Avalugg,,
|
||||
365,Rufflet,,
|
||||
366,Braviary,,
|
||||
367,Pawniard,,
|
||||
368,Bisharp,,
|
||||
369,Kingambit,,
|
||||
370,Deino,,
|
||||
371,Zweilous,,
|
||||
372,Hydreigon,,
|
||||
373,Veluza,,
|
||||
374,Dondozo,,
|
||||
375,Tatsugiri,,
|
||||
376,Great Tusk,,
|
||||
377,Scream Tail,,
|
||||
378,Brute Bonnet,,
|
||||
379,Flutter Mane,,
|
||||
380,Slither Wing,,
|
||||
381,Sandy Shocks,,
|
||||
382,Iron Treads,,
|
||||
383,Iron Bundle,,
|
||||
384,Iron Hands,,
|
||||
385,Iron Jugulis,,
|
||||
386,Iron Moth,,
|
||||
387,Iron Thorns,,
|
||||
388,Frigibax,,
|
||||
389,Arctibax,,
|
||||
390,Baxcalibur,,
|
||||
391,Gimmighoul,,
|
||||
392,Gholdengo,,
|
||||
393,Wo-Chien,,
|
||||
394,Chien-Pao,,
|
||||
395,Ting-Lu,,
|
||||
396,Chi-Yu,,
|
||||
397,Roaring Moon,,
|
||||
398,Iron Valiant,,
|
||||
399,Koraidon,,
|
||||
400,Miraidon,,
|
||||
|
@@ -0,0 +1,131 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Pikipek,,
|
||||
2,Trumbeak,,
|
||||
3,Toucannon,,
|
||||
4,Yungoos,,
|
||||
5,Gumshoos,,
|
||||
6,Rattata,,
|
||||
7,Raticate,,
|
||||
8,Caterpie,,
|
||||
9,Metapod,,
|
||||
10,Butterfree,,
|
||||
11,Grubbin,,
|
||||
12,Charjabug,,
|
||||
13,Vikavolt,,
|
||||
14,Bonsly,,
|
||||
15,Sudowoodo,,
|
||||
16,Happiny,,
|
||||
17,Chansey,,
|
||||
18,Blissey,,
|
||||
19,Wingull,,
|
||||
20,Pelipper,,
|
||||
21,Crabrawler,,
|
||||
22,Crabominable,,
|
||||
23,Gastly,,
|
||||
24,Haunter,,
|
||||
25,Gengar,,
|
||||
26,Zubat,,
|
||||
27,Golbat,,
|
||||
28,Crobat,,
|
||||
29,Diglett,,
|
||||
30,Dugtrio,,
|
||||
31,Oricorio,,
|
||||
32,Psyduck,,
|
||||
33,Golduck,,
|
||||
34,Magikarp,,
|
||||
35,Gyarados,,
|
||||
36,Barboach,,
|
||||
37,Whiscash,,
|
||||
38,Tentacool,,
|
||||
39,Tentacruel,,
|
||||
40,Finneon,,
|
||||
41,Lumineon,,
|
||||
42,Wishiwashi,,
|
||||
43,Luvdisc,,
|
||||
44,Corsola,,
|
||||
45,Mareanie,,
|
||||
46,Toxapex,,
|
||||
47,Lillipup,,
|
||||
48,Herdier,,
|
||||
49,Stoutland,,
|
||||
50,Eevee,,
|
||||
51,Vaporeon,,
|
||||
52,Jolteon,,
|
||||
53,Flareon,,
|
||||
54,Espeon,,
|
||||
55,Umbreon,,
|
||||
56,Leafeon,,
|
||||
57,Glaceon,,
|
||||
58,Sylveon,,
|
||||
59,Mudbray,,
|
||||
60,Mudsdale,,
|
||||
61,Igglybuff,,
|
||||
62,Jigglypuff,,
|
||||
63,Wigglytuff,,
|
||||
64,Tauros,,
|
||||
65,Miltank,,
|
||||
66,Surskit,,
|
||||
67,Masquerain,,
|
||||
68,Dewpider,,
|
||||
69,Araquanid,,
|
||||
70,Fomantis,,
|
||||
71,Lurantis,,
|
||||
72,Morelull,,
|
||||
73,Shiinotic,,
|
||||
74,Paras,,
|
||||
75,Parasect,,
|
||||
76,Poliwag,,
|
||||
77,Poliwhirl,,
|
||||
78,Poliwrath,,
|
||||
79,Politoed,,
|
||||
80,Goldeen,,
|
||||
81,Seaking,,
|
||||
82,Feebas,,
|
||||
83,Milotic,,
|
||||
84,Alomomola,,
|
||||
85,Fletchling,,
|
||||
86,Fletchinder,,
|
||||
87,Talonflame,,
|
||||
88,Salandit,,
|
||||
89,Salazzle,,
|
||||
90,Cubone,,
|
||||
91,Marowak,,
|
||||
92,Kangaskhan,,
|
||||
93,Magby,,
|
||||
94,Magmar,,
|
||||
95,Magmortar,,
|
||||
96,Stufful,,
|
||||
97,Bewear,,
|
||||
98,Bounsweet,,
|
||||
99,Steenee,,
|
||||
100,Tsareena,,
|
||||
101,Comfey,,
|
||||
102,Pinsir,,
|
||||
103,Oranguru,,
|
||||
104,Passimian,,
|
||||
105,Goomy,,
|
||||
106,Sliggoo,,
|
||||
107,Goodra,,
|
||||
108,Castform,,
|
||||
109,Wimpod,,
|
||||
110,Golisopod,,
|
||||
111,Staryu,,
|
||||
112,Starmie,,
|
||||
113,Sandygast,,
|
||||
114,Palossand,,
|
||||
115,Cranidos,,
|
||||
116,Rampardos,,
|
||||
117,Shieldon,,
|
||||
118,Bastiodon,,
|
||||
119,Archen,,
|
||||
120,Archeops,,
|
||||
121,Tirtouga,,
|
||||
122,Carracosta,,
|
||||
123,Phantump,,
|
||||
124,Trevenant,,
|
||||
125,Nosepass,,
|
||||
126,Probopass,,
|
||||
127,Pyukumuku,,
|
||||
128,Chinchou,,
|
||||
129,Lanturn,,
|
||||
130,Tapu Lele,,
|
||||
|
@@ -0,0 +1,303 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Rowlet,,
|
||||
2,Dartrix,,
|
||||
3,Decidueye,,
|
||||
4,Litten,,
|
||||
5,Torracat,,
|
||||
6,Incineroar,,
|
||||
7,Popplio,,
|
||||
8,Brionne,,
|
||||
9,Primarina,,
|
||||
10,Pikipek,,
|
||||
11,Trumbeak,,
|
||||
12,Toucannon,,
|
||||
13,Yungoos,,
|
||||
14,Gumshoos,,
|
||||
15,Rattata,,
|
||||
16,Raticate,,
|
||||
17,Caterpie,,
|
||||
18,Metapod,,
|
||||
19,Butterfree,,
|
||||
20,Ledyba,,
|
||||
21,Ledian,,
|
||||
22,Spinarak,,
|
||||
23,Ariados,,
|
||||
24,Pichu,,
|
||||
25,Pikachu,,
|
||||
26,Raichu,,
|
||||
27,Grubbin,,
|
||||
28,Charjabug,,
|
||||
29,Vikavolt,,
|
||||
30,Bonsly,,
|
||||
31,Sudowoodo,,
|
||||
32,Happiny,,
|
||||
33,Chansey,,
|
||||
34,Blissey,,
|
||||
35,Munchlax,,
|
||||
36,Snorlax,,
|
||||
37,Slowpoke,,
|
||||
38,Slowbro,,
|
||||
39,Slowking,,
|
||||
40,Wingull,,
|
||||
41,Pelipper,,
|
||||
42,Abra,,
|
||||
43,Kadabra,,
|
||||
44,Alakazam,,
|
||||
45,Meowth,,
|
||||
46,Persian,,
|
||||
47,Magnemite,,
|
||||
48,Magneton,,
|
||||
49,Magnezone,,
|
||||
50,Grimer,,
|
||||
51,Muk,,
|
||||
52,Growlithe,,
|
||||
53,Arcanine,,
|
||||
54,Drowzee,,
|
||||
55,Hypno,,
|
||||
56,Makuhita,,
|
||||
57,Hariyama,,
|
||||
58,Smeargle,,
|
||||
59,Crabrawler,,
|
||||
60,Crabominable,,
|
||||
61,Gastly,,
|
||||
62,Haunter,,
|
||||
63,Gengar,,
|
||||
64,Drifloon,,
|
||||
65,Drifblim,,
|
||||
66,Misdreavus,,
|
||||
67,Mismagius,,
|
||||
68,Zubat,,
|
||||
69,Golbat,,
|
||||
70,Crobat,,
|
||||
71,Diglett,,
|
||||
72,Dugtrio,,
|
||||
73,Spearow,,
|
||||
74,Fearow,,
|
||||
75,Rufflet,,
|
||||
76,Braviary,,
|
||||
77,Vullaby,,
|
||||
78,Mandibuzz,,
|
||||
79,Mankey,,
|
||||
80,Primeape,,
|
||||
81,Delibird,,
|
||||
82,Oricorio,,
|
||||
83,Cutiefly,,
|
||||
84,Ribombee,,
|
||||
85,Petilil,,
|
||||
86,Lilligant,,
|
||||
87,Cottonee,,
|
||||
88,Whimsicott,,
|
||||
89,Psyduck,,
|
||||
90,Golduck,,
|
||||
91,Magikarp,,
|
||||
92,Gyarados,,
|
||||
93,Barboach,,
|
||||
94,Whiscash,,
|
||||
95,Machop,,
|
||||
96,Machoke,,
|
||||
97,Machamp,,
|
||||
98,Roggenrola,,
|
||||
99,Boldore,,
|
||||
100,Gigalith,,
|
||||
101,Carbink,,
|
||||
102,Sableye,,
|
||||
103,Rockruff,,
|
||||
104,Lycanroc,,
|
||||
105,Spinda,,
|
||||
106,Tentacool,,
|
||||
107,Tentacruel,,
|
||||
108,Finneon,,
|
||||
109,Lumineon,,
|
||||
110,Wishiwashi,,
|
||||
111,Luvdisc,,
|
||||
112,Corsola,,
|
||||
113,Mareanie,,
|
||||
114,Toxapex,,
|
||||
115,Shellder,,
|
||||
116,Cloyster,,
|
||||
117,Bagon,,
|
||||
118,Shelgon,,
|
||||
119,Salamence,,
|
||||
120,Lillipup,,
|
||||
121,Herdier,,
|
||||
122,Stoutland,,
|
||||
123,Eevee,,
|
||||
124,Vaporeon,,
|
||||
125,Jolteon,,
|
||||
126,Flareon,,
|
||||
127,Espeon,,
|
||||
128,Umbreon,,
|
||||
129,Leafeon,,
|
||||
130,Glaceon,,
|
||||
131,Sylveon,,
|
||||
132,Mudbray,,
|
||||
133,Mudsdale,,
|
||||
134,Igglybuff,,
|
||||
135,Jigglypuff,,
|
||||
136,Wigglytuff,,
|
||||
137,Tauros,,
|
||||
138,Miltank,,
|
||||
139,Surskit,,
|
||||
140,Masquerain,,
|
||||
141,Dewpider,,
|
||||
142,Araquanid,,
|
||||
143,Fomantis,,
|
||||
144,Lurantis,,
|
||||
145,Morelull,,
|
||||
146,Shiinotic,,
|
||||
147,Paras,,
|
||||
148,Parasect,,
|
||||
149,Poliwag,,
|
||||
150,Poliwhirl,,
|
||||
151,Poliwrath,,
|
||||
152,Politoed,,
|
||||
153,Goldeen,,
|
||||
154,Seaking,,
|
||||
155,Feebas,,
|
||||
156,Milotic,,
|
||||
157,Alomomola,,
|
||||
158,Fletchling,,
|
||||
159,Fletchinder,,
|
||||
160,Talonflame,,
|
||||
161,Salandit,,
|
||||
162,Salazzle,,
|
||||
163,Cubone,,
|
||||
164,Marowak,,
|
||||
165,Kangaskhan,,
|
||||
166,Magby,,
|
||||
167,Magmar,,
|
||||
168,Magmortar,,
|
||||
169,Stufful,,
|
||||
170,Bewear,,
|
||||
171,Bounsweet,,
|
||||
172,Steenee,,
|
||||
173,Tsareena,,
|
||||
174,Comfey,,
|
||||
175,Pinsir,,
|
||||
176,Oranguru,,
|
||||
177,Passimian,,
|
||||
178,Goomy,,
|
||||
179,Sliggoo,,
|
||||
180,Goodra,,
|
||||
181,Castform,,
|
||||
182,Wimpod,,
|
||||
183,Golisopod,,
|
||||
184,Staryu,,
|
||||
185,Starmie,,
|
||||
186,Sandygast,,
|
||||
187,Palossand,,
|
||||
188,Cranidos,,
|
||||
189,Rampardos,,
|
||||
190,Shieldon,,
|
||||
191,Bastiodon,,
|
||||
192,Archen,,
|
||||
193,Archeops,,
|
||||
194,Tirtouga,,
|
||||
195,Carracosta,,
|
||||
196,Phantump,,
|
||||
197,Trevenant,,
|
||||
198,Nosepass,,
|
||||
199,Probopass,,
|
||||
200,Pyukumuku,,
|
||||
201,Chinchou,,
|
||||
202,Lanturn,,
|
||||
203,Type: Null,,
|
||||
204,Silvally,,
|
||||
205,Zygarde,,
|
||||
206,Trubbish,,
|
||||
207,Garbodor,,
|
||||
208,Skarmory,,
|
||||
209,Ditto,,
|
||||
210,Cleffa,,
|
||||
211,Clefairy,,
|
||||
212,Clefable,,
|
||||
213,Minior,,
|
||||
214,Beldum,,
|
||||
215,Metang,,
|
||||
216,Metagross,,
|
||||
217,Porygon,,
|
||||
218,Porygon2,,
|
||||
219,Porygon-Z,,
|
||||
220,Pancham,,
|
||||
221,Pangoro,,
|
||||
222,Komala,,
|
||||
223,Torkoal,,
|
||||
224,Turtonator,,
|
||||
225,Togedemaru,,
|
||||
226,Elekid,,
|
||||
227,Electabuzz,,
|
||||
228,Electivire,,
|
||||
229,Geodude,,
|
||||
230,Graveler,,
|
||||
231,Golem,,
|
||||
232,Sandile,,
|
||||
233,Krokorok,,
|
||||
234,Krookodile,,
|
||||
235,Trapinch,,
|
||||
236,Vibrava,,
|
||||
237,Flygon,,
|
||||
238,Gible,,
|
||||
239,Gabite,,
|
||||
240,Garchomp,,
|
||||
241,Klefki,,
|
||||
242,Mimikyu,,
|
||||
243,Bruxish,,
|
||||
244,Drampa,,
|
||||
245,Absol,,
|
||||
246,Snorunt,,
|
||||
247,Glalie,,
|
||||
248,Froslass,,
|
||||
249,Sneasel,,
|
||||
250,Weavile,,
|
||||
251,Sandshrew,,
|
||||
252,Sandslash,,
|
||||
253,Vulpix,,
|
||||
254,Ninetales,,
|
||||
255,Vanillite,,
|
||||
256,Vanillish,,
|
||||
257,Vanilluxe,,
|
||||
258,Snubbull,,
|
||||
259,Granbull,,
|
||||
260,Shellos,,
|
||||
261,Gastrodon,,
|
||||
262,Relicanth,,
|
||||
263,Dhelmise,,
|
||||
264,Carvanha,,
|
||||
265,Sharpedo,,
|
||||
266,Wailmer,,
|
||||
267,Wailord,,
|
||||
268,Lapras,,
|
||||
269,Exeggcute,,
|
||||
270,Exeggutor,,
|
||||
271,Jangmo-o,,
|
||||
272,Hakamo-o,,
|
||||
273,Kommo-o,,
|
||||
274,Emolga,,
|
||||
275,Scyther,,
|
||||
276,Scizor,,
|
||||
277,Murkrow,,
|
||||
278,Honchkrow,,
|
||||
279,Riolu,,
|
||||
280,Lucario,,
|
||||
281,Dratini,,
|
||||
282,Dragonair,,
|
||||
283,Dragonite,,
|
||||
284,Aerodactyl,,
|
||||
285,Tapu Koko,,
|
||||
286,Tapu Lele,,
|
||||
287,Tapu Bulu,,
|
||||
288,Tapu Fini,,
|
||||
289,Cosmog,,
|
||||
290,Cosmoem,,
|
||||
291,Solgaleo,,
|
||||
292,Lunala,,
|
||||
293,Nihilego,,
|
||||
294,Buzzwole,,
|
||||
295,Pheromosa,,
|
||||
296,Xurkitree,,
|
||||
297,Celesteela,,
|
||||
298,Kartana,,
|
||||
299,Guzzlord,,
|
||||
300,Necrozma,,
|
||||
301,Magearna,,
|
||||
302,Marshadow,,
|
||||
|
@@ -0,0 +1,121 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Rowlet,,
|
||||
2,Dartrix,,
|
||||
3,Decidueye,,
|
||||
4,Litten,,
|
||||
5,Torracat,,
|
||||
6,Incineroar,,
|
||||
7,Popplio,,
|
||||
8,Brionne,,
|
||||
9,Primarina,,
|
||||
10,Pikipek,,
|
||||
11,Trumbeak,,
|
||||
12,Toucannon,,
|
||||
13,Yungoos,,
|
||||
14,Gumshoos,,
|
||||
15,Rattata,,
|
||||
16,Raticate,,
|
||||
17,Caterpie,,
|
||||
18,Metapod,,
|
||||
19,Butterfree,,
|
||||
20,Ledyba,,
|
||||
21,Ledian,,
|
||||
22,Spinarak,,
|
||||
23,Ariados,,
|
||||
24,Pichu,,
|
||||
25,Pikachu,,
|
||||
26,Raichu,,
|
||||
27,Grubbin,,
|
||||
28,Charjabug,,
|
||||
29,Vikavolt,,
|
||||
30,Bonsly,,
|
||||
31,Sudowoodo,,
|
||||
32,Happiny,,
|
||||
33,Chansey,,
|
||||
34,Blissey,,
|
||||
35,Munchlax,,
|
||||
36,Snorlax,,
|
||||
37,Slowpoke,,
|
||||
38,Slowbro,,
|
||||
39,Slowking,,
|
||||
40,Wingull,,
|
||||
41,Pelipper,,
|
||||
42,Abra,,
|
||||
43,Kadabra,,
|
||||
44,Alakazam,,
|
||||
45,Meowth,,
|
||||
46,Persian,,
|
||||
47,Magnemite,,
|
||||
48,Magneton,,
|
||||
49,Magnezone,,
|
||||
50,Grimer,,
|
||||
51,Muk,,
|
||||
52,Growlithe,,
|
||||
53,Arcanine,,
|
||||
54,Drowzee,,
|
||||
55,Hypno,,
|
||||
56,Makuhita,,
|
||||
57,Hariyama,,
|
||||
58,Smeargle,,
|
||||
59,Crabrawler,,
|
||||
60,Crabominable,,
|
||||
61,Gastly,,
|
||||
62,Haunter,,
|
||||
63,Gengar,,
|
||||
64,Drifloon,,
|
||||
65,Drifblim,,
|
||||
66,Misdreavus,,
|
||||
67,Mismagius,,
|
||||
68,Zubat,,
|
||||
69,Golbat,,
|
||||
70,Crobat,,
|
||||
71,Diglett,,
|
||||
72,Dugtrio,,
|
||||
73,Spearow,,
|
||||
74,Fearow,,
|
||||
75,Rufflet,,
|
||||
76,Braviary,,
|
||||
77,Vullaby,,
|
||||
78,Mandibuzz,,
|
||||
79,Mankey,,
|
||||
80,Primeape,,
|
||||
81,Delibird,,
|
||||
82,Oricorio,,
|
||||
83,Cutiefly,,
|
||||
84,Ribombee,,
|
||||
85,Petilil,,
|
||||
86,Lilligant,,
|
||||
87,Cottonee,,
|
||||
88,Whimsicott,,
|
||||
89,Psyduck,,
|
||||
90,Golduck,,
|
||||
91,Magikarp,,
|
||||
92,Gyarados,,
|
||||
93,Barboach,,
|
||||
94,Whiscash,,
|
||||
95,Machop,,
|
||||
96,Machoke,,
|
||||
97,Machamp,,
|
||||
98,Roggenrola,,
|
||||
99,Boldore,,
|
||||
100,Gigalith,,
|
||||
101,Carbink,,
|
||||
102,Sableye,,
|
||||
103,Rockruff,,
|
||||
104,Lycanroc,,
|
||||
105,Spinda,,
|
||||
106,Tentacool,,
|
||||
107,Tentacruel,,
|
||||
108,Finneon,,
|
||||
109,Lumineon,,
|
||||
110,Wishiwashi,,
|
||||
111,Luvdisc,,
|
||||
112,Corsola,,
|
||||
113,Mareanie,,
|
||||
114,Toxapex,,
|
||||
115,Shellder,,
|
||||
116,Cloyster,,
|
||||
117,Bagon,,
|
||||
118,Shelgon,,
|
||||
119,Salamence,,
|
||||
120,Tapu Koko,,
|
||||
|
@@ -0,0 +1,101 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Pikipek,,
|
||||
2,Trumbeak,,
|
||||
3,Toucannon,,
|
||||
4,Yungoos,,
|
||||
5,Gumshoos,,
|
||||
6,Rattata,,
|
||||
7,Raticate,,
|
||||
8,Happiny,,
|
||||
9,Chansey,,
|
||||
10,Blissey,,
|
||||
11,Wingull,,
|
||||
12,Pelipper,,
|
||||
13,Drowzee,,
|
||||
14,Hypno,,
|
||||
15,Makuhita,,
|
||||
16,Hariyama,,
|
||||
17,Crabrawler,,
|
||||
18,Crabominable,,
|
||||
19,Zubat,,
|
||||
20,Golbat,,
|
||||
21,Crobat,,
|
||||
22,Diglett,,
|
||||
23,Dugtrio,,
|
||||
24,Spearow,,
|
||||
25,Fearow,,
|
||||
26,Rufflet,,
|
||||
27,Braviary,,
|
||||
28,Vullaby,,
|
||||
29,Mandibuzz,,
|
||||
30,Mankey,,
|
||||
31,Primeape,,
|
||||
32,Oricorio,,
|
||||
33,Cutiefly,,
|
||||
34,Ribombee,,
|
||||
35,Petilil,,
|
||||
36,Lilligant,,
|
||||
37,Cottonee,,
|
||||
38,Whimsicott,,
|
||||
39,Psyduck,,
|
||||
40,Golduck,,
|
||||
41,Magikarp,,
|
||||
42,Gyarados,,
|
||||
43,Barboach,,
|
||||
44,Whiscash,,
|
||||
45,Machop,,
|
||||
46,Machoke,,
|
||||
47,Machamp,,
|
||||
48,Roggenrola,,
|
||||
49,Boldore,,
|
||||
50,Gigalith,,
|
||||
51,Carbink,,
|
||||
52,Sableye,,
|
||||
53,Rockruff,,
|
||||
54,Lycanroc,,
|
||||
55,Tentacool,,
|
||||
56,Tentacruel,,
|
||||
57,Finneon,,
|
||||
58,Lumineon,,
|
||||
59,Mudbray,,
|
||||
60,Mudsdale,,
|
||||
61,Tauros,,
|
||||
62,Miltank,,
|
||||
63,Stufful,,
|
||||
64,Bewear,,
|
||||
65,Pinsir,,
|
||||
66,Goomy,,
|
||||
67,Sliggoo,,
|
||||
68,Goodra,,
|
||||
69,Castform,,
|
||||
70,Wimpod,,
|
||||
71,Golisopod,,
|
||||
72,Skarmory,,
|
||||
73,Snubbull,,
|
||||
74,Granbull,,
|
||||
75,Shellos,,
|
||||
76,Gastrodon,,
|
||||
77,Relicanth,,
|
||||
78,Dhelmise,,
|
||||
79,Carvanha,,
|
||||
80,Sharpedo,,
|
||||
81,Wailmer,,
|
||||
82,Wailord,,
|
||||
83,Lapras,,
|
||||
84,Exeggcute,,
|
||||
85,Exeggutor,,
|
||||
86,Jangmo-o,,
|
||||
87,Hakamo-o,,
|
||||
88,Kommo-o,,
|
||||
89,Emolga,,
|
||||
90,Scyther,,
|
||||
91,Scizor,,
|
||||
92,Murkrow,,
|
||||
93,Honchkrow,,
|
||||
94,Riolu,,
|
||||
95,Lucario,,
|
||||
96,Dratini,,
|
||||
97,Dragonair,,
|
||||
98,Dragonite,,
|
||||
99,Aerodactyl,,
|
||||
100,Tapu Fini,,
|
||||
|
@@ -0,0 +1,131 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Pikipek,,
|
||||
2,Trumbeak,,
|
||||
3,Toucannon,,
|
||||
4,Yungoos,,
|
||||
5,Gumshoos,,
|
||||
6,Rattata,,
|
||||
7,Raticate,,
|
||||
8,Ledyba,,
|
||||
9,Ledian,,
|
||||
10,Spinarak,,
|
||||
11,Ariados,,
|
||||
12,Grubbin,,
|
||||
13,Charjabug,,
|
||||
14,Vikavolt,,
|
||||
15,Happiny,,
|
||||
16,Chansey,,
|
||||
17,Blissey,,
|
||||
18,Slowpoke,,
|
||||
19,Slowbro,,
|
||||
20,Slowking,,
|
||||
21,Wingull,,
|
||||
22,Pelipper,,
|
||||
23,Meowth,,
|
||||
24,Persian,,
|
||||
25,Magnemite,,
|
||||
26,Magneton,,
|
||||
27,Magnezone,,
|
||||
28,Grimer,,
|
||||
29,Muk,,
|
||||
30,Crabrawler,,
|
||||
31,Crabominable,,
|
||||
32,Gastly,,
|
||||
33,Haunter,,
|
||||
34,Gengar,,
|
||||
35,Zubat,,
|
||||
36,Golbat,,
|
||||
37,Crobat,,
|
||||
38,Diglett,,
|
||||
39,Dugtrio,,
|
||||
40,Spearow,,
|
||||
41,Fearow,,
|
||||
42,Oricorio,,
|
||||
43,Cutiefly,,
|
||||
44,Ribombee,,
|
||||
45,Petilil,,
|
||||
46,Lilligant,,
|
||||
47,Cottonee,,
|
||||
48,Whimsicott,,
|
||||
49,Psyduck,,
|
||||
50,Golduck,,
|
||||
51,Magikarp,,
|
||||
52,Gyarados,,
|
||||
53,Tentacool,,
|
||||
54,Tentacruel,,
|
||||
55,Finneon,,
|
||||
56,Lumineon,,
|
||||
57,Wishiwashi,,
|
||||
58,Mudbray,,
|
||||
59,Mudsdale,,
|
||||
60,Surskit,,
|
||||
61,Masquerain,,
|
||||
62,Dewpider,,
|
||||
63,Araquanid,,
|
||||
64,Morelull,,
|
||||
65,Shiinotic,,
|
||||
66,Paras,,
|
||||
67,Parasect,,
|
||||
68,Poliwag,,
|
||||
69,Poliwhirl,,
|
||||
70,Poliwrath,,
|
||||
71,Politoed,,
|
||||
72,Goldeen,,
|
||||
73,Seaking,,
|
||||
74,Goomy,,
|
||||
75,Sliggoo,,
|
||||
76,Goodra,,
|
||||
77,Castform,,
|
||||
78,Trubbish,,
|
||||
79,Garbodor,,
|
||||
80,Skarmory,,
|
||||
81,Ditto,,
|
||||
82,Cleffa,,
|
||||
83,Clefairy,,
|
||||
84,Clefable,,
|
||||
85,Minior,,
|
||||
86,Beldum,,
|
||||
87,Metang,,
|
||||
88,Metagross,,
|
||||
89,Porygon,,
|
||||
90,Porygon2,,
|
||||
91,Porygon-Z,,
|
||||
92,Pancham,,
|
||||
93,Pangoro,,
|
||||
94,Komala,,
|
||||
95,Torkoal,,
|
||||
96,Turtonator,,
|
||||
97,Togedemaru,,
|
||||
98,Elekid,,
|
||||
99,Electabuzz,,
|
||||
100,Electivire,,
|
||||
101,Geodude,,
|
||||
102,Graveler,,
|
||||
103,Golem,,
|
||||
104,Sandile,,
|
||||
105,Krokorok,,
|
||||
106,Krookodile,,
|
||||
107,Trapinch,,
|
||||
108,Vibrava,,
|
||||
109,Flygon,,
|
||||
110,Gible,,
|
||||
111,Gabite,,
|
||||
112,Garchomp,,
|
||||
113,Klefki,,
|
||||
114,Mimikyu,,
|
||||
115,Bruxish,,
|
||||
116,Drampa,,
|
||||
117,Absol,,
|
||||
118,Snorunt,,
|
||||
119,Glalie,,
|
||||
120,Froslass,,
|
||||
121,Sneasel,,
|
||||
122,Weavile,,
|
||||
123,Sandshrew,,
|
||||
124,Sandslash,,
|
||||
125,Vulpix,,
|
||||
126,Ninetales,,
|
||||
127,Vanillite,,
|
||||
128,Vanillish,,
|
||||
129,Vanilluxe,,
|
||||
130,Tapu Bulu,,
|
||||
|
@@ -0,0 +1,211 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Snom,,
|
||||
2,Frosmoth,,
|
||||
3,Wooloo,,
|
||||
4,Dubwool,,
|
||||
5,Skwovet,,
|
||||
6,Greedent,,
|
||||
7,Swinub,,
|
||||
8,Piloswine,,
|
||||
9,Mamoswine,,
|
||||
10,Mime Jr.,,
|
||||
11,Mr. Mime,,
|
||||
12,Mr. Rime,,
|
||||
13,Smoochum,,
|
||||
14,Jynx,,
|
||||
15,Elekid,,
|
||||
16,Electabuzz,,
|
||||
17,Electivire,,
|
||||
18,Magby,,
|
||||
19,Magmar,,
|
||||
20,Magmortar,,
|
||||
21,Audino,,
|
||||
22,Vanillite,,
|
||||
23,Vanillish,,
|
||||
24,Vanilluxe,,
|
||||
25,Snorunt,,
|
||||
26,Glalie,,
|
||||
27,Froslass,,
|
||||
28,Sneasel,,
|
||||
29,Weavile,,
|
||||
30,Cryogonal,,
|
||||
31,Snover,,
|
||||
32,Abomasnow,,
|
||||
33,Phantump,,
|
||||
34,Trevenant,,
|
||||
35,Swablu,,
|
||||
36,Altaria,,
|
||||
37,Impidimp,,
|
||||
38,Morgrem,,
|
||||
39,Grimmsnarl,,
|
||||
40,Hatenna,,
|
||||
41,Hattrem,,
|
||||
42,Hatterene,,
|
||||
43,Cleffa,,
|
||||
44,Clefairy,,
|
||||
45,Clefable,,
|
||||
46,Mimikyu,,
|
||||
47,Spiritomb,,
|
||||
48,Litwick,,
|
||||
49,Lampent,,
|
||||
50,Chandelure,,
|
||||
51,Gothita,,
|
||||
52,Gothorita,,
|
||||
53,Gothitelle,,
|
||||
54,Solosis,,
|
||||
55,Duosion,,
|
||||
56,Reuniclus,,
|
||||
57,Timburr,,
|
||||
58,Gurdurr,,
|
||||
59,Conkeldurr,,
|
||||
60,Barboach,,
|
||||
61,Whiscash,,
|
||||
62,Magikarp,,
|
||||
63,Gyarados,,
|
||||
64,Basculin,,
|
||||
65,Nidoran♀,,
|
||||
66,Nidorina,,
|
||||
67,Nidoqueen,,
|
||||
68,Nidoran♂,,
|
||||
69,Nidorino,,
|
||||
70,Nidoking,,
|
||||
71,Zigzagoon,,
|
||||
72,Linoone,,
|
||||
73,Obstagoon,,
|
||||
74,Eevee,,
|
||||
75,Vaporeon,,
|
||||
76,Jolteon,,
|
||||
77,Flareon,,
|
||||
78,Umbreon,,
|
||||
79,Espeon,,
|
||||
80,Glaceon,,
|
||||
81,Leafeon,,
|
||||
82,Sylveon,,
|
||||
83,Tyrunt,,
|
||||
84,Tyrantrum,,
|
||||
85,Amaura,,
|
||||
86,Aurorus,,
|
||||
87,Bronzor,,
|
||||
88,Bronzong,,
|
||||
89,Stonjourner,,
|
||||
90,Eiscue,,
|
||||
91,Dewpider,,
|
||||
92,Araquanid,,
|
||||
93,Joltik,,
|
||||
94,Galvantula,,
|
||||
95,Karrablast,,
|
||||
96,Escavalier,,
|
||||
97,Shelmet,,
|
||||
98,Accelgor,,
|
||||
99,Sizzlipede,,
|
||||
100,Centiskorch,,
|
||||
101,Durant,,
|
||||
102,Heatmor,,
|
||||
103,Darumaka,,
|
||||
104,Darmanitan,,
|
||||
105,Ponyta,,
|
||||
106,Rapidash,,
|
||||
107,Absol,,
|
||||
108,Cufant,,
|
||||
109,Copperajah,,
|
||||
110,Dreepy,,
|
||||
111,Drakloak,,
|
||||
112,Dragapult,,
|
||||
113,Bagon,,
|
||||
114,Shelgon,,
|
||||
115,Salamence,,
|
||||
116,Gible,,
|
||||
117,Gabite,,
|
||||
118,Garchomp,,
|
||||
119,Druddigon,,
|
||||
120,Delibird,,
|
||||
121,Cubchoo,,
|
||||
122,Beartic,,
|
||||
123,Omanyte,,
|
||||
124,Omastar,,
|
||||
125,Kabuto,,
|
||||
126,Kabutops,,
|
||||
127,Aerodactyl,,
|
||||
128,Carbink,,
|
||||
129,Beldum,,
|
||||
130,Metang,,
|
||||
131,Metagross,,
|
||||
132,Sinistea,,
|
||||
133,Polteageist,,
|
||||
134,Riolu,,
|
||||
135,Lucario,,
|
||||
136,Deino,,
|
||||
137,Zweilous,,
|
||||
138,Hydreigon,,
|
||||
139,Larvitar,,
|
||||
140,Pupitar,,
|
||||
141,Tyranitar,,
|
||||
142,Bergmite,,
|
||||
143,Avalugg,,
|
||||
144,Zubat,,
|
||||
145,Golbat,,
|
||||
146,Crobat,,
|
||||
147,Tirtouga,,
|
||||
148,Carracosta,,
|
||||
149,Archen,,
|
||||
150,Archeops,,
|
||||
151,Baltoy,,
|
||||
152,Claydol,,
|
||||
153,Golett,,
|
||||
154,Golurk,,
|
||||
155,Yamper,,
|
||||
156,Boltund,,
|
||||
157,Morpeko,,
|
||||
158,Pincurchin,,
|
||||
159,Spheal,,
|
||||
160,Sealeo,,
|
||||
161,Walrein,,
|
||||
162,Dhelmise,,
|
||||
163,Rookidee,,
|
||||
164,Corvisquire,,
|
||||
165,Corviknight,,
|
||||
166,Gossifleur,,
|
||||
167,Eldegoss,,
|
||||
168,Cottonee,,
|
||||
169,Whimsicott,,
|
||||
170,Shuckle,,
|
||||
171,Indeedee,,
|
||||
172,Munchlax,,
|
||||
173,Snorlax,,
|
||||
174,Sableye,,
|
||||
175,Mawile,,
|
||||
176,Rolycoly,,
|
||||
177,Carkol,,
|
||||
178,Coalossal,,
|
||||
179,Ferroseed,,
|
||||
180,Ferrothorn,,
|
||||
181,Noibat,,
|
||||
182,Noivern,,
|
||||
183,Lileep,,
|
||||
184,Cradily,,
|
||||
185,Anorith,,
|
||||
186,Armaldo,,
|
||||
187,Relicanth,,
|
||||
188,Feebas,,
|
||||
189,Milotic,,
|
||||
190,Lapras,,
|
||||
191,Aron,,
|
||||
192,Lairon,,
|
||||
193,Aggron,,
|
||||
194,Dratini,,
|
||||
195,Dragonair,,
|
||||
196,Dragonite,,
|
||||
197,Regirock,,
|
||||
198,Regice,,
|
||||
199,Registeel,,
|
||||
200,Regieleki,,
|
||||
201,Regidrago,,
|
||||
202,Articuno,,
|
||||
203,Zapdos,,
|
||||
204,Moltres,,
|
||||
205,Cobalion,,
|
||||
206,Terrakion,,
|
||||
207,Virizion,,
|
||||
208,Glastrier,,
|
||||
209,Spectrier,,
|
||||
210,Calyrex,,
|
||||
|
@@ -0,0 +1,212 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Slowpoke,,
|
||||
2,Slowbro,,
|
||||
3,Slowking,,
|
||||
4,Buneary,,
|
||||
5,Lopunny,,
|
||||
6,Happiny,,
|
||||
7,Chansey,,
|
||||
8,Blissey,,
|
||||
9,Skwovet,,
|
||||
10,Greedent,,
|
||||
11,Igglybuff,,
|
||||
12,Jigglypuff,,
|
||||
13,Wigglytuff,,
|
||||
14,Blipbug,,
|
||||
15,Dottler,,
|
||||
16,Orbeetle,,
|
||||
17,Fomantis,,
|
||||
18,Lurantis,,
|
||||
19,Applin,,
|
||||
20,Flapple,,
|
||||
21,Appletun,,
|
||||
22,Fletchling,,
|
||||
23,Fletchinder,,
|
||||
24,Talonflame,,
|
||||
25,Shinx,,
|
||||
26,Luxio,,
|
||||
27,Luxray,,
|
||||
28,Klefki,,
|
||||
29,Pawniard,,
|
||||
30,Bisharp,,
|
||||
31,Abra,,
|
||||
32,Kadabra,,
|
||||
33,Alakazam,,
|
||||
34,Ralts,,
|
||||
35,Kirlia,,
|
||||
36,Gardevoir,,
|
||||
37,Gallade,,
|
||||
38,Krabby,,
|
||||
39,Kingler,,
|
||||
40,Tentacool,,
|
||||
41,Tentacruel,,
|
||||
42,Magikarp,,
|
||||
43,Gyarados,,
|
||||
44,Remoraid,,
|
||||
45,Octillery,,
|
||||
46,Mantyke,,
|
||||
47,Mantine,,
|
||||
48,Wingull,,
|
||||
49,Pelipper,,
|
||||
50,Skorupi,,
|
||||
51,Drapion,,
|
||||
52,Dunsparce,,
|
||||
53,Bouffalant,,
|
||||
54,Lickitung,,
|
||||
55,Lickilicky,,
|
||||
56,Chewtle,,
|
||||
57,Drednaw,,
|
||||
58,Wooper,,
|
||||
59,Quagsire,,
|
||||
60,Goomy,,
|
||||
61,Sliggoo,,
|
||||
62,Goodra,,
|
||||
63,Druddigon,,
|
||||
64,Shelmet,,
|
||||
65,Accelgor,,
|
||||
66,Karrablast,,
|
||||
67,Escavalier,,
|
||||
68,Bulbasaur,,
|
||||
69,Ivysaur,,
|
||||
70,Venusaur,,
|
||||
71,Squirtle,,
|
||||
72,Wartortle,,
|
||||
73,Blastoise,,
|
||||
74,Venipede,,
|
||||
75,Whirlipede,,
|
||||
76,Scolipede,,
|
||||
77,Foongus,,
|
||||
78,Amoonguss,,
|
||||
79,Comfey,,
|
||||
80,Tangela,,
|
||||
81,Tangrowth,,
|
||||
82,Croagunk,,
|
||||
83,Toxicroak,,
|
||||
84,Pichu,,
|
||||
85,Pikachu,,
|
||||
86,Raichu,,
|
||||
87,Zorua,,
|
||||
88,Zoroark,,
|
||||
89,Oranguru,,
|
||||
90,Passimian,,
|
||||
91,Corphish,,
|
||||
92,Crawdaunt,,
|
||||
93,Cramorant,,
|
||||
94,Goldeen,,
|
||||
95,Seaking,,
|
||||
96,Arrokuda,,
|
||||
97,Barraskewda,,
|
||||
98,Staryu,,
|
||||
99,Starmie,,
|
||||
100,Kubfu,,
|
||||
101,Urshifu,,
|
||||
102,Emolga,,
|
||||
103,Dedenne,,
|
||||
104,Morpeko,,
|
||||
105,Magnemite,,
|
||||
106,Magneton,,
|
||||
107,Magnezone,,
|
||||
108,Inkay,,
|
||||
109,Malamar,,
|
||||
110,Wishiwashi,,
|
||||
111,Carvanha,,
|
||||
112,Sharpedo,,
|
||||
113,Lillipup,,
|
||||
114,Herdier,,
|
||||
115,Stoutland,,
|
||||
116,Tauros,,
|
||||
117,Miltank,,
|
||||
118,Scyther,,
|
||||
119,Scizor,,
|
||||
120,Pinsir,,
|
||||
121,Heracross,,
|
||||
122,Dwebble,,
|
||||
123,Crustle,,
|
||||
124,Wimpod,,
|
||||
125,Golisopod,,
|
||||
126,Pincurchin,,
|
||||
127,Mareanie,,
|
||||
128,Toxapex,,
|
||||
129,Clobbopus,,
|
||||
130,Grapploct,,
|
||||
131,Shellder,,
|
||||
132,Cloyster,,
|
||||
133,Sandygast,,
|
||||
134,Palossand,,
|
||||
135,Drifloon,,
|
||||
136,Drifblim,,
|
||||
137,Barboach,,
|
||||
138,Whiscash,,
|
||||
139,Azurill,,
|
||||
140,Marill,,
|
||||
141,Azumarill,,
|
||||
142,Poliwag,,
|
||||
143,Poliwhirl,,
|
||||
144,Poliwrath,,
|
||||
145,Politoed,,
|
||||
146,Psyduck,,
|
||||
147,Golduck,,
|
||||
148,Whismur,,
|
||||
149,Loudred,,
|
||||
150,Exploud,,
|
||||
151,Woobat,,
|
||||
152,Swoobat,,
|
||||
153,Skarmory,,
|
||||
154,Roggenrola,,
|
||||
155,Boldore,,
|
||||
156,Gigalith,,
|
||||
157,Rockruff,,
|
||||
158,Lycanroc,,
|
||||
159,Salandit,,
|
||||
160,Salazzle,,
|
||||
161,Scraggy,,
|
||||
162,Scrafty,,
|
||||
163,Mienfoo,,
|
||||
164,Mienshao,,
|
||||
165,Jangmo-o,,
|
||||
166,Hakamo-o,,
|
||||
167,Kommo-o,,
|
||||
168,Sandshrew,,
|
||||
169,Sandslash,,
|
||||
170,Cubone,,
|
||||
171,Marowak,,
|
||||
172,Kangaskhan,,
|
||||
173,Torkoal,,
|
||||
174,Silicobra,,
|
||||
175,Sandaconda,,
|
||||
176,Sandile,,
|
||||
177,Krokorok,,
|
||||
178,Krookodile,,
|
||||
179,Rufflet,,
|
||||
180,Braviary,,
|
||||
181,Vullaby,,
|
||||
182,Mandibuzz,,
|
||||
183,Rhyhorn,,
|
||||
184,Rhydon,,
|
||||
185,Rhyperior,,
|
||||
186,Larvesta,,
|
||||
187,Volcarona,,
|
||||
188,Chinchou,,
|
||||
189,Lanturn,,
|
||||
190,Wailmer,,
|
||||
191,Wailord,,
|
||||
192,Frillish,,
|
||||
193,Jellicent,,
|
||||
194,Skrelp,,
|
||||
195,Dragalge,,
|
||||
196,Clauncher,,
|
||||
197,Clawitzer,,
|
||||
198,Horsea,,
|
||||
199,Seadra,,
|
||||
200,Kingdra,,
|
||||
201,Petilil,,
|
||||
202,Lilligant,,
|
||||
203,Combee,,
|
||||
204,Vespiquen,,
|
||||
205,Exeggcute,,
|
||||
206,Exeggutor,,
|
||||
207,Ditto,,
|
||||
208,Porygon,,
|
||||
209,Porygon2,,
|
||||
210,Porygon-Z,,
|
||||
211,Zarude,,
|
||||
|
@@ -0,0 +1,401 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Grookey,,
|
||||
2,Thwackey,,
|
||||
3,Rillaboom,,
|
||||
4,Scorbunny,,
|
||||
5,Raboot,,
|
||||
6,Cinderace,,
|
||||
7,Sobble,,
|
||||
8,Drizzile,,
|
||||
9,Inteleon,,
|
||||
10,Blipbug,,
|
||||
11,Dottler,,
|
||||
12,Orbeetle,,
|
||||
13,Caterpie,,
|
||||
14,Metapod,,
|
||||
15,Butterfree,,
|
||||
16,Grubbin,,
|
||||
17,Charjabug,,
|
||||
18,Vikavolt,,
|
||||
19,Hoothoot,,
|
||||
20,Noctowl,,
|
||||
21,Rookidee,,
|
||||
22,Corvisquire,,
|
||||
23,Corviknight,,
|
||||
24,Skwovet,,
|
||||
25,Greedent,,
|
||||
26,Pidove,,
|
||||
27,Tranquill,,
|
||||
28,Unfezant,,
|
||||
29,Nickit,,
|
||||
30,Thievul,,
|
||||
31,Zigzagoon,,
|
||||
32,Linoone,,
|
||||
33,Obstagoon,,
|
||||
34,Wooloo,,
|
||||
35,Dubwool,,
|
||||
36,Lotad,,
|
||||
37,Lombre,,
|
||||
38,Ludicolo,,
|
||||
39,Seedot,,
|
||||
40,Nuzleaf,,
|
||||
41,Shiftry,,
|
||||
42,Chewtle,,
|
||||
43,Drednaw,,
|
||||
44,Purrloin,,
|
||||
45,Liepard,,
|
||||
46,Yamper,,
|
||||
47,Boltund,,
|
||||
48,Bunnelby,,
|
||||
49,Diggersby,,
|
||||
50,Minccino,,
|
||||
51,Cinccino,,
|
||||
52,Bounsweet,,
|
||||
53,Steenee,,
|
||||
54,Tsareena,,
|
||||
55,Oddish,,
|
||||
56,Gloom,,
|
||||
57,Vileplume,,
|
||||
58,Bellossom,,
|
||||
59,Budew,,
|
||||
60,Roselia,,
|
||||
61,Roserade,,
|
||||
62,Wingull,,
|
||||
63,Pelipper,,
|
||||
64,Joltik,,
|
||||
65,Galvantula,,
|
||||
66,Electrike,,
|
||||
67,Manectric,,
|
||||
68,Vulpix,,
|
||||
69,Ninetales,,
|
||||
70,Growlithe,,
|
||||
71,Arcanine,,
|
||||
72,Vanillite,,
|
||||
73,Vanillish,,
|
||||
74,Vanilluxe,,
|
||||
75,Swinub,,
|
||||
76,Piloswine,,
|
||||
77,Mamoswine,,
|
||||
78,Delibird,,
|
||||
79,Snorunt,,
|
||||
80,Glalie,,
|
||||
81,Froslass,,
|
||||
82,Baltoy,,
|
||||
83,Claydol,,
|
||||
84,Mudbray,,
|
||||
85,Mudsdale,,
|
||||
86,Dwebble,,
|
||||
87,Crustle,,
|
||||
88,Golett,,
|
||||
89,Golurk,,
|
||||
90,Munna,,
|
||||
91,Musharna,,
|
||||
92,Natu,,
|
||||
93,Xatu,,
|
||||
94,Stufful,,
|
||||
95,Bewear,,
|
||||
96,Snover,,
|
||||
97,Abomasnow,,
|
||||
98,Krabby,,
|
||||
99,Kingler,,
|
||||
100,Wooper,,
|
||||
101,Quagsire,,
|
||||
102,Corphish,,
|
||||
103,Crawdaunt,,
|
||||
104,Nincada,,
|
||||
105,Ninjask,,
|
||||
106,Shedinja,,
|
||||
107,Tyrogue,,
|
||||
108,Hitmonlee,,
|
||||
109,Hitmonchan,,
|
||||
110,Hitmontop,,
|
||||
111,Pancham,,
|
||||
112,Pangoro,,
|
||||
113,Klink,,
|
||||
114,Klang,,
|
||||
115,Klinklang,,
|
||||
116,Combee,,
|
||||
117,Vespiquen,,
|
||||
118,Bronzor,,
|
||||
119,Bronzong,,
|
||||
120,Ralts,,
|
||||
121,Kirlia,,
|
||||
122,Gardevoir,,
|
||||
123,Gallade,,
|
||||
124,Drifloon,,
|
||||
125,Drifblim,,
|
||||
126,Gossifleur,,
|
||||
127,Eldegoss,,
|
||||
128,Cherubi,,
|
||||
129,Cherrim,,
|
||||
130,Stunky,,
|
||||
131,Skuntank,,
|
||||
132,Tympole,,
|
||||
133,Palpitoad,,
|
||||
134,Seismitoad,,
|
||||
135,Duskull,,
|
||||
136,Dusclops,,
|
||||
137,Dusknoir,,
|
||||
138,Machop,,
|
||||
139,Machoke,,
|
||||
140,Machamp,,
|
||||
141,Gastly,,
|
||||
142,Haunter,,
|
||||
143,Gengar,,
|
||||
144,Magikarp,,
|
||||
145,Gyarados,,
|
||||
146,Goldeen,,
|
||||
147,Seaking,,
|
||||
148,Remoraid,,
|
||||
149,Octillery,,
|
||||
150,Shellder,,
|
||||
151,Cloyster,,
|
||||
152,Feebas,,
|
||||
153,Milotic,,
|
||||
154,Basculin,,
|
||||
155,Wishiwashi,,
|
||||
156,Pyukumuku,,
|
||||
157,Trubbish,,
|
||||
158,Garbodor,,
|
||||
159,Sizzlipede,,
|
||||
160,Centiskorch,,
|
||||
161,Rolycoly,,
|
||||
162,Carkol,,
|
||||
163,Coalossal,,
|
||||
164,Diglett,,
|
||||
165,Dugtrio,,
|
||||
166,Drilbur,,
|
||||
167,Excadrill,,
|
||||
168,Roggenrola,,
|
||||
169,Boldore,,
|
||||
170,Gigalith,,
|
||||
171,Timburr,,
|
||||
172,Gurdurr,,
|
||||
173,Conkeldurr,,
|
||||
174,Woobat,,
|
||||
175,Swoobat,,
|
||||
176,Noibat,,
|
||||
177,Noivern,,
|
||||
178,Onix,,
|
||||
179,Steelix,,
|
||||
180,Arrokuda,,
|
||||
181,Barraskewda,,
|
||||
182,Meowth,,
|
||||
183,Perrserker,,
|
||||
184,Persian,,
|
||||
185,Milcery,,
|
||||
186,Alcremie,,
|
||||
187,Cutiefly,,
|
||||
188,Ribombee,,
|
||||
189,Ferroseed,,
|
||||
190,Ferrothorn,,
|
||||
191,Pumpkaboo,,
|
||||
192,Gourgeist,,
|
||||
193,Pichu,,
|
||||
194,Pikachu,,
|
||||
195,Raichu,,
|
||||
196,Eevee,,
|
||||
197,Vaporeon,,
|
||||
198,Jolteon,,
|
||||
199,Flareon,,
|
||||
200,Espeon,,
|
||||
201,Umbreon,,
|
||||
202,Leafeon,,
|
||||
203,Glaceon,,
|
||||
204,Sylveon,,
|
||||
205,Applin,,
|
||||
206,Flapple,,
|
||||
207,Appletun,,
|
||||
208,Espurr,,
|
||||
209,Meowstic,,
|
||||
210,Swirlix,,
|
||||
211,Slurpuff,,
|
||||
212,Spritzee,,
|
||||
213,Aromatisse,,
|
||||
214,Dewpider,,
|
||||
215,Araquanid,,
|
||||
216,Wynaut,,
|
||||
217,Wobbuffet,,
|
||||
218,Farfetch’d,,
|
||||
219,Sirfetch’d,,
|
||||
220,Chinchou,,
|
||||
221,Lanturn,,
|
||||
222,Croagunk,,
|
||||
223,Toxicroak,,
|
||||
224,Scraggy,,
|
||||
225,Scrafty,,
|
||||
226,Stunfisk,,
|
||||
227,Shuckle,,
|
||||
228,Barboach,,
|
||||
229,Whiscash,,
|
||||
230,Shellos,,
|
||||
231,Gastrodon,,
|
||||
232,Wimpod,,
|
||||
233,Golisopod,,
|
||||
234,Binacle,,
|
||||
235,Barbaracle,,
|
||||
236,Corsola,,
|
||||
237,Cursola,,
|
||||
238,Impidimp,,
|
||||
239,Morgrem,,
|
||||
240,Grimmsnarl,,
|
||||
241,Hatenna,,
|
||||
242,Hattrem,,
|
||||
243,Hatterene,,
|
||||
244,Salandit,,
|
||||
245,Salazzle,,
|
||||
246,Pawniard,,
|
||||
247,Bisharp,,
|
||||
248,Throh,,
|
||||
249,Sawk,,
|
||||
250,Koffing,,
|
||||
251,Weezing,,
|
||||
252,Bonsly,,
|
||||
253,Sudowoodo,,
|
||||
254,Cleffa,,
|
||||
255,Clefairy,,
|
||||
256,Clefable,,
|
||||
257,Togepi,,
|
||||
258,Togetic,,
|
||||
259,Togekiss,,
|
||||
260,Munchlax,,
|
||||
261,Snorlax,,
|
||||
262,Cottonee,,
|
||||
263,Whimsicott,,
|
||||
264,Rhyhorn,,
|
||||
265,Rhydon,,
|
||||
266,Rhyperior,,
|
||||
267,Gothita,,
|
||||
268,Gothorita,,
|
||||
269,Gothitelle,,
|
||||
270,Solosis,,
|
||||
271,Duosion,,
|
||||
272,Reuniclus,,
|
||||
273,Karrablast,,
|
||||
274,Escavalier,,
|
||||
275,Shelmet,,
|
||||
276,Accelgor,,
|
||||
277,Elgyem,,
|
||||
278,Beheeyem,,
|
||||
279,Cubchoo,,
|
||||
280,Beartic,,
|
||||
281,Rufflet,,
|
||||
282,Braviary,,
|
||||
283,Vullaby,,
|
||||
284,Mandibuzz,,
|
||||
285,Skorupi,,
|
||||
286,Drapion,,
|
||||
287,Litwick,,
|
||||
288,Lampent,,
|
||||
289,Chandelure,,
|
||||
290,Inkay,,
|
||||
291,Malamar,,
|
||||
292,Sneasel,,
|
||||
293,Weavile,,
|
||||
294,Sableye,,
|
||||
295,Mawile,,
|
||||
296,Maractus,,
|
||||
297,Sigilyph,,
|
||||
298,Riolu,,
|
||||
299,Lucario,,
|
||||
300,Torkoal,,
|
||||
301,Mimikyu,,
|
||||
302,Cufant,,
|
||||
303,Copperajah,,
|
||||
304,Qwilfish,,
|
||||
305,Frillish,,
|
||||
306,Jellicent,,
|
||||
307,Mareanie,,
|
||||
308,Toxapex,,
|
||||
309,Cramorant,,
|
||||
310,Toxel,,
|
||||
311,Toxtricity,,
|
||||
312,Silicobra,,
|
||||
313,Sandaconda,,
|
||||
314,Hippopotas,,
|
||||
315,Hippowdon,,
|
||||
316,Durant,,
|
||||
317,Heatmor,,
|
||||
318,Helioptile,,
|
||||
319,Heliolisk,,
|
||||
320,Hawlucha,,
|
||||
321,Trapinch,,
|
||||
322,Vibrava,,
|
||||
323,Flygon,,
|
||||
324,Axew,,
|
||||
325,Fraxure,,
|
||||
326,Haxorus,,
|
||||
327,Yamask,,
|
||||
328,Runerigus,,
|
||||
329,Cofagrigus,,
|
||||
330,Honedge,,
|
||||
331,Doublade,,
|
||||
332,Aegislash,,
|
||||
333,Ponyta,,
|
||||
334,Rapidash,,
|
||||
335,Sinistea,,
|
||||
336,Polteageist,,
|
||||
337,Indeedee,,
|
||||
338,Phantump,,
|
||||
339,Trevenant,,
|
||||
340,Morelull,,
|
||||
341,Shiinotic,,
|
||||
342,Oranguru,,
|
||||
343,Passimian,,
|
||||
344,Morpeko,,
|
||||
345,Falinks,,
|
||||
346,Drampa,,
|
||||
347,Turtonator,,
|
||||
348,Togedemaru,,
|
||||
349,Snom,,
|
||||
350,Frosmoth,,
|
||||
351,Clobbopus,,
|
||||
352,Grapploct,,
|
||||
353,Pincurchin,,
|
||||
354,Mantyke,,
|
||||
355,Mantine,,
|
||||
356,Wailmer,,
|
||||
357,Wailord,,
|
||||
358,Bergmite,,
|
||||
359,Avalugg,,
|
||||
360,Dhelmise,,
|
||||
361,Lapras,,
|
||||
362,Lunatone,,
|
||||
363,Solrock,,
|
||||
364,Mime Jr.,,
|
||||
365,Mr. Mime,,
|
||||
366,Mr. Rime,,
|
||||
367,Darumaka,,
|
||||
368,Darmanitan,,
|
||||
369,Stonjourner,,
|
||||
370,Eiscue,,
|
||||
371,Duraludon,,
|
||||
372,Rotom,,
|
||||
373,Ditto,,
|
||||
374,Dracozolt,,
|
||||
375,Arctozolt,,
|
||||
376,Dracovish,,
|
||||
377,Arctovish,,
|
||||
378,Charmander,,
|
||||
379,Charmeleon,,
|
||||
380,Charizard,,
|
||||
381,Type: Null,,
|
||||
382,Silvally,,
|
||||
383,Larvitar,,
|
||||
384,Pupitar,,
|
||||
385,Tyranitar,,
|
||||
386,Deino,,
|
||||
387,Zweilous,,
|
||||
388,Hydreigon,,
|
||||
389,Goomy,,
|
||||
390,Sliggoo,,
|
||||
391,Goodra,,
|
||||
392,Jangmo-o,,
|
||||
393,Hakamo-o,,
|
||||
394,Kommo-o,,
|
||||
395,Dreepy,,
|
||||
396,Drakloak,,
|
||||
397,Dragapult,,
|
||||
398,Zacian,,
|
||||
399,Zamazenta,,
|
||||
400,Eternatus,,
|
||||
|
@@ -0,0 +1,161 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Pikipek,,
|
||||
2,Trumbeak,,
|
||||
3,Toucannon,,
|
||||
4,Yungoos,,
|
||||
5,Gumshoos,,
|
||||
6,Rattata,,
|
||||
7,Raticate,,
|
||||
8,Caterpie,,
|
||||
9,Metapod,,
|
||||
10,Butterfree,,
|
||||
11,Grubbin,,
|
||||
12,Charjabug,,
|
||||
13,Vikavolt,,
|
||||
14,Bonsly,,
|
||||
15,Sudowoodo,,
|
||||
16,Happiny,,
|
||||
17,Chansey,,
|
||||
18,Blissey,,
|
||||
19,Wingull,,
|
||||
20,Pelipper,,
|
||||
21,Crabrawler,,
|
||||
22,Crabominable,,
|
||||
23,Gastly,,
|
||||
24,Haunter,,
|
||||
25,Gengar,,
|
||||
26,Zubat,,
|
||||
27,Golbat,,
|
||||
28,Crobat,,
|
||||
29,Diglett,,
|
||||
30,Dugtrio,,
|
||||
31,Oricorio,,
|
||||
32,Psyduck,,
|
||||
33,Golduck,,
|
||||
34,Magikarp,,
|
||||
35,Gyarados,,
|
||||
36,Barboach,,
|
||||
37,Whiscash,,
|
||||
38,Tentacool,,
|
||||
39,Tentacruel,,
|
||||
40,Finneon,,
|
||||
41,Lumineon,,
|
||||
42,Wishiwashi,,
|
||||
43,Luvdisc,,
|
||||
44,Corsola,,
|
||||
45,Mareanie,,
|
||||
46,Toxapex,,
|
||||
47,Remoraid,,
|
||||
48,Octillery,,
|
||||
49,Mantyke,,
|
||||
50,Mantine,,
|
||||
51,Lillipup,,
|
||||
52,Herdier,,
|
||||
53,Stoutland,,
|
||||
54,Eevee,,
|
||||
55,Vaporeon,,
|
||||
56,Jolteon,,
|
||||
57,Flareon,,
|
||||
58,Espeon,,
|
||||
59,Umbreon,,
|
||||
60,Leafeon,,
|
||||
61,Glaceon,,
|
||||
62,Sylveon,,
|
||||
63,Mareep,,
|
||||
64,Flaaffy,,
|
||||
65,Ampharos,,
|
||||
66,Mudbray,,
|
||||
67,Mudsdale,,
|
||||
68,Igglybuff,,
|
||||
69,Jigglypuff,,
|
||||
70,Wigglytuff,,
|
||||
71,Tauros,,
|
||||
72,Miltank,,
|
||||
73,Surskit,,
|
||||
74,Masquerain,,
|
||||
75,Dewpider,,
|
||||
76,Araquanid,,
|
||||
77,Fomantis,,
|
||||
78,Lurantis,,
|
||||
79,Morelull,,
|
||||
80,Shiinotic,,
|
||||
81,Paras,,
|
||||
82,Parasect,,
|
||||
83,Poliwag,,
|
||||
84,Poliwhirl,,
|
||||
85,Poliwrath,,
|
||||
86,Politoed,,
|
||||
87,Goldeen,,
|
||||
88,Seaking,,
|
||||
89,Basculin,,
|
||||
90,Feebas,,
|
||||
91,Milotic,,
|
||||
92,Alomomola,,
|
||||
93,Fletchling,,
|
||||
94,Fletchinder,,
|
||||
95,Talonflame,,
|
||||
96,Salandit,,
|
||||
97,Salazzle,,
|
||||
98,Cubone,,
|
||||
99,Marowak,,
|
||||
100,Kangaskhan,,
|
||||
101,Magby,,
|
||||
102,Magmar,,
|
||||
103,Magmortar,,
|
||||
104,Larvesta,,
|
||||
105,Volcarona,,
|
||||
106,Stufful,,
|
||||
107,Bewear,,
|
||||
108,Bounsweet,,
|
||||
109,Steenee,,
|
||||
110,Tsareena,,
|
||||
111,Comfey,,
|
||||
112,Pinsir,,
|
||||
113,Hoothoot,,
|
||||
114,Noctowl,,
|
||||
115,Kecleon,,
|
||||
116,Oranguru,,
|
||||
117,Passimian,,
|
||||
118,Goomy,,
|
||||
119,Sliggoo,,
|
||||
120,Goodra,,
|
||||
121,Castform,,
|
||||
122,Wimpod,,
|
||||
123,Golisopod,,
|
||||
124,Staryu,,
|
||||
125,Starmie,,
|
||||
126,Sandygast,,
|
||||
127,Palossand,,
|
||||
128,Omanyte,,
|
||||
129,Omastar,,
|
||||
130,Kabuto,,
|
||||
131,Kabutops,,
|
||||
132,Lileep,,
|
||||
133,Cradily,,
|
||||
134,Anorith,,
|
||||
135,Armaldo,,
|
||||
136,Cranidos,,
|
||||
137,Rampardos,,
|
||||
138,Shieldon,,
|
||||
139,Bastiodon,,
|
||||
140,Archen,,
|
||||
141,Archeops,,
|
||||
142,Tirtouga,,
|
||||
143,Carracosta,,
|
||||
144,Tyrunt,,
|
||||
145,Tyrantrum,,
|
||||
146,Amaura,,
|
||||
147,Aurorus,,
|
||||
148,Larvitar,,
|
||||
149,Pupitar,,
|
||||
150,Tyranitar,,
|
||||
151,Phantump,,
|
||||
152,Trevenant,,
|
||||
153,Natu,,
|
||||
154,Xatu,,
|
||||
155,Nosepass,,
|
||||
156,Probopass,,
|
||||
157,Pyukumuku,,
|
||||
158,Chinchou,,
|
||||
159,Lanturn,,
|
||||
160,Tapu Lele,,
|
||||
|
@@ -0,0 +1,404 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Rowlet,,
|
||||
2,Dartrix,,
|
||||
3,Decidueye,,
|
||||
4,Litten,,
|
||||
5,Torracat,,
|
||||
6,Incineroar,,
|
||||
7,Popplio,,
|
||||
8,Brionne,,
|
||||
9,Primarina,,
|
||||
10,Pikipek,,
|
||||
11,Trumbeak,,
|
||||
12,Toucannon,,
|
||||
13,Yungoos,,
|
||||
14,Gumshoos,,
|
||||
15,Rattata,,
|
||||
16,Raticate,,
|
||||
17,Caterpie,,
|
||||
18,Metapod,,
|
||||
19,Butterfree,,
|
||||
20,Ledyba,,
|
||||
21,Ledian,,
|
||||
22,Spinarak,,
|
||||
23,Ariados,,
|
||||
24,Buneary,,
|
||||
25,Lopunny,,
|
||||
26,Inkay,,
|
||||
27,Malamar,,
|
||||
28,Zorua,,
|
||||
29,Zoroark,,
|
||||
30,Furfrou,,
|
||||
31,Pichu,,
|
||||
32,Pikachu,,
|
||||
33,Raichu,,
|
||||
34,Grubbin,,
|
||||
35,Charjabug,,
|
||||
36,Vikavolt,,
|
||||
37,Bonsly,,
|
||||
38,Sudowoodo,,
|
||||
39,Happiny,,
|
||||
40,Chansey,,
|
||||
41,Blissey,,
|
||||
42,Munchlax,,
|
||||
43,Snorlax,,
|
||||
44,Slowpoke,,
|
||||
45,Slowbro,,
|
||||
46,Slowking,,
|
||||
47,Wingull,,
|
||||
48,Pelipper,,
|
||||
49,Abra,,
|
||||
50,Kadabra,,
|
||||
51,Alakazam,,
|
||||
52,Meowth,,
|
||||
53,Persian,,
|
||||
54,Magnemite,,
|
||||
55,Magneton,,
|
||||
56,Magnezone,,
|
||||
57,Grimer,,
|
||||
58,Muk,,
|
||||
59,Mime Jr.,,
|
||||
60,Mr. Mime,,
|
||||
61,Ekans,,
|
||||
62,Arbok,,
|
||||
63,Dunsparce,,
|
||||
64,Growlithe,,
|
||||
65,Arcanine,,
|
||||
66,Drowzee,,
|
||||
67,Hypno,,
|
||||
68,Makuhita,,
|
||||
69,Hariyama,,
|
||||
70,Smeargle,,
|
||||
71,Crabrawler,,
|
||||
72,Crabominable,,
|
||||
73,Gastly,,
|
||||
74,Haunter,,
|
||||
75,Gengar,,
|
||||
76,Drifloon,,
|
||||
77,Drifblim,,
|
||||
78,Murkrow,,
|
||||
79,Honchkrow,,
|
||||
80,Zubat,,
|
||||
81,Golbat,,
|
||||
82,Crobat,,
|
||||
83,Noibat,,
|
||||
84,Noivern,,
|
||||
85,Diglett,,
|
||||
86,Dugtrio,,
|
||||
87,Spearow,,
|
||||
88,Fearow,,
|
||||
89,Rufflet,,
|
||||
90,Braviary,,
|
||||
91,Vullaby,,
|
||||
92,Mandibuzz,,
|
||||
93,Mankey,,
|
||||
94,Primeape,,
|
||||
95,Delibird,,
|
||||
96,Hawlucha,,
|
||||
97,Oricorio,,
|
||||
98,Cutiefly,,
|
||||
99,Ribombee,,
|
||||
100,Flabébé,,
|
||||
101,Floette,,
|
||||
102,Florges,,
|
||||
103,Petilil,,
|
||||
104,Lilligant,,
|
||||
105,Cottonee,,
|
||||
106,Whimsicott,,
|
||||
107,Psyduck,,
|
||||
108,Golduck,,
|
||||
109,Smoochum,,
|
||||
110,Jynx,,
|
||||
111,Magikarp,,
|
||||
112,Gyarados,,
|
||||
113,Barboach,,
|
||||
114,Whiscash,,
|
||||
115,Seel,,
|
||||
116,Dewgong,,
|
||||
117,Machop,,
|
||||
118,Machoke,,
|
||||
119,Machamp,,
|
||||
120,Roggenrola,,
|
||||
121,Boldore,,
|
||||
122,Gigalith,,
|
||||
123,Carbink,,
|
||||
124,Sableye,,
|
||||
125,Mawile,,
|
||||
126,Rockruff,,
|
||||
127,Lycanroc,,
|
||||
128,Spinda,,
|
||||
129,Tentacool,,
|
||||
130,Tentacruel,,
|
||||
131,Finneon,,
|
||||
132,Lumineon,,
|
||||
133,Wishiwashi,,
|
||||
134,Luvdisc,,
|
||||
135,Corsola,,
|
||||
136,Mareanie,,
|
||||
137,Toxapex,,
|
||||
138,Shellder,,
|
||||
139,Cloyster,,
|
||||
140,Clamperl,,
|
||||
141,Huntail,,
|
||||
142,Gorebyss,,
|
||||
143,Remoraid,,
|
||||
144,Octillery,,
|
||||
145,Mantyke,,
|
||||
146,Mantine,,
|
||||
147,Bagon,,
|
||||
148,Shelgon,,
|
||||
149,Salamence,,
|
||||
150,Lillipup,,
|
||||
151,Herdier,,
|
||||
152,Stoutland,,
|
||||
153,Eevee,,
|
||||
154,Vaporeon,,
|
||||
155,Jolteon,,
|
||||
156,Flareon,,
|
||||
157,Espeon,,
|
||||
158,Umbreon,,
|
||||
159,Leafeon,,
|
||||
160,Glaceon,,
|
||||
161,Sylveon,,
|
||||
162,Mareep,,
|
||||
163,Flaaffy,,
|
||||
164,Ampharos,,
|
||||
165,Mudbray,,
|
||||
166,Mudsdale,,
|
||||
167,Igglybuff,,
|
||||
168,Jigglypuff,,
|
||||
169,Wigglytuff,,
|
||||
170,Tauros,,
|
||||
171,Miltank,,
|
||||
172,Surskit,,
|
||||
173,Masquerain,,
|
||||
174,Dewpider,,
|
||||
175,Araquanid,,
|
||||
176,Fomantis,,
|
||||
177,Lurantis,,
|
||||
178,Morelull,,
|
||||
179,Shiinotic,,
|
||||
180,Paras,,
|
||||
181,Parasect,,
|
||||
182,Poliwag,,
|
||||
183,Poliwhirl,,
|
||||
184,Poliwrath,,
|
||||
185,Politoed,,
|
||||
186,Goldeen,,
|
||||
187,Seaking,,
|
||||
188,Basculin,,
|
||||
189,Feebas,,
|
||||
190,Milotic,,
|
||||
191,Alomomola,,
|
||||
192,Fletchling,,
|
||||
193,Fletchinder,,
|
||||
194,Talonflame,,
|
||||
195,Salandit,,
|
||||
196,Salazzle,,
|
||||
197,Cubone,,
|
||||
198,Marowak,,
|
||||
199,Kangaskhan,,
|
||||
200,Magby,,
|
||||
201,Magmar,,
|
||||
202,Magmortar,,
|
||||
203,Larvesta,,
|
||||
204,Volcarona,,
|
||||
205,Stufful,,
|
||||
206,Bewear,,
|
||||
207,Bounsweet,,
|
||||
208,Steenee,,
|
||||
209,Tsareena,,
|
||||
210,Comfey,,
|
||||
211,Pinsir,,
|
||||
212,Hoothoot,,
|
||||
213,Noctowl,,
|
||||
214,Kecleon,,
|
||||
215,Oranguru,,
|
||||
216,Passimian,,
|
||||
217,Goomy,,
|
||||
218,Sliggoo,,
|
||||
219,Goodra,,
|
||||
220,Castform,,
|
||||
221,Wimpod,,
|
||||
222,Golisopod,,
|
||||
223,Staryu,,
|
||||
224,Starmie,,
|
||||
225,Sandygast,,
|
||||
226,Palossand,,
|
||||
227,Omanyte,,
|
||||
228,Omastar,,
|
||||
229,Kabuto,,
|
||||
230,Kabutops,,
|
||||
231,Lileep,,
|
||||
232,Cradily,,
|
||||
233,Anorith,,
|
||||
234,Armaldo,,
|
||||
235,Cranidos,,
|
||||
236,Rampardos,,
|
||||
237,Shieldon,,
|
||||
238,Bastiodon,,
|
||||
239,Archen,,
|
||||
240,Archeops,,
|
||||
241,Tirtouga,,
|
||||
242,Carracosta,,
|
||||
243,Tyrunt,,
|
||||
244,Tyrantrum,,
|
||||
245,Amaura,,
|
||||
246,Aurorus,,
|
||||
247,Larvitar,,
|
||||
248,Pupitar,,
|
||||
249,Tyranitar,,
|
||||
250,Phantump,,
|
||||
251,Trevenant,,
|
||||
252,Natu,,
|
||||
253,Xatu,,
|
||||
254,Nosepass,,
|
||||
255,Probopass,,
|
||||
256,Pyukumuku,,
|
||||
257,Chinchou,,
|
||||
258,Lanturn,,
|
||||
259,Type: Null,,
|
||||
260,Silvally,,
|
||||
261,Poipole,,
|
||||
262,Naganadel,,
|
||||
263,Zygarde,,
|
||||
264,Trubbish,,
|
||||
265,Garbodor,,
|
||||
266,Minccino,,
|
||||
267,Cinccino,,
|
||||
268,Pineco,,
|
||||
269,Forretress,,
|
||||
270,Skarmory,,
|
||||
271,Ditto,,
|
||||
272,Cleffa,,
|
||||
273,Clefairy,,
|
||||
274,Clefable,,
|
||||
275,Elgyem,,
|
||||
276,Beheeyem,,
|
||||
277,Minior,,
|
||||
278,Beldum,,
|
||||
279,Metang,,
|
||||
280,Metagross,,
|
||||
281,Porygon,,
|
||||
282,Porygon2,,
|
||||
283,Porygon-Z,,
|
||||
284,Pancham,,
|
||||
285,Pangoro,,
|
||||
286,Komala,,
|
||||
287,Torkoal,,
|
||||
288,Turtonator,,
|
||||
289,Houndour,,
|
||||
290,Houndoom,,
|
||||
291,Dedenne,,
|
||||
292,Togedemaru,,
|
||||
293,Electrike,,
|
||||
294,Manectric,,
|
||||
295,Elekid,,
|
||||
296,Electabuzz,,
|
||||
297,Electivire,,
|
||||
298,Geodude,,
|
||||
299,Graveler,,
|
||||
300,Golem,,
|
||||
301,Sandile,,
|
||||
302,Krokorok,,
|
||||
303,Krookodile,,
|
||||
304,Trapinch,,
|
||||
305,Vibrava,,
|
||||
306,Flygon,,
|
||||
307,Gible,,
|
||||
308,Gabite,,
|
||||
309,Garchomp,,
|
||||
310,Baltoy,,
|
||||
311,Claydol,,
|
||||
312,Golett,,
|
||||
313,Golurk,,
|
||||
314,Klefki,,
|
||||
315,Mimikyu,,
|
||||
316,Shuppet,,
|
||||
317,Banette,,
|
||||
318,Frillish,,
|
||||
319,Jellicent,,
|
||||
320,Bruxish,,
|
||||
321,Drampa,,
|
||||
322,Absol,,
|
||||
323,Snorunt,,
|
||||
324,Glalie,,
|
||||
325,Froslass,,
|
||||
326,Sneasel,,
|
||||
327,Weavile,,
|
||||
328,Sandshrew,,
|
||||
329,Sandslash,,
|
||||
330,Vulpix,,
|
||||
331,Ninetales,,
|
||||
332,Vanillite,,
|
||||
333,Vanillish,,
|
||||
334,Vanilluxe,,
|
||||
335,Scraggy,,
|
||||
336,Scrafty,,
|
||||
337,Pawniard,,
|
||||
338,Bisharp,,
|
||||
339,Snubbull,,
|
||||
340,Granbull,,
|
||||
341,Shellos,,
|
||||
342,Gastrodon,,
|
||||
343,Relicanth,,
|
||||
344,Dhelmise,,
|
||||
345,Carvanha,,
|
||||
346,Sharpedo,,
|
||||
347,Skrelp,,
|
||||
348,Dragalge,,
|
||||
349,Clauncher,,
|
||||
350,Clawitzer,,
|
||||
351,Wailmer,,
|
||||
352,Wailord,,
|
||||
353,Lapras,,
|
||||
354,Tropius,,
|
||||
355,Exeggcute,,
|
||||
356,Exeggutor,,
|
||||
357,Corphish,,
|
||||
358,Crawdaunt,,
|
||||
359,Mienfoo,,
|
||||
360,Mienshao,,
|
||||
361,Jangmo-o,,
|
||||
362,Hakamo-o,,
|
||||
363,Kommo-o,,
|
||||
364,Emolga,,
|
||||
365,Scyther,,
|
||||
366,Scizor,,
|
||||
367,Heracross,,
|
||||
368,Aipom,,
|
||||
369,Ambipom,,
|
||||
370,Litleo,,
|
||||
371,Pyroar,,
|
||||
372,Misdreavus,,
|
||||
373,Mismagius,,
|
||||
374,Druddigon,,
|
||||
375,Lickitung,,
|
||||
376,Lickilicky,,
|
||||
377,Riolu,,
|
||||
378,Lucario,,
|
||||
379,Dratini,,
|
||||
380,Dragonair,,
|
||||
381,Dragonite,,
|
||||
382,Aerodactyl,,
|
||||
383,Tapu Koko,,
|
||||
384,Tapu Lele,,
|
||||
385,Tapu Bulu,,
|
||||
386,Tapu Fini,,
|
||||
387,Cosmog,,
|
||||
388,Cosmoem,,
|
||||
389,Solgaleo,,
|
||||
390,Lunala,,
|
||||
391,Stakataka,,
|
||||
392,Blacephalon,,
|
||||
393,Nihilego,,
|
||||
394,Buzzwole,,
|
||||
395,Pheromosa,,
|
||||
396,Xurkitree,,
|
||||
397,Celesteela,,
|
||||
398,Kartana,,
|
||||
399,Guzzlord,,
|
||||
400,Necrozma,,
|
||||
401,Magearna,,
|
||||
402,Marshadow,,
|
||||
403,Zeraora,,
|
||||
|
@@ -0,0 +1,151 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Rowlet,,
|
||||
2,Dartrix,,
|
||||
3,Decidueye,,
|
||||
4,Litten,,
|
||||
5,Torracat,,
|
||||
6,Incineroar,,
|
||||
7,Popplio,,
|
||||
8,Brionne,,
|
||||
9,Primarina,,
|
||||
10,Pikipek,,
|
||||
11,Trumbeak,,
|
||||
12,Toucannon,,
|
||||
13,Yungoos,,
|
||||
14,Gumshoos,,
|
||||
15,Rattata,,
|
||||
16,Raticate,,
|
||||
17,Caterpie,,
|
||||
18,Metapod,,
|
||||
19,Butterfree,,
|
||||
20,Ledyba,,
|
||||
21,Ledian,,
|
||||
22,Spinarak,,
|
||||
23,Ariados,,
|
||||
24,Buneary,,
|
||||
25,Lopunny,,
|
||||
26,Inkay,,
|
||||
27,Malamar,,
|
||||
28,Zorua,,
|
||||
29,Zoroark,,
|
||||
30,Furfrou,,
|
||||
31,Pichu,,
|
||||
32,Pikachu,,
|
||||
33,Raichu,,
|
||||
34,Grubbin,,
|
||||
35,Charjabug,,
|
||||
36,Vikavolt,,
|
||||
37,Bonsly,,
|
||||
38,Sudowoodo,,
|
||||
39,Happiny,,
|
||||
40,Chansey,,
|
||||
41,Blissey,,
|
||||
42,Munchlax,,
|
||||
43,Snorlax,,
|
||||
44,Slowpoke,,
|
||||
45,Slowbro,,
|
||||
46,Slowking,,
|
||||
47,Wingull,,
|
||||
48,Pelipper,,
|
||||
49,Abra,,
|
||||
50,Kadabra,,
|
||||
51,Alakazam,,
|
||||
52,Meowth,,
|
||||
53,Persian,,
|
||||
54,Magnemite,,
|
||||
55,Magneton,,
|
||||
56,Magnezone,,
|
||||
57,Grimer,,
|
||||
58,Muk,,
|
||||
59,Mime Jr.,,
|
||||
60,Mr. Mime,,
|
||||
61,Ekans,,
|
||||
62,Arbok,,
|
||||
63,Dunsparce,,
|
||||
64,Growlithe,,
|
||||
65,Arcanine,,
|
||||
66,Drowzee,,
|
||||
67,Hypno,,
|
||||
68,Makuhita,,
|
||||
69,Hariyama,,
|
||||
70,Smeargle,,
|
||||
71,Crabrawler,,
|
||||
72,Crabominable,,
|
||||
73,Gastly,,
|
||||
74,Haunter,,
|
||||
75,Gengar,,
|
||||
76,Drifloon,,
|
||||
77,Drifblim,,
|
||||
78,Murkrow,,
|
||||
79,Honchkrow,,
|
||||
80,Zubat,,
|
||||
81,Golbat,,
|
||||
82,Crobat,,
|
||||
83,Noibat,,
|
||||
84,Noivern,,
|
||||
85,Diglett,,
|
||||
86,Dugtrio,,
|
||||
87,Spearow,,
|
||||
88,Fearow,,
|
||||
89,Rufflet,,
|
||||
90,Braviary,,
|
||||
91,Vullaby,,
|
||||
92,Mandibuzz,,
|
||||
93,Mankey,,
|
||||
94,Primeape,,
|
||||
95,Delibird,,
|
||||
96,Hawlucha,,
|
||||
97,Oricorio,,
|
||||
98,Cutiefly,,
|
||||
99,Ribombee,,
|
||||
100,Flabébé,,
|
||||
101,Floette,,
|
||||
102,Florges,,
|
||||
103,Petilil,,
|
||||
104,Lilligant,,
|
||||
105,Cottonee,,
|
||||
106,Whimsicott,,
|
||||
107,Psyduck,,
|
||||
108,Golduck,,
|
||||
109,Smoochum,,
|
||||
110,Jynx,,
|
||||
111,Magikarp,,
|
||||
112,Gyarados,,
|
||||
113,Barboach,,
|
||||
114,Whiscash,,
|
||||
115,Seel,,
|
||||
116,Dewgong,,
|
||||
117,Machop,,
|
||||
118,Machoke,,
|
||||
119,Machamp,,
|
||||
120,Roggenrola,,
|
||||
121,Boldore,,
|
||||
122,Gigalith,,
|
||||
123,Carbink,,
|
||||
124,Sableye,,
|
||||
125,Mawile,,
|
||||
126,Rockruff,,
|
||||
127,Lycanroc,,
|
||||
128,Spinda,,
|
||||
129,Tentacool,,
|
||||
130,Tentacruel,,
|
||||
131,Finneon,,
|
||||
132,Lumineon,,
|
||||
133,Wishiwashi,,
|
||||
134,Luvdisc,,
|
||||
135,Corsola,,
|
||||
136,Mareanie,,
|
||||
137,Toxapex,,
|
||||
138,Shellder,,
|
||||
139,Cloyster,,
|
||||
140,Clamperl,,
|
||||
141,Huntail,,
|
||||
142,Gorebyss,,
|
||||
143,Remoraid,,
|
||||
144,Octillery,,
|
||||
145,Mantyke,,
|
||||
146,Mantine,,
|
||||
147,Bagon,,
|
||||
148,Shelgon,,
|
||||
149,Salamence,,
|
||||
150,Tapu Koko,,
|
||||
|
@@ -0,0 +1,131 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Pikipek,,
|
||||
2,Trumbeak,,
|
||||
3,Toucannon,,
|
||||
4,Yungoos,,
|
||||
5,Gumshoos,,
|
||||
6,Rattata,,
|
||||
7,Raticate,,
|
||||
8,Buneary,,
|
||||
9,Lopunny,,
|
||||
10,Inkay,,
|
||||
11,Malamar,,
|
||||
12,Zorua,,
|
||||
13,Zoroark,,
|
||||
14,Furfrou,,
|
||||
15,Happiny,,
|
||||
16,Chansey,,
|
||||
17,Blissey,,
|
||||
18,Wingull,,
|
||||
19,Pelipper,,
|
||||
20,Drowzee,,
|
||||
21,Hypno,,
|
||||
22,Makuhita,,
|
||||
23,Hariyama,,
|
||||
24,Crabrawler,,
|
||||
25,Crabominable,,
|
||||
26,Zubat,,
|
||||
27,Golbat,,
|
||||
28,Crobat,,
|
||||
29,Noibat,,
|
||||
30,Noivern,,
|
||||
31,Diglett,,
|
||||
32,Dugtrio,,
|
||||
33,Spearow,,
|
||||
34,Fearow,,
|
||||
35,Rufflet,,
|
||||
36,Braviary,,
|
||||
37,Vullaby,,
|
||||
38,Mandibuzz,,
|
||||
39,Mankey,,
|
||||
40,Primeape,,
|
||||
41,Oricorio,,
|
||||
42,Cutiefly,,
|
||||
43,Ribombee,,
|
||||
44,Flabébé,,
|
||||
45,Floette,,
|
||||
46,Florges,,
|
||||
47,Petilil,,
|
||||
48,Lilligant,,
|
||||
49,Cottonee,,
|
||||
50,Whimsicott,,
|
||||
51,Psyduck,,
|
||||
52,Golduck,,
|
||||
53,Magikarp,,
|
||||
54,Gyarados,,
|
||||
55,Barboach,,
|
||||
56,Whiscash,,
|
||||
57,Machop,,
|
||||
58,Machoke,,
|
||||
59,Machamp,,
|
||||
60,Roggenrola,,
|
||||
61,Boldore,,
|
||||
62,Gigalith,,
|
||||
63,Carbink,,
|
||||
64,Sableye,,
|
||||
65,Rockruff,,
|
||||
66,Lycanroc,,
|
||||
67,Tentacool,,
|
||||
68,Tentacruel,,
|
||||
69,Finneon,,
|
||||
70,Lumineon,,
|
||||
71,Mudbray,,
|
||||
72,Mudsdale,,
|
||||
73,Tauros,,
|
||||
74,Miltank,,
|
||||
75,Basculin,,
|
||||
76,Stufful,,
|
||||
77,Bewear,,
|
||||
78,Pinsir,,
|
||||
79,Goomy,,
|
||||
80,Sliggoo,,
|
||||
81,Goodra,,
|
||||
82,Castform,,
|
||||
83,Wimpod,,
|
||||
84,Golisopod,,
|
||||
85,Skarmory,,
|
||||
86,Snubbull,,
|
||||
87,Granbull,,
|
||||
88,Shellos,,
|
||||
89,Gastrodon,,
|
||||
90,Relicanth,,
|
||||
91,Dhelmise,,
|
||||
92,Carvanha,,
|
||||
93,Sharpedo,,
|
||||
94,Skrelp,,
|
||||
95,Dragalge,,
|
||||
96,Clauncher,,
|
||||
97,Clawitzer,,
|
||||
98,Wailmer,,
|
||||
99,Wailord,,
|
||||
100,Lapras,,
|
||||
101,Tropius,,
|
||||
102,Exeggcute,,
|
||||
103,Exeggutor,,
|
||||
104,Corphish,,
|
||||
105,Crawdaunt,,
|
||||
106,Mienfoo,,
|
||||
107,Mienshao,,
|
||||
108,Jangmo-o,,
|
||||
109,Hakamo-o,,
|
||||
110,Kommo-o,,
|
||||
111,Emolga,,
|
||||
112,Scyther,,
|
||||
113,Scizor,,
|
||||
114,Heracross,,
|
||||
115,Aipom,,
|
||||
116,Ambipom,,
|
||||
117,Litleo,,
|
||||
118,Pyroar,,
|
||||
119,Misdreavus,,
|
||||
120,Mismagius,,
|
||||
121,Druddigon,,
|
||||
122,Lickitung,,
|
||||
123,Lickilicky,,
|
||||
124,Riolu,,
|
||||
125,Lucario,,
|
||||
126,Dratini,,
|
||||
127,Dragonair,,
|
||||
128,Dragonite,,
|
||||
129,Aerodactyl,,
|
||||
130,Tapu Fini,,
|
||||
|
@@ -0,0 +1,161 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Pikipek,,
|
||||
2,Trumbeak,,
|
||||
3,Toucannon,,
|
||||
4,Yungoos,,
|
||||
5,Gumshoos,,
|
||||
6,Rattata,,
|
||||
7,Raticate,,
|
||||
8,Ledyba,,
|
||||
9,Ledian,,
|
||||
10,Spinarak,,
|
||||
11,Ariados,,
|
||||
12,Grubbin,,
|
||||
13,Charjabug,,
|
||||
14,Vikavolt,,
|
||||
15,Happiny,,
|
||||
16,Chansey,,
|
||||
17,Blissey,,
|
||||
18,Slowpoke,,
|
||||
19,Slowbro,,
|
||||
20,Slowking,,
|
||||
21,Wingull,,
|
||||
22,Pelipper,,
|
||||
23,Meowth,,
|
||||
24,Persian,,
|
||||
25,Magnemite,,
|
||||
26,Magneton,,
|
||||
27,Magnezone,,
|
||||
28,Grimer,,
|
||||
29,Muk,,
|
||||
30,Crabrawler,,
|
||||
31,Crabominable,,
|
||||
32,Gastly,,
|
||||
33,Haunter,,
|
||||
34,Gengar,,
|
||||
35,Zubat,,
|
||||
36,Golbat,,
|
||||
37,Crobat,,
|
||||
38,Diglett,,
|
||||
39,Dugtrio,,
|
||||
40,Spearow,,
|
||||
41,Fearow,,
|
||||
42,Oricorio,,
|
||||
43,Cutiefly,,
|
||||
44,Ribombee,,
|
||||
45,Flabébé,,
|
||||
46,Floette,,
|
||||
47,Florges,,
|
||||
48,Petilil,,
|
||||
49,Lilligant,,
|
||||
50,Cottonee,,
|
||||
51,Whimsicott,,
|
||||
52,Psyduck,,
|
||||
53,Golduck,,
|
||||
54,Magikarp,,
|
||||
55,Gyarados,,
|
||||
56,Tentacool,,
|
||||
57,Tentacruel,,
|
||||
58,Finneon,,
|
||||
59,Lumineon,,
|
||||
60,Wishiwashi,,
|
||||
61,Clamperl,,
|
||||
62,Huntail,,
|
||||
63,Gorebyss,,
|
||||
64,Mudbray,,
|
||||
65,Mudsdale,,
|
||||
66,Surskit,,
|
||||
67,Masquerain,,
|
||||
68,Dewpider,,
|
||||
69,Araquanid,,
|
||||
70,Morelull,,
|
||||
71,Shiinotic,,
|
||||
72,Paras,,
|
||||
73,Parasect,,
|
||||
74,Poliwag,,
|
||||
75,Poliwhirl,,
|
||||
76,Poliwrath,,
|
||||
77,Politoed,,
|
||||
78,Goldeen,,
|
||||
79,Seaking,,
|
||||
80,Basculin,,
|
||||
81,Goomy,,
|
||||
82,Sliggoo,,
|
||||
83,Goodra,,
|
||||
84,Castform,,
|
||||
85,Trubbish,,
|
||||
86,Garbodor,,
|
||||
87,Minccino,,
|
||||
88,Cinccino,,
|
||||
89,Pineco,,
|
||||
90,Forretress,,
|
||||
91,Skarmory,,
|
||||
92,Ditto,,
|
||||
93,Cleffa,,
|
||||
94,Clefairy,,
|
||||
95,Clefable,,
|
||||
96,Elgyem,,
|
||||
97,Beheeyem,,
|
||||
98,Minior,,
|
||||
99,Beldum,,
|
||||
100,Metang,,
|
||||
101,Metagross,,
|
||||
102,Porygon,,
|
||||
103,Porygon2,,
|
||||
104,Porygon-Z,,
|
||||
105,Pancham,,
|
||||
106,Pangoro,,
|
||||
107,Komala,,
|
||||
108,Torkoal,,
|
||||
109,Turtonator,,
|
||||
110,Houndour,,
|
||||
111,Houndoom,,
|
||||
112,Dedenne,,
|
||||
113,Togedemaru,,
|
||||
114,Electrike,,
|
||||
115,Manectric,,
|
||||
116,Elekid,,
|
||||
117,Electabuzz,,
|
||||
118,Electivire,,
|
||||
119,Geodude,,
|
||||
120,Graveler,,
|
||||
121,Golem,,
|
||||
122,Sandile,,
|
||||
123,Krokorok,,
|
||||
124,Krookodile,,
|
||||
125,Trapinch,,
|
||||
126,Vibrava,,
|
||||
127,Flygon,,
|
||||
128,Gible,,
|
||||
129,Gabite,,
|
||||
130,Garchomp,,
|
||||
131,Baltoy,,
|
||||
132,Claydol,,
|
||||
133,Golett,,
|
||||
134,Golurk,,
|
||||
135,Klefki,,
|
||||
136,Mimikyu,,
|
||||
137,Shuppet,,
|
||||
138,Banette,,
|
||||
139,Frillish,,
|
||||
140,Jellicent,,
|
||||
141,Bruxish,,
|
||||
142,Drampa,,
|
||||
143,Absol,,
|
||||
144,Snorunt,,
|
||||
145,Glalie,,
|
||||
146,Froslass,,
|
||||
147,Sneasel,,
|
||||
148,Weavile,,
|
||||
149,Sandshrew,,
|
||||
150,Sandslash,,
|
||||
151,Vulpix,,
|
||||
152,Ninetales,,
|
||||
153,Vanillite,,
|
||||
154,Vanillish,,
|
||||
155,Vanilluxe,,
|
||||
156,Scraggy,,
|
||||
157,Scrafty,,
|
||||
158,Pawniard,,
|
||||
159,Bisharp,,
|
||||
160,Tapu Bulu,,
|
||||
|
@@ -0,0 +1,154 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Chespin,,
|
||||
2,Quilladin,,
|
||||
3,Chesnaught,,
|
||||
4,Fennekin,,
|
||||
5,Braixen,,
|
||||
6,Delphox,,
|
||||
7,Froakie,,
|
||||
8,Frogadier,,
|
||||
9,Greninja,,
|
||||
10,Bunnelby,,
|
||||
11,Diggersby,,
|
||||
12,Zigzagoon,,
|
||||
13,Linoone,,
|
||||
14,Fletchling,,
|
||||
15,Fletchinder,,
|
||||
16,Talonflame,,
|
||||
17,Pidgey,,
|
||||
18,Pidgeotto,,
|
||||
19,Pidgeot,,
|
||||
20,Scatterbug,,
|
||||
21,Spewpa,,
|
||||
22,Vivillon,,
|
||||
23,Caterpie,,
|
||||
24,Metapod,,
|
||||
25,Butterfree,,
|
||||
26,Weedle,,
|
||||
27,Kakuna,,
|
||||
28,Beedrill,,
|
||||
29,Pansage,,
|
||||
30,Simisage,,
|
||||
31,Pansear,,
|
||||
32,Simisear,,
|
||||
33,Panpour,,
|
||||
34,Simipour,,
|
||||
35,Pichu,,
|
||||
36,Pikachu,,
|
||||
37,Raichu,,
|
||||
38,Bidoof,,
|
||||
39,Bibarel,,
|
||||
40,Dunsparce,,
|
||||
41,Azurill,,
|
||||
42,Marill,,
|
||||
43,Azumarill,,
|
||||
44,Burmy,,
|
||||
45,Wormadam,,
|
||||
46,Mothim,,
|
||||
47,Surskit,,
|
||||
48,Masquerain,,
|
||||
49,Magikarp,,
|
||||
50,Gyarados,,
|
||||
51,Corphish,,
|
||||
52,Crawdaunt,,
|
||||
53,Goldeen,,
|
||||
54,Seaking,,
|
||||
55,Carvanha,,
|
||||
56,Sharpedo,,
|
||||
57,Litleo,,
|
||||
58,Pyroar,,
|
||||
59,Psyduck,,
|
||||
60,Golduck,,
|
||||
61,Farfetch'd,,
|
||||
62,Riolu,,
|
||||
63,Lucario,,
|
||||
64,Ralts,,
|
||||
65,Kirlia,,
|
||||
66,Gardevoir,,
|
||||
67,Gallade,,
|
||||
68,Flabébé,,
|
||||
69,Floette,,
|
||||
70,Florges,,
|
||||
71,Budew,,
|
||||
72,Roselia,,
|
||||
73,Roserade,,
|
||||
74,Ledyba,,
|
||||
75,Ledian,,
|
||||
76,Combee,,
|
||||
77,Vespiquen,,
|
||||
78,Skitty,,
|
||||
79,Delcatty,,
|
||||
80,Bulbasaur,,
|
||||
81,Ivysaur,,
|
||||
82,Venusaur,,
|
||||
83,Charmander,,
|
||||
84,Charmeleon,,
|
||||
85,Charizard,,
|
||||
86,Squirtle,,
|
||||
87,Wartortle,,
|
||||
88,Blastoise,,
|
||||
89,Skiddo,,
|
||||
90,Gogoat,,
|
||||
91,Pancham,,
|
||||
92,Pangoro,,
|
||||
93,Furfrou,,
|
||||
94,Doduo,,
|
||||
95,Dodrio,,
|
||||
96,Plusle,,
|
||||
97,Minun,,
|
||||
98,Gulpin,,
|
||||
99,Swalot,,
|
||||
100,Scraggy,,
|
||||
101,Scrafty,,
|
||||
102,Abra,,
|
||||
103,Kadabra,,
|
||||
104,Alakazam,,
|
||||
105,Oddish,,
|
||||
106,Gloom,,
|
||||
107,Vileplume,,
|
||||
108,Bellossom,,
|
||||
109,Sentret,,
|
||||
110,Furret,,
|
||||
111,Nincada,,
|
||||
112,Ninjask,,
|
||||
113,Shedinja,,
|
||||
114,Espurr,,
|
||||
115,Meowstic,,
|
||||
116,Kecleon,,
|
||||
117,Honedge,,
|
||||
118,Doublade,,
|
||||
119,Aegislash,,
|
||||
120,Venipede,,
|
||||
121,Whirlipede,,
|
||||
122,Scolipede,,
|
||||
123,Audino,,
|
||||
124,Smeargle,,
|
||||
125,Croagunk,,
|
||||
126,Toxicroak,,
|
||||
127,Ducklett,,
|
||||
128,Swanna,,
|
||||
129,Spritzee,,
|
||||
130,Aromatisse,,
|
||||
131,Swirlix,,
|
||||
132,Slurpuff,,
|
||||
133,Volbeat,,
|
||||
134,Illumise,,
|
||||
135,Hoppip,,
|
||||
136,Skiploom,,
|
||||
137,Jumpluff,,
|
||||
138,Munchlax,,
|
||||
139,Snorlax,,
|
||||
140,Whismur,,
|
||||
141,Loudred,,
|
||||
142,Exploud,,
|
||||
143,Meditite,,
|
||||
144,Medicham,,
|
||||
145,Zubat,,
|
||||
146,Golbat,,
|
||||
147,Crobat,,
|
||||
148,Axew,,
|
||||
149,Fraxure,,
|
||||
150,Haxorus,,
|
||||
151,Diancie,,
|
||||
152,Hoopa,,
|
||||
153,Volcanion,,
|
||||
|
@@ -0,0 +1,154 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Drifloon,,
|
||||
2,Drifblim,,
|
||||
3,Mienfoo,,
|
||||
4,Mienshao,,
|
||||
5,Zangoose,,
|
||||
6,Seviper,,
|
||||
7,Spoink,,
|
||||
8,Grumpig,,
|
||||
9,Absol,,
|
||||
10,Inkay,,
|
||||
11,Malamar,,
|
||||
12,Lunatone,,
|
||||
13,Solrock,,
|
||||
14,Bagon,,
|
||||
15,Shelgon,,
|
||||
16,Salamence,,
|
||||
17,Wingull,,
|
||||
18,Pelipper,,
|
||||
19,Taillow,,
|
||||
20,Swellow,,
|
||||
21,Binacle,,
|
||||
22,Barbaracle,,
|
||||
23,Dwebble,,
|
||||
24,Crustle,,
|
||||
25,Tentacool,,
|
||||
26,Tentacruel,,
|
||||
27,Wailmer,,
|
||||
28,Wailord,,
|
||||
29,Luvdisc,,
|
||||
30,Skrelp,,
|
||||
31,Dragalge,,
|
||||
32,Clauncher,,
|
||||
33,Clawitzer,,
|
||||
34,Staryu,,
|
||||
35,Starmie,,
|
||||
36,Shellder,,
|
||||
37,Cloyster,,
|
||||
38,Qwilfish,,
|
||||
39,Horsea,,
|
||||
40,Seadra,,
|
||||
41,Kingdra,,
|
||||
42,Relicanth,,
|
||||
43,Sandile,,
|
||||
44,Krokorok,,
|
||||
45,Krookodile,,
|
||||
46,Helioptile,,
|
||||
47,Heliolisk,,
|
||||
48,Hippopotas,,
|
||||
49,Hippowdon,,
|
||||
50,Rhyhorn,,
|
||||
51,Rhydon,,
|
||||
52,Rhyperior,,
|
||||
53,Onix,,
|
||||
54,Steelix,,
|
||||
55,Woobat,,
|
||||
56,Swoobat,,
|
||||
57,Machop,,
|
||||
58,Machoke,,
|
||||
59,Machamp,,
|
||||
60,Cubone,,
|
||||
61,Marowak,,
|
||||
62,Kangaskhan,,
|
||||
63,Mawile,,
|
||||
64,Tyrunt,,
|
||||
65,Tyrantrum,,
|
||||
66,Amaura,,
|
||||
67,Aurorus,,
|
||||
68,Aerodactyl,,
|
||||
69,Ferroseed,,
|
||||
70,Ferrothorn,,
|
||||
71,Snubbull,,
|
||||
72,Granbull,,
|
||||
73,Electrike,,
|
||||
74,Manectric,,
|
||||
75,Houndour,,
|
||||
76,Houndoom,,
|
||||
77,Eevee,,
|
||||
78,Vaporeon,,
|
||||
79,Jolteon,,
|
||||
80,Flareon,,
|
||||
81,Espeon,,
|
||||
82,Umbreon,,
|
||||
83,Leafeon,,
|
||||
84,Glaceon,,
|
||||
85,Sylveon,,
|
||||
86,Emolga,,
|
||||
87,Yanma,,
|
||||
88,Yanmega,,
|
||||
89,Hawlucha,,
|
||||
90,Sigilyph,,
|
||||
91,Golett,,
|
||||
92,Golurk,,
|
||||
93,Nosepass,,
|
||||
94,Probopass,,
|
||||
95,Makuhita,,
|
||||
96,Hariyama,,
|
||||
97,Throh,,
|
||||
98,Sawk,,
|
||||
99,Starly,,
|
||||
100,Staravia,,
|
||||
101,Staraptor,,
|
||||
102,Stunky,,
|
||||
103,Skuntank,,
|
||||
104,Nidoran♀,,
|
||||
105,Nidorina,,
|
||||
106,Nidoqueen,,
|
||||
107,Nidoran♂,,
|
||||
108,Nidorino,,
|
||||
109,Nidoking,,
|
||||
110,Dedenne,,
|
||||
111,Chingling,,
|
||||
112,Chimecho,,
|
||||
113,Mime Jr.,,
|
||||
114,Mr. Mime,,
|
||||
115,Solosis,,
|
||||
116,Duosion,,
|
||||
117,Reuniclus,,
|
||||
118,Wynaut,,
|
||||
119,Wobbuffet,,
|
||||
120,Roggenrola,,
|
||||
121,Boldore,,
|
||||
122,Gigalith,,
|
||||
123,Sableye,,
|
||||
124,Carbink,,
|
||||
125,Tauros,,
|
||||
126,Miltank,,
|
||||
127,Mareep,,
|
||||
128,Flaaffy,,
|
||||
129,Ampharos,,
|
||||
130,Pinsir,,
|
||||
131,Heracross,,
|
||||
132,Pachirisu,,
|
||||
133,Slowpoke,,
|
||||
134,Slowbro,,
|
||||
135,Slowking,,
|
||||
136,Exeggcute,,
|
||||
137,Exeggutor,,
|
||||
138,Chatot,,
|
||||
139,Mantyke,,
|
||||
140,Mantine,,
|
||||
141,Clamperl,,
|
||||
142,Huntail,,
|
||||
143,Gorebyss,,
|
||||
144,Remoraid,,
|
||||
145,Octillery,,
|
||||
146,Corsola,,
|
||||
147,Chinchou,,
|
||||
148,Lanturn,,
|
||||
149,Alomomola,,
|
||||
150,Lapras,,
|
||||
151,Articuno,,
|
||||
152,Zapdos,,
|
||||
153,Moltres,,
|
||||
|
@@ -0,0 +1,152 @@
|
||||
dexNumber,pokemon,form,notes
|
||||
1,Diglett,,
|
||||
2,Dugtrio,,
|
||||
3,Trapinch,,
|
||||
4,Vibrava,,
|
||||
5,Flygon,,
|
||||
6,Gible,,
|
||||
7,Gabite,,
|
||||
8,Garchomp,,
|
||||
9,Geodude,,
|
||||
10,Graveler,,
|
||||
11,Golem,,
|
||||
12,Slugma,,
|
||||
13,Magcargo,,
|
||||
14,Shuckle,,
|
||||
15,Skorupi,,
|
||||
16,Drapion,,
|
||||
17,Wooper,,
|
||||
18,Quagsire,,
|
||||
19,Goomy,,
|
||||
20,Sliggoo,,
|
||||
21,Goodra,,
|
||||
22,Karrablast,,
|
||||
23,Escavalier,,
|
||||
24,Shelmet,,
|
||||
25,Accelgor,,
|
||||
26,Bellsprout,,
|
||||
27,Weepinbell,,
|
||||
28,Victreebel,,
|
||||
29,Carnivine,,
|
||||
30,Gastly,,
|
||||
31,Haunter,,
|
||||
32,Gengar,,
|
||||
33,Poliwag,,
|
||||
34,Poliwhirl,,
|
||||
35,Poliwrath,,
|
||||
36,Politoed,,
|
||||
37,Ekans,,
|
||||
38,Arbok,,
|
||||
39,Stunfisk,,
|
||||
40,Barboach,,
|
||||
41,Whiscash,,
|
||||
42,Purrloin,,
|
||||
43,Liepard,,
|
||||
44,Poochyena,,
|
||||
45,Mightyena,,
|
||||
46,Patrat,,
|
||||
47,Watchog,,
|
||||
48,Pawniard,,
|
||||
49,Bisharp,,
|
||||
50,Klefki,,
|
||||
51,Murkrow,,
|
||||
52,Honchkrow,,
|
||||
53,Foongus,,
|
||||
54,Amoonguss,,
|
||||
55,Lotad,,
|
||||
56,Lombre,,
|
||||
57,Ludicolo,,
|
||||
58,Buizel,,
|
||||
59,Floatzel,,
|
||||
60,Basculin,,
|
||||
61,Phantump,,
|
||||
62,Trevenant,,
|
||||
63,Pumpkaboo,,
|
||||
64,Gourgeist,,
|
||||
65,Litwick,,
|
||||
66,Lampent,,
|
||||
67,Chandelure,,
|
||||
68,Rotom,,
|
||||
69,Magnemite,,
|
||||
70,Magneton,,
|
||||
71,Magnezone,,
|
||||
72,Voltorb,,
|
||||
73,Electrode,,
|
||||
74,Trubbish,,
|
||||
75,Garbodor,,
|
||||
76,Swinub,,
|
||||
77,Piloswine,,
|
||||
78,Mamoswine,,
|
||||
79,Bergmite,,
|
||||
80,Avalugg,,
|
||||
81,Cubchoo,,
|
||||
82,Beartic,,
|
||||
83,Smoochum,,
|
||||
84,Jynx,,
|
||||
85,Vanillite,,
|
||||
86,Vanillish,,
|
||||
87,Vanilluxe,,
|
||||
88,Snover,,
|
||||
89,Abomasnow,,
|
||||
90,Delibird,,
|
||||
91,Sneasel,,
|
||||
92,Weavile,,
|
||||
93,Timburr,,
|
||||
94,Gurdurr,,
|
||||
95,Conkeldurr,,
|
||||
96,Torkoal,,
|
||||
97,Sandshrew,,
|
||||
98,Sandslash,,
|
||||
99,Aron,,
|
||||
100,Lairon,,
|
||||
101,Aggron,,
|
||||
102,Larvitar,,
|
||||
103,Pupitar,,
|
||||
104,Tyranitar,,
|
||||
105,Heatmor,,
|
||||
106,Durant,,
|
||||
107,Spinarak,,
|
||||
108,Ariados,,
|
||||
109,Spearow,,
|
||||
110,Fearow,,
|
||||
111,Cryogonal,,
|
||||
112,Skarmory,,
|
||||
113,Noibat,,
|
||||
114,Noivern,,
|
||||
115,Gligar,,
|
||||
116,Gliscor,,
|
||||
117,Hoothoot,,
|
||||
118,Noctowl,,
|
||||
119,Igglybuff,,
|
||||
120,Jigglypuff,,
|
||||
121,Wigglytuff,,
|
||||
122,Shuppet,,
|
||||
123,Banette,,
|
||||
124,Zorua,,
|
||||
125,Zoroark,,
|
||||
126,Gothita,,
|
||||
127,Gothorita,,
|
||||
128,Gothitelle,,
|
||||
129,Bonsly,,
|
||||
130,Sudowoodo,,
|
||||
131,Spinda,,
|
||||
132,Teddiursa,,
|
||||
133,Ursaring,,
|
||||
134,Lickitung,,
|
||||
135,Lickilicky,,
|
||||
136,Scyther,,
|
||||
137,Scizor,,
|
||||
138,Ditto,,
|
||||
139,Swablu,,
|
||||
140,Altaria,,
|
||||
141,Druddigon,,
|
||||
142,Deino,,
|
||||
143,Zweilous,,
|
||||
144,Hydreigon,,
|
||||
145,Dratini,,
|
||||
146,Dragonair,,
|
||||
147,Dragonite,,
|
||||
148,Xerneas,,
|
||||
149,Yveltal,,
|
||||
150,Zygarde,,
|
||||
151,Mewtwo,,
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
region,releaseOrder
|
||||
Kanto,1
|
||||
Johto,2
|
||||
Hoenn,3
|
||||
Orre,4
|
||||
Sinnoh,5
|
||||
Ranch,6
|
||||
Unova,7
|
||||
Kalos,8
|
||||
Alola,9
|
||||
Go,10
|
||||
Galar,11
|
||||
Home,12
|
||||
Hisui,13
|
||||
Paldea,14
|
||||
|
+8
-2
@@ -1,3 +1,9 @@
|
||||
[build]
|
||||
command = "npm run build"
|
||||
publish = "build"
|
||||
command = "npm ci && ./node_modules/.bin/supabase link --project-ref $SUPABASE_PROJECT_REF && ./node_modules/.bin/supabase db push && npm run build"
|
||||
publish = "build"
|
||||
|
||||
[build.environment]
|
||||
NODE_VERSION = "22"
|
||||
|
||||
[context.deploy-preview]
|
||||
command = "npm ci && npm run build"
|
||||
|
||||
Generated
+1862
-1027
File diff suppressed because it is too large
Load Diff
+13
-4
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "LivingDexTracker",
|
||||
"name": "livingdextracker",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npx tailwindcss -i ./static/input.css -o ./static/output.css && vite dev",
|
||||
"dev-generate": "GENERATE_SW=true npx tailwindcss -i ./static/input.css -o ./static/output.css && vite dev",
|
||||
"dev-generate-suppress-w": "GENERATE_SW=true SUPPRESS_WARNING=true npx tailwindcss -i ./static/input.css -o ./static/output.css && vite dev",
|
||||
"sprites:build": "node scripts/optimize-sprites.mjs",
|
||||
"build-generate-sw": "GENERATE_SW=true vite build",
|
||||
"build-generate-sw-node": "NODE_ADAPTER=true GENERATE_SW=true vite build",
|
||||
"build": "npx tailwindcss -i ./static/input.css -o ./static/output.css && vite build",
|
||||
@@ -23,7 +24,14 @@
|
||||
"test-generate-sw-node": "npm run build-generate-sw-node && NODE_ADAPTER=true GENERATE_SW=true vitest run && NODE_ADAPTER=true GENERATE_SW=true playwright test",
|
||||
"test-inject-manifest": "npm run build-inject-manifest && vitest run && playwright test",
|
||||
"test-inject-manifest-node": "npm run build-inject-manifest-node && NODE_ADAPTER=true vitest run && NODE_ADAPTER=true playwright test",
|
||||
"test": "npm run test-generate-sw && npm run test-generate-sw-node && npm run test-inject-manifest && npm run test-inject-manifest-node"
|
||||
"test": "npm run test-generate-sw && npm run test-generate-sw-node && npm run test-inject-manifest && npm run test-inject-manifest-node",
|
||||
"supabase:start": "supabase start",
|
||||
"supabase:stop": "supabase stop",
|
||||
"supabase:reset": "supabase db reset",
|
||||
"supabase:studio": "supabase studio",
|
||||
"migrate:convert-tsv": "node scripts/convert-tsv-to-sql.js",
|
||||
"dev:local": "./scripts/dev-local.sh && npm run dev",
|
||||
"dev:supabase": "supabase start && npm run dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.37.1",
|
||||
@@ -31,7 +39,7 @@
|
||||
"@sveltejs/adapter-netlify": "^4.1.0",
|
||||
"@sveltejs/adapter-node": "^2.0.0",
|
||||
"@sveltejs/adapter-static": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.6",
|
||||
"@sveltejs/kit": "^2.5.3",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@types/cookie": "^0.6.0",
|
||||
"@types/eslint": "^8.56.0",
|
||||
@@ -47,6 +55,8 @@
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-svelte": "^3.1.2",
|
||||
"sharp": "^0.33.4",
|
||||
"supabase": "2.72.7",
|
||||
"svelte": "^4.2.8",
|
||||
"svelte-check": "^3.6.2",
|
||||
"tailwindcss": "^3.4.3",
|
||||
@@ -58,7 +68,6 @@
|
||||
"dependencies": {
|
||||
"@supabase/ssr": "^0.1.0",
|
||||
"@supabase/supabase-js": "^2.42.0",
|
||||
"mongoose": "^8.0.3",
|
||||
"nanoid": "^5.0.4"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
Generated
+7717
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Generates SQL migration from CSV files
|
||||
* Usage: node csv-to-migration.js <Region>
|
||||
* Example: node csv-to-migration.js Kanto
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
/**
|
||||
* Parse CSV file into array of objects
|
||||
*/
|
||||
function parseCSV(filePath) {
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
const lines = content.split('\n').filter(line => line.trim());
|
||||
const headers = lines[0].split(',');
|
||||
|
||||
return lines.slice(1).map(line => {
|
||||
const values = parseCSVLine(line);
|
||||
const obj = {};
|
||||
headers.forEach((header, i) => {
|
||||
obj[header] = values[i] || null;
|
||||
});
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single CSV line, handling quoted values
|
||||
*/
|
||||
function parseCSVLine(line) {
|
||||
const values = [];
|
||||
let current = '';
|
||||
let inQuotes = false;
|
||||
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
const char = line[i];
|
||||
|
||||
if (char === '"') {
|
||||
inQuotes = !inQuotes;
|
||||
} else if (char === ',' && !inQuotes) {
|
||||
values.push(current);
|
||||
current = '';
|
||||
} else {
|
||||
current += char;
|
||||
}
|
||||
}
|
||||
values.push(current);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate migration SQL from CSV data
|
||||
*/
|
||||
function generateMigration(region) {
|
||||
console.log(`\nGenerating migration for ${region}...`);
|
||||
|
||||
// Determine generation number from region
|
||||
const regionToGen = {
|
||||
'Kanto': 1, 'Johto': 2, 'Hoenn': 3, 'Sinnoh': 4,
|
||||
'Unova': 5, 'Kalos': 6, 'Alola': 7, 'Galar': 8,
|
||||
'Hisui': 8, 'Paldea': 9
|
||||
};
|
||||
const gen = regionToGen[region] || 1;
|
||||
|
||||
// 1. Load CSV files
|
||||
const pokemonPath = path.join(__dirname, '..', 'data', 'pokemon', `gen${gen}-${region.toLowerCase()}.csv`);
|
||||
const gamesPath = path.join(__dirname, '..', 'data', 'pokemon', 'games.csv');
|
||||
|
||||
if (!fs.existsSync(pokemonPath)) {
|
||||
console.error(`Error: Pokemon CSV not found at ${pokemonPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const pokemon = parseCSV(pokemonPath);
|
||||
const games = parseCSV(gamesPath);
|
||||
|
||||
// 2. Filter for this region
|
||||
const regionGames = games.filter(g => g.region === region);
|
||||
|
||||
if (regionGames.length === 0) {
|
||||
console.error(`Error: No games found for region ${region} in games.csv`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 3. Generate SQL
|
||||
let sql = `-- Seed ${region} region Pokémon (Gen ${gen})\n`;
|
||||
sql += `-- Auto-generated from CSV files\n\n`;
|
||||
|
||||
// Region-game mappings
|
||||
sql += `-- Insert ${region} region-game mappings\n`;
|
||||
sql += `INSERT INTO region_game_mappings (region, game) VALUES\n`;
|
||||
sql += regionGames.map(g => ` ('${region}', '${g.displayName}')`).join(',\n');
|
||||
sql += `\nON CONFLICT (region, game) DO NOTHING;\n\n`;
|
||||
|
||||
// Pokemon entries (without regional dex number)
|
||||
sql += `-- Insert ${region} Pokémon entries\n`;
|
||||
sql += `INSERT INTO pokedex_entries (\n`;
|
||||
sql += ` "pokedexNumber",\n`;
|
||||
sql += ` pokemon,\n`;
|
||||
sql += ` form,\n`;
|
||||
sql += ` "canGigantamax",\n`;
|
||||
sql += ` "regionToCatchIn",\n`;
|
||||
sql += ` "gamesToCatchIn"\n`;
|
||||
sql += `) VALUES\n`;
|
||||
|
||||
const rows = pokemon.map(p => {
|
||||
const form = p.form ? `'${p.form}'` : 'NULL';
|
||||
// Use regionalDexGames for the database (regional dex availability)
|
||||
// originGames column is for future origin dex feature
|
||||
const gamesField = p.regionalDexGames || p.games; // Fallback to old 'games' column for compatibility
|
||||
const gamesList = gamesField.split('|');
|
||||
const gamesArray = `ARRAY[${gamesList.map(g => `'${g}'`).join(', ')}]`;
|
||||
|
||||
return `(${p.pokedexNumber}, '${p.name}', ${form}, false, '${region}', ${gamesArray})`;
|
||||
});
|
||||
|
||||
sql += rows.join(',\n');
|
||||
sql += '\nON CONFLICT ON CONSTRAINT unique_pokemon_form DO NOTHING;\n\n';
|
||||
|
||||
// Regional dex numbers (separate table)
|
||||
sql += `-- Insert ${region} regional dex numbers\n`;
|
||||
|
||||
const dexRows = pokemon
|
||||
.filter(p => p.regionalNumber) // Only entries with regional dex numbers
|
||||
.map(p => {
|
||||
const formCondition = p.form
|
||||
? `form = '${p.form}'`
|
||||
: `form IS NULL`;
|
||||
|
||||
return ` ((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = ${p.pokedexNumber} AND ${formCondition}), '${region}', ${p.regionalNumber})`;
|
||||
});
|
||||
|
||||
if (dexRows.length > 0) {
|
||||
sql += `INSERT INTO regional_dex_numbers (\n`;
|
||||
sql += ` pokedex_entry_id,\n`;
|
||||
sql += ` region,\n`;
|
||||
sql += ` dex_number\n`;
|
||||
sql += `) VALUES\n`;
|
||||
sql += dexRows.join(',\n');
|
||||
sql += ';\n\n';
|
||||
} else {
|
||||
sql += '-- No regional dex numbers for this region\n\n';
|
||||
}
|
||||
|
||||
// Add metadata
|
||||
sql += `-- Add metadata\n`;
|
||||
sql += `INSERT INTO metadata (key, value) VALUES\n`;
|
||||
sql += ` ('${region.toLowerCase()}_seeded', 'true'),\n`;
|
||||
sql += ` ('${region.toLowerCase()}_seed_date', NOW()::TEXT),\n`;
|
||||
sql += ` ('${region.toLowerCase()}_pokemon_count', '${pokemon.filter(p => !p.form).length}');\n`;
|
||||
|
||||
// 4. Write file
|
||||
const timestamp = new Date().toISOString().replace(/[-:T.]/g, '').slice(0, 14);
|
||||
const filename = `${timestamp}_seed_${region.toLowerCase()}.sql`;
|
||||
const outputPath = path.join(__dirname, '..', 'supabase', 'migrations', filename);
|
||||
|
||||
fs.writeFileSync(outputPath, sql);
|
||||
|
||||
console.log(`✓ Generated ${filename}`);
|
||||
console.log(` - ${pokemon.length} Pokemon entries`);
|
||||
console.log(` - ${dexRows.length} regional dex numbers`);
|
||||
console.log(` - ${regionGames.length} games\n`);
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
// Run
|
||||
const region = process.argv[2];
|
||||
if (!region) {
|
||||
console.error('Usage: node csv-to-migration.js <Region>');
|
||||
console.error('Example: node csv-to-migration.js Kanto');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
generateMigration(region);
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env node
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
import { mkdir, readdir, rename } from 'node:fs/promises';
|
||||
import sharp from 'sharp';
|
||||
|
||||
const inputDir = process.env.SPRITE_INPUT_DIR ?? path.join(process.cwd(), 'static', 'sprites');
|
||||
const outputDir =
|
||||
process.env.SPRITE_OUTPUT_DIR ?? path.join(process.cwd(), 'static', 'sprites-small');
|
||||
const format = (process.env.SPRITE_FORMAT ?? 'webp').toLowerCase();
|
||||
const quality = Number(process.env.SPRITE_QUALITY ?? 80);
|
||||
const maxSize = Number(process.env.SPRITE_MAX_SIZE ?? 0);
|
||||
|
||||
if (!['png', 'webp'].includes(format)) {
|
||||
console.error(`Unsupported SPRITE_FORMAT "${format}". Use "png" or "webp".`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
async function walk(dir, files = []) {
|
||||
const entries = await readdir(dir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
await walk(fullPath, files);
|
||||
continue;
|
||||
}
|
||||
if (entry.isFile() && entry.name.toLowerCase().endsWith('.png')) {
|
||||
files.push(fullPath);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
const files = await walk(inputDir);
|
||||
console.log(`Optimizing ${files.length} sprite images from ${inputDir}`);
|
||||
|
||||
for (const [index, file] of files.entries()) {
|
||||
const relative = path.relative(inputDir, file);
|
||||
const baseName = path.basename(file, path.extname(file));
|
||||
const targetDir = path.join(outputDir, path.dirname(relative));
|
||||
await mkdir(targetDir, { recursive: true });
|
||||
|
||||
const targetExt = format === 'png' ? '.png' : '.webp';
|
||||
const targetPath = path.join(targetDir, `${baseName}${targetExt}`);
|
||||
const tempPath = format === 'png' && outputDir === inputDir ? `${targetPath}.tmp` : targetPath;
|
||||
|
||||
const pipeline = sharp(file);
|
||||
if (maxSize > 0) {
|
||||
pipeline.resize({
|
||||
width: maxSize,
|
||||
height: maxSize,
|
||||
fit: 'inside',
|
||||
withoutEnlargement: true
|
||||
});
|
||||
}
|
||||
|
||||
if (format === 'png') {
|
||||
await pipeline.png({ compressionLevel: 9, palette: true, quality }).toFile(tempPath);
|
||||
} else {
|
||||
await pipeline.webp({ quality }).toFile(tempPath);
|
||||
}
|
||||
|
||||
if (tempPath !== targetPath) {
|
||||
await rename(tempPath, targetPath);
|
||||
}
|
||||
|
||||
if ((index + 1) % 250 === 0) {
|
||||
console.log(`Processed ${index + 1}/${files.length}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Sprite optimization complete.');
|
||||
Vendored
+6
-1
@@ -1,6 +1,7 @@
|
||||
import 'vite-plugin-pwa/svelte';
|
||||
import 'vite-plugin-pwa/info';
|
||||
import 'vite-plugin-pwa/pwa-assets';
|
||||
import { SupabaseClient, Session, User } from '@supabase/supabase-js';
|
||||
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
@@ -11,12 +12,16 @@ declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
interface Locals {
|
||||
supabase: SupabaseClient;
|
||||
safeGetSession(): Promise<{ session: Session | null; user: User | null }>;
|
||||
userid: string;
|
||||
buildDate: string;
|
||||
periodicUpdates: boolean;
|
||||
}
|
||||
|
||||
// interface PageData {}
|
||||
interface PageData {
|
||||
session: Session | null;
|
||||
}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
|
||||
+14
-1
@@ -1,9 +1,22 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="pokeball">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
const storedTheme = localStorage.getItem('theme');
|
||||
const allowed = ['pokeball', 'dark'];
|
||||
const theme = storedTheme && allowed.includes(storedTheme) ? storedTheme : 'pokeball';
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
} catch (e) {
|
||||
// Fallback to default theme if localStorage is not accessible
|
||||
document.documentElement.setAttribute('data-theme', 'pokeball');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
%sveltekit.head%
|
||||
<link rel="stylesheet" href="%sveltekit.assets%/output.css" />
|
||||
</head>
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
type InViewParams = {
|
||||
rootMargin?: string;
|
||||
threshold?: number | number[];
|
||||
once?: boolean;
|
||||
enabled?: boolean;
|
||||
onChange?: (inView: boolean, entry: IntersectionObserverEntry) => void;
|
||||
};
|
||||
|
||||
const observers = new Map<string, IntersectionObserver>();
|
||||
const callbacks = new WeakMap<Element, (entry: IntersectionObserverEntry) => void>();
|
||||
|
||||
function normalizeThreshold(threshold: number | number[] | undefined) {
|
||||
if (threshold === undefined) return [0];
|
||||
return Array.isArray(threshold) ? threshold : [threshold];
|
||||
}
|
||||
|
||||
function buildObserverKey(rootMargin: string, threshold: number | number[]) {
|
||||
return `${rootMargin}|${JSON.stringify(normalizeThreshold(threshold))}`;
|
||||
}
|
||||
|
||||
function getObserver(rootMargin: string, threshold: number | number[]) {
|
||||
const key = buildObserverKey(rootMargin, threshold);
|
||||
const existing = observers.get(key);
|
||||
if (existing) return existing;
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
const callback = callbacks.get(entry.target);
|
||||
if (callback) {
|
||||
callback(entry);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ rootMargin, threshold }
|
||||
);
|
||||
observers.set(key, observer);
|
||||
return observer;
|
||||
}
|
||||
|
||||
export function inView(node: Element, params: InViewParams = {}) {
|
||||
let options: Required<InViewParams> = {
|
||||
rootMargin: '200px 0px',
|
||||
threshold: 0,
|
||||
once: true,
|
||||
enabled: true,
|
||||
onChange: () => undefined,
|
||||
...params
|
||||
};
|
||||
|
||||
let observer = getObserver(options.rootMargin, options.threshold);
|
||||
|
||||
const handleEntry = (entry: IntersectionObserverEntry) => {
|
||||
const isIntersecting = entry.isIntersecting || entry.intersectionRatio > 0;
|
||||
options.onChange(isIntersecting, entry);
|
||||
if (isIntersecting && options.once) {
|
||||
observer.unobserve(node);
|
||||
callbacks.delete(node);
|
||||
}
|
||||
};
|
||||
|
||||
const startObserving = () => {
|
||||
callbacks.set(node, handleEntry);
|
||||
observer.observe(node);
|
||||
};
|
||||
|
||||
const stopObserving = () => {
|
||||
observer.unobserve(node);
|
||||
callbacks.delete(node);
|
||||
};
|
||||
|
||||
if (options.enabled) {
|
||||
startObserving();
|
||||
}
|
||||
|
||||
return {
|
||||
update(next: InViewParams = {}) {
|
||||
const nextOptions: Required<InViewParams> = {
|
||||
...options,
|
||||
...next,
|
||||
onChange: next.onChange ?? options.onChange
|
||||
};
|
||||
const observerKeyChanged =
|
||||
buildObserverKey(options.rootMargin, options.threshold) !==
|
||||
buildObserverKey(nextOptions.rootMargin, nextOptions.threshold);
|
||||
const enabledChanged = options.enabled !== nextOptions.enabled;
|
||||
|
||||
if (observerKeyChanged || enabledChanged) {
|
||||
stopObserving();
|
||||
}
|
||||
|
||||
options = nextOptions;
|
||||
|
||||
if (observerKeyChanged) {
|
||||
observer = getObserver(options.rootMargin, options.threshold);
|
||||
}
|
||||
|
||||
if (options.enabled) {
|
||||
startObserving();
|
||||
}
|
||||
},
|
||||
destroy() {
|
||||
stopObserving();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,100 +1,106 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import pokeApiPokemon from '$lib/helpers/pokeapi-pokemon.json';
|
||||
import { PUBLIC_USE_LOCAL_POKEMON_SPRITE_FOLDER } from '$env/static/public';
|
||||
import { inView } from '$lib/actions/inView';
|
||||
|
||||
export let pokemonName: string;
|
||||
export let pokedexNumber: string | number;
|
||||
export let form: string | undefined;
|
||||
export let spriteKey: string | undefined;
|
||||
export let shiny: boolean | undefined = false;
|
||||
export let loadingStrategy: 'eager' | 'lazy' | 'inView' = 'inView';
|
||||
|
||||
let imagePath = null as string | null;
|
||||
let blah = '';
|
||||
let isInView = false;
|
||||
|
||||
function setImagePath() {
|
||||
let rootFolder =
|
||||
function isFemaleForm(value?: string) {
|
||||
return /^female\b/i.test((value ?? '').trim());
|
||||
}
|
||||
|
||||
function buildFallbackKey() {
|
||||
const strippedPokedexNumber = pokedexNumber.toString().replace(/^0+/, '') || '0';
|
||||
if (!form) return strippedPokedexNumber;
|
||||
|
||||
let formValue = form.trim();
|
||||
formValue = formValue.replace(/^female[-\s]*/i, '');
|
||||
formValue = formValue
|
||||
.replace(/\s*\(.*?\)/g, '')
|
||||
.replace(/\s*\[.*?\]/g, '')
|
||||
.trim();
|
||||
if (!formValue || formValue.toLowerCase() === 'male') return strippedPokedexNumber;
|
||||
|
||||
formValue = formValue
|
||||
.toLowerCase()
|
||||
.replace(/%/g, '')
|
||||
.replace(/\balolan\b/g, 'alola')
|
||||
.replace(/\bgalarian\b/g, 'galar')
|
||||
.replace(/\bhisuian\b/g, 'hisui')
|
||||
.replace(/\bpaldean\b/g, 'paldea')
|
||||
.replace(/\bform(e)?$/, '')
|
||||
.replace(/\bability$/, '')
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/(^-|-$)/g, '')
|
||||
.replace(/2/g, 'two')
|
||||
.replace(/3/g, 'three')
|
||||
.replace(/4/g, 'four');
|
||||
|
||||
return formValue ? `${strippedPokedexNumber}-${formValue}` : strippedPokedexNumber;
|
||||
}
|
||||
|
||||
$: {
|
||||
const rootFolderBase =
|
||||
PUBLIC_USE_LOCAL_POKEMON_SPRITE_FOLDER === 'true'
|
||||
? '/sprites/home'
|
||||
: 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/home';
|
||||
|
||||
if (form === 'Female') {
|
||||
rootFolder += '/female';
|
||||
? '/sprites-small/home'
|
||||
: 'https://raw.githubusercontent.com/jcreek/LivingDexTracker/master/static/sprites-small/home';
|
||||
const resolvedSpriteKey = spriteKey?.trim() || buildFallbackKey();
|
||||
if (!spriteKey?.trim()) {
|
||||
console.warn('Missing sprite key for pokemon entry', {
|
||||
pokemonName,
|
||||
pokedexNumber,
|
||||
form
|
||||
});
|
||||
}
|
||||
|
||||
let rootFolder = rootFolderBase;
|
||||
if (shiny) {
|
||||
rootFolder += '/shiny';
|
||||
}
|
||||
|
||||
// Remove leading zeros
|
||||
const strippedPokedexNumber = pokedexNumber.toString().replace(/^0+/, '');
|
||||
|
||||
// Sanitise the pokemon name by making it all lowercase and replacing any spaces with hyphens and removing other characters
|
||||
let sanitisedPokemonName = pokemonName.toLowerCase().replace(/[^a-z]/g, '');
|
||||
|
||||
// Get the PokeApi id for the pokemon
|
||||
let pokeApiId;
|
||||
if (form && form.length > 0 && form !== 'Female') {
|
||||
// Sanitise the form by making it all lowercase and replacing spaces with hyphens
|
||||
let sanitisedForm = form
|
||||
.toLowerCase()
|
||||
.replaceAll(' ', '-')
|
||||
.replaceAll('2', 'two')
|
||||
.replaceAll('3', 'three')
|
||||
.replaceAll('4', 'four');
|
||||
|
||||
switch (sanitisedForm) {
|
||||
case 'alolan':
|
||||
sanitisedForm = 'alola';
|
||||
break;
|
||||
case 'galarian':
|
||||
sanitisedForm = 'galar';
|
||||
break;
|
||||
case 'hisuian':
|
||||
sanitisedForm = 'hisui';
|
||||
break;
|
||||
// case 'rainbow-ribbon':
|
||||
// sanitisedForm = 'rainbow-swirl-ribbon-sweet';
|
||||
// break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// if (strippedPokedexNumber == '869') {
|
||||
// console.log(sanitisedPokemonName, sanitisedForm);
|
||||
// }
|
||||
|
||||
// If the form is contained in the identifier, use that
|
||||
if (
|
||||
pokeApiPokemon.find(
|
||||
(pokemon) => pokemon.identifier === sanitisedPokemonName + '-' + sanitisedForm
|
||||
)
|
||||
) {
|
||||
pokeApiId = pokeApiPokemon.find(
|
||||
(pokemon) => pokemon.identifier === sanitisedPokemonName + '-' + sanitisedForm
|
||||
)?.id;
|
||||
} else {
|
||||
// If the form is not contained in the identifier, use the species_id
|
||||
pokeApiId = pokeApiPokemon.find(
|
||||
(pokemon) => pokemon.species_id.toString() === strippedPokedexNumber
|
||||
)?.id;
|
||||
}
|
||||
} else {
|
||||
pokeApiId = pokeApiPokemon.find(
|
||||
(pokemon) => pokemon.species_id.toString() === strippedPokedexNumber
|
||||
)?.id;
|
||||
if (isFemaleForm(form)) {
|
||||
rootFolder += '/female';
|
||||
}
|
||||
|
||||
imagePath = `${rootFolder}/${pokeApiId}.png`;
|
||||
blah = `${pokeApiId}.png`;
|
||||
// blah = `${strippedPokedexNumber}${form?.length && form !== 'Female' ? '-' + form : ''}.png`;
|
||||
imagePath = `${rootFolder}/${resolvedSpriteKey}.webp`;
|
||||
}
|
||||
|
||||
onMount(setImagePath);
|
||||
$: if (loadingStrategy !== 'inView') {
|
||||
isInView = true;
|
||||
}
|
||||
|
||||
function handleInView(inView: boolean) {
|
||||
if (inView) {
|
||||
isInView = true;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if imagePath}
|
||||
<!-- {blah} -->
|
||||
<img src={imagePath} alt="sprite" />
|
||||
<span
|
||||
use:inView={{
|
||||
enabled: loadingStrategy === 'inView',
|
||||
once: true,
|
||||
rootMargin: '200px 0px',
|
||||
onChange: handleInView
|
||||
}}
|
||||
>
|
||||
{#if loadingStrategy === 'inView' && !isInView}
|
||||
<span class="loading loading-spinner loading-xs"></span>
|
||||
{:else}
|
||||
<img
|
||||
src={imagePath}
|
||||
alt="sprite"
|
||||
loading={loadingStrategy === 'lazy' ? 'lazy' : 'eager'}
|
||||
decoding="async"
|
||||
/>
|
||||
{/if}
|
||||
</span>
|
||||
{:else}
|
||||
<span class="loading loading-spinner loading-xs"></span>
|
||||
{/if}
|
||||
|
||||
@@ -8,49 +8,141 @@
|
||||
|
||||
let email = '';
|
||||
let password = '';
|
||||
let isLoading = false;
|
||||
let errorMessage = '';
|
||||
|
||||
// Access the supabase client from the layout data
|
||||
export let supabase: any;
|
||||
|
||||
async function signInWithEmail() {
|
||||
// TODO use the data and error from the response
|
||||
const { data, error } = await supabase.auth
|
||||
.signInWithPassword({
|
||||
isLoading = true;
|
||||
errorMessage = '';
|
||||
|
||||
try {
|
||||
const { data, error } = await supabase.auth.signInWithPassword({
|
||||
email: email,
|
||||
password: password
|
||||
})
|
||||
.then(() => {
|
||||
emitSignedInEvent();
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error('Sign in error:', error);
|
||||
errorMessage = error.message;
|
||||
return;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
emitSignedInEvent();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Sign in error:', err);
|
||||
errorMessage = 'An unexpected error occurred. Please try again.';
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyPress(event: KeyboardEvent) {
|
||||
if (event.key === 'Enter') {
|
||||
signInWithEmail();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<label class="input input-bordered flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4 opacity-70"
|
||||
><path
|
||||
d="M2.5 3A1.5 1.5 0 0 0 1 4.5v.793c.026.009.051.02.076.032L7.674 8.51c.206.1.446.1.652 0l6.598-3.185A.755.755 0 0 1 15 5.293V4.5A1.5 1.5 0 0 0 13.5 3h-11Z"
|
||||
/><path
|
||||
d="M15 6.954 8.978 9.86a2.25 2.25 0 0 1-1.956 0L1 6.954V11.5A1.5 1.5 0 0 0 2.5 13h11a1.5 1.5 0 0 0 1.5-1.5V6.954Z"
|
||||
/></svg
|
||||
>
|
||||
<input type="text" class="grow" placeholder="Email" bind:value={email} />
|
||||
</label>
|
||||
<label class="input input-bordered flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4 opacity-70"
|
||||
><path
|
||||
fill-rule="evenodd"
|
||||
d="M14 6a4 4 0 0 1-4.899 3.899l-1.955 1.955a.5.5 0 0 1-.353.146H5v1.5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-2.293a.5.5 0 0 1 .146-.353l3.955-3.955A4 4 0 1 1 14 6Zm-4-2a.75.75 0 0 0 0 1.5.5.5 0 0 1 .5.5.75.75 0 0 0 1.5 0 2 2 0 0 0-2-2Z"
|
||||
clip-rule="evenodd"
|
||||
/></svg
|
||||
>
|
||||
<input type="password" class="grow" placeholder="Password" bind:value={password} />
|
||||
</label>
|
||||
<button class="btn btn-active btn-primary" on:click={signInWithEmail}>Sign In</button>
|
||||
<div class="space-y-4">
|
||||
<!-- Error Message -->
|
||||
{#if errorMessage}
|
||||
<div class="alert alert-error text-sm">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 shrink-0 stroke-current"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<span>{errorMessage}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Email Input -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="signin-email">
|
||||
<span class="label-text font-medium">Email</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
id="signin-email"
|
||||
type="email"
|
||||
placeholder="your@email.com"
|
||||
class="input input-bordered w-full pl-10"
|
||||
bind:value={email}
|
||||
on:keypress={handleKeyPress}
|
||||
disabled={isLoading}
|
||||
/>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="h-4 w-4 opacity-70 absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none"
|
||||
>
|
||||
<path
|
||||
d="M2.5 3A1.5 1.5 0 0 0 1 4.5v.793c.026.009.051.02.076.032L7.674 8.51c.206.1.446.1.652 0l6.598-3.185A.755.755 0 0 1 15 5.293V4.5A1.5 1.5 0 0 0 13.5 3h-11Z"
|
||||
/>
|
||||
<path
|
||||
d="M15 6.954 8.978 9.86a2.25 2.25 0 0 1-1.956 0L1 6.954V11.5A1.5 1.5 0 0 0 2.5 13h11a1.5 1.5 0 0 0 1.5-1.5V6.954Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password Input -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="signin-password">
|
||||
<span class="label-text font-medium">Password</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
id="signin-password"
|
||||
type="password"
|
||||
placeholder="••••••••"
|
||||
class="input input-bordered w-full pl-10"
|
||||
bind:value={password}
|
||||
on:keypress={handleKeyPress}
|
||||
disabled={isLoading}
|
||||
/>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="h-4 w-4 opacity-70 absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M14 6a4 4 0 0 1-4.899 3.899l-1.955 1.955a.5.5 0 0 1-.353.146H5v1.5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-2.293a.5.5 0 0 1 .146-.353l3.955-3.955A4 4 0 1 1 14 6Zm-4-2a.75.75 0 0 0 0 1.5.5.5 0 0 1 .5.5.75.75 0 0 0 1.5 0 2 2 0 0 0-2-2Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sign In Button -->
|
||||
<div class="form-control mt-6">
|
||||
<button
|
||||
class="btn btn-primary w-full"
|
||||
on:click={signInWithEmail}
|
||||
disabled={isLoading || !email || !password}
|
||||
>
|
||||
{#if isLoading}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
Signing in...
|
||||
{:else}
|
||||
Sign In
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let email = '';
|
||||
let password = '';
|
||||
|
||||
@@ -17,23 +20,29 @@
|
||||
});
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
console.error('Sign up error:', error);
|
||||
alert(`Sign up failed: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle success (optional)
|
||||
} catch (error) {
|
||||
console.error('Sign up error:', error.message);
|
||||
// Handle error
|
||||
if (data) {
|
||||
// Emit signedUp event to notify parent component
|
||||
dispatch('signedUp', {});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Sign up error:', err);
|
||||
alert('Sign up failed');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form class="card-body">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<label class="label" for="signup-email">
|
||||
<span class="label-text">Email</span>
|
||||
</label>
|
||||
<input
|
||||
id="signup-email"
|
||||
type="email"
|
||||
placeholder="email"
|
||||
class="input input-bordered"
|
||||
@@ -42,10 +51,11 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<label class="label" for="signup-password">
|
||||
<span class="label-text">Password</span>
|
||||
</label>
|
||||
<input
|
||||
id="signup-password"
|
||||
type="password"
|
||||
placeholder="password"
|
||||
class="input input-bordered"
|
||||
@@ -54,6 +64,12 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="form-control mt-6">
|
||||
<button class="btn btn btn-primary" on:click={signUpNewUser}>Sign Up</button>
|
||||
<button class="btn btn-primary" on:click={signUpNewUser}>Sign Up</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
.card-body {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
<script lang="ts">
|
||||
import { theme, applyTheme } from '$lib/stores/theme.js';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let currentTheme: 'pokeball' | 'dark' = 'pokeball';
|
||||
|
||||
// Subscribe to theme changes
|
||||
$: (currentTheme = $theme), applyTheme($theme);
|
||||
|
||||
onMount(() => {
|
||||
// Initialize theme from localStorage
|
||||
theme.init();
|
||||
});
|
||||
|
||||
function toggleTheme() {
|
||||
theme.toggle();
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="btn btn-ghost btn-circle"
|
||||
on:click={toggleTheme}
|
||||
aria-label="Toggle dark mode"
|
||||
title="Toggle dark mode"
|
||||
>
|
||||
{#if currentTheme === 'pokeball'}
|
||||
<!-- Sun icon for light mode (clicking will switch to dark) -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"
|
||||
/>
|
||||
</svg>
|
||||
{:else}
|
||||
<!-- Moon icon for dark mode (clicking will switch to light) -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
@@ -7,14 +7,16 @@
|
||||
</script>
|
||||
|
||||
<div class="relative inline-block">
|
||||
<div
|
||||
class="tooltip-trigger cursor-pointer"
|
||||
<button
|
||||
type="button"
|
||||
class="tooltip-trigger cursor-pointer bg-transparent border-0 p-0 appearance-none"
|
||||
aria-expanded={show}
|
||||
on:click={handleClick}
|
||||
on:mouseenter={() => (show = true)}
|
||||
on:mouseleave={() => (show = false)}
|
||||
>
|
||||
<slot name="hover-target" />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{#if show}
|
||||
<div class="tooltip-content absolute z-10 mt-2 w-52">
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<script lang="ts">
|
||||
import type { Pokedex } from '$lib/models/Pokedex';
|
||||
|
||||
export let pokedex: Pokedex;
|
||||
export let onEdit: () => void;
|
||||
export let onDelete: () => void;
|
||||
export let onView: () => void;
|
||||
|
||||
// Get active type badges
|
||||
$: typeBadges = [
|
||||
pokedex.isLivingDex && 'Living',
|
||||
pokedex.isShinyDex && 'Shiny',
|
||||
pokedex.isOriginDex && 'Origin',
|
||||
pokedex.isFormDex && 'Form'
|
||||
].filter(Boolean);
|
||||
</script>
|
||||
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">
|
||||
{pokedex.name}
|
||||
</h2>
|
||||
|
||||
{#if pokedex.description}
|
||||
<p class="text-sm">{pokedex.description}</p>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-wrap gap-2 my-2">
|
||||
{#each typeBadges as badge}
|
||||
<span class="badge badge-primary">{badge}</span>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{#if pokedex.gameScope}
|
||||
<div class="text-sm text-base-content/70">
|
||||
<span class="font-semibold">Game:</span>
|
||||
{pokedex.gameScope}
|
||||
</div>
|
||||
{#if pokedex.dexScopes?.length}
|
||||
<div class="text-sm text-base-content/70">
|
||||
<span class="font-semibold">Dexes:</span>
|
||||
{pokedex.dexScopes.length}
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="text-sm text-base-content/70">
|
||||
<span class="font-semibold">Scope:</span> All Games
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="card-actions justify-end mt-4">
|
||||
<button class="btn btn-sm btn-ghost" on:click={onEdit}>Edit</button>
|
||||
<button class="btn btn-sm btn-error btn-outline" on:click={onDelete}>Delete</button>
|
||||
<button class="btn btn-sm btn-primary" on:click={onView}>View</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,20 +1,62 @@
|
||||
<script lang="ts">
|
||||
import type { CatchRecord } from '$lib/models/CatchRecord';
|
||||
import type { PokedexEntry } from '$lib/models/PokedexEntry';
|
||||
import type { CatchInformationItem, PokedexEntry } from '$lib/models/PokedexEntry';
|
||||
import PokemonSprite from '../PokemonSprite.svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
export let pokedexEntry: PokedexEntry;
|
||||
export let catchRecord: CatchRecord;
|
||||
export let catchRecord: CatchRecord | null;
|
||||
export let showOrigins: boolean;
|
||||
export let showForms: boolean;
|
||||
export let showShiny: boolean;
|
||||
export let userId: string | null = null;
|
||||
export let pokedexId: string;
|
||||
|
||||
// Create a default catch record if none exists
|
||||
$: if (!catchRecord) {
|
||||
catchRecord = {
|
||||
_id: '', // Empty string, not temp ID - will be created by server
|
||||
userId: userId || '',
|
||||
pokemonId: pokedexEntry._id,
|
||||
pokedexId: pokedexId,
|
||||
haveToEvolve: false,
|
||||
caught: false,
|
||||
inHome: false,
|
||||
hasGigantamaxed: false,
|
||||
personalNotes: ''
|
||||
};
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function updateCatchRecord() {
|
||||
dispatch('updateCatch', { pokedexEntry, catchRecord });
|
||||
type UpdateCatchSource = 'toggle' | 'notes' | 'notes-blur';
|
||||
|
||||
const isCatchInformationItem = (
|
||||
value: string | CatchInformationItem
|
||||
): value is CatchInformationItem => typeof value !== 'string';
|
||||
|
||||
function updateCatchRecord(source: UpdateCatchSource) {
|
||||
dispatch('updateCatch', { pokedexEntry, catchRecord, source });
|
||||
}
|
||||
|
||||
function onCaughtChange() {
|
||||
if (!catchRecord) return;
|
||||
// Mutually exclusive with "needs to evolve"
|
||||
if (catchRecord.caught) {
|
||||
catchRecord.haveToEvolve = false;
|
||||
}
|
||||
updateCatchRecord('toggle');
|
||||
}
|
||||
|
||||
function onNeedsToEvolveChange() {
|
||||
if (!catchRecord) return;
|
||||
// Mutually exclusive with "caught"
|
||||
if (catchRecord.haveToEvolve) {
|
||||
catchRecord.caught = false;
|
||||
}
|
||||
updateCatchRecord('toggle');
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -22,123 +64,116 @@
|
||||
>
|
||||
<div class="dex-column pokedex-entry-container">
|
||||
<div class="flex mb-2">
|
||||
<div class="sprite-container flex justify-center items-center bg-white rounded-lg p-2">
|
||||
<div class="pl-2">
|
||||
<h3 class="text-xl font-bold pt-1">{pokedexEntry.pokemon}</h3>
|
||||
<sub class="text-primary-content/80"
|
||||
>#{pokedexEntry.pokedexNumber.toString().padStart(3, '0')}</sub
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex mb-2">
|
||||
<div class="sprite-container flex justify-center items-center bg-base-100 rounded-lg p-2">
|
||||
<PokemonSprite
|
||||
pokemonName={pokedexEntry.pokemon}
|
||||
pokedexNumber={pokedexEntry.pokedexNumber}
|
||||
form={pokedexEntry.form}
|
||||
spriteKey={pokedexEntry.spriteKey}
|
||||
shiny={showShiny}
|
||||
/>
|
||||
</div>
|
||||
<div class="pl-2">
|
||||
<h3 class="text-xl font-bold pt-1 text-secondary">{pokedexEntry.pokemon}</h3>
|
||||
<sub class="text-gray-200">#{pokedexEntry.pokedexNumber.toString().padStart(3, '0')}</sub>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if showForms}
|
||||
<div class="bg-white text-black rounded-lg p-4 mb-2">
|
||||
<div class="bg-base-100 text-base-content rounded-lg p-4 mb-2">
|
||||
<p><strong>Form:</strong> {pokedexEntry.form ? pokedexEntry.form : '-'}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="bg-white text-black rounded-lg p-4">
|
||||
{#if showForms}
|
||||
<p><strong>Box:</strong> {pokedexEntry.boxPlacementForms.box}</p>
|
||||
<p><strong>Row:</strong> {pokedexEntry.boxPlacementForms.row}</p>
|
||||
<p><strong>Column:</strong> {pokedexEntry.boxPlacementForms.column}</p>
|
||||
<p><strong>Can Gigantamax:</strong> {pokedexEntry.canGigantamax ? 'Yes' : 'No'}</p>
|
||||
{:else}
|
||||
<p><strong>Box:</strong> {pokedexEntry.boxPlacement.box}</p>
|
||||
<p><strong>Row:</strong> {pokedexEntry.boxPlacement.row}</p>
|
||||
<p><strong>Column:</strong> {pokedexEntry.boxPlacement.column}</p>
|
||||
{/if}
|
||||
|
||||
{#if pokedexEntry.evolutionInformation}
|
||||
{#if pokedexEntry.evolutionInformation.trim().length > 0}
|
||||
<div class="bg-base-100 text-base-content rounded-lg p-4">
|
||||
<p><strong>How to evolve: </strong>{pokedexEntry.evolutionInformation}</p>
|
||||
{:else}
|
||||
<p>
|
||||
<strong>How to evolve: </strong>Currently missing - can you
|
||||
<a
|
||||
href="https://github.com/jcreek/LivingDexTracker"
|
||||
class="underline text-primary hover:text-secondary">help contribute</a
|
||||
>?
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="dex-column catch-record-container bg-white text-black rounded-lg p-4 mb-4 md:mb-0">
|
||||
<div class="flex items-center">
|
||||
<div class="form-control">
|
||||
<label class="cursor-pointer label">
|
||||
<span class="block font-bold mr-2">Caught:</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={catchRecord.caught}
|
||||
class="checkbox checkbox-primary border-black"
|
||||
on:change={updateCatchRecord}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="form-control">
|
||||
<label class="cursor-pointer label">
|
||||
<span class="block font-bold mr-2">Needs to evolve:</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={catchRecord.haveToEvolve}
|
||||
class="checkbox checkbox-primary border-black"
|
||||
on:change={updateCatchRecord}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="form-control">
|
||||
<label class="cursor-pointer label">
|
||||
<span class="block font-bold mr-2">In home:</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={catchRecord.inHome}
|
||||
class="checkbox checkbox-primary border-black"
|
||||
on:change={updateCatchRecord}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{#if pokedexEntry.canGigantamax && showForms}
|
||||
{#if catchRecord}
|
||||
<div
|
||||
class="dex-column catch-record-container bg-base-100 text-base-content rounded-lg p-4 mb-4 md:mb-0"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<div class="form-control">
|
||||
<label class="cursor-pointer label">
|
||||
<span class="block font-bold mr-2">Has Gigantamaxed:</span>
|
||||
<span class="block font-bold mr-2">Caught:</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={catchRecord.hasGigantamaxed}
|
||||
class="checkbox checkbox-primary border-black"
|
||||
on:change={updateCatchRecord}
|
||||
bind:checked={catchRecord.caught}
|
||||
class="checkbox checkbox-primary"
|
||||
on:change={onCaughtChange}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<p>
|
||||
<label class="block font-bold mb-1" for={`personalNotesInput-${catchRecord._id}`}
|
||||
>Notes:</label
|
||||
>
|
||||
<textarea
|
||||
bind:value={catchRecord.personalNotes}
|
||||
id={`personalNotesInput-${catchRecord._id}`}
|
||||
class="form-textarea w-full p-2 border rounded"
|
||||
on:change={updateCatchRecord}
|
||||
></textarea>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="form-control">
|
||||
<label class="cursor-pointer label">
|
||||
<span class="block font-bold mr-2">Needs to evolve:</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={catchRecord.haveToEvolve}
|
||||
class="checkbox checkbox-primary"
|
||||
on:change={onNeedsToEvolveChange}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="form-control">
|
||||
<label class="cursor-pointer label">
|
||||
<span class="block font-bold mr-2">In Home:</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={catchRecord.inHome}
|
||||
class="checkbox checkbox-primary"
|
||||
on:change={() => updateCatchRecord('toggle')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{#if pokedexEntry.canGigantamax && showForms}
|
||||
<div class="flex items-center">
|
||||
<div class="form-control">
|
||||
<label class="cursor-pointer label">
|
||||
<span class="block font-bold mr-2">Has Gigantamaxed:</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={catchRecord.hasGigantamaxed}
|
||||
class="checkbox checkbox-primary"
|
||||
on:change={() => updateCatchRecord('toggle')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<p>
|
||||
<label
|
||||
class="block font-bold mb-1"
|
||||
for={`personalNotesInput-${catchRecord._id || pokedexEntry._id}`}>Notes:</label
|
||||
>
|
||||
<textarea
|
||||
bind:value={catchRecord.personalNotes}
|
||||
id={`personalNotesInput-${catchRecord._id || pokedexEntry._id}`}
|
||||
class="textarea textarea-bordered w-full"
|
||||
style="min-height: 120px;"
|
||||
on:input={() => updateCatchRecord('notes')}
|
||||
on:change={() => updateCatchRecord('notes-blur')}
|
||||
></textarea>
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="dex-column additional-details-container">
|
||||
{#if showOrigins}
|
||||
<div class="bg-white text-black rounded-lg p-4 mb-2">
|
||||
<div class="bg-base-100 text-base-content rounded-lg p-4 mb-2">
|
||||
<h3 class="text-xl font-semibold mb-4">Origin Dex Requirements</h3>
|
||||
<p><strong>Region to Catch In:</strong> {pokedexEntry.regionToCatchIn}</p>
|
||||
<p><strong>Games to catch in:</strong></p>
|
||||
@@ -153,16 +188,20 @@
|
||||
</div>
|
||||
{/if}
|
||||
{#if pokedexEntry.catchInformation.length > 0}
|
||||
<div class="bg-white text-black rounded-lg p-4 mb-2">
|
||||
<div class="bg-base-100 text-base-content rounded-lg p-4 mb-2">
|
||||
<p><strong>Where to catch: </strong></p>
|
||||
<ul class="list-disc list-inside">
|
||||
{#each pokedexEntry.catchInformation as info}
|
||||
<li>
|
||||
<ul>
|
||||
<li><strong>Game:</strong> {info.game}</li>
|
||||
<li><strong>Location:</strong> {info.location}</li>
|
||||
<li><strong>Notes:</strong> {info.notes}</li>
|
||||
</ul>
|
||||
{#if isCatchInformationItem(info)}
|
||||
<ul>
|
||||
<li><strong>Game:</strong> {info.game}</li>
|
||||
<li><strong>Location:</strong> {info.location}</li>
|
||||
<li><strong>Notes:</strong> {info.notes}</li>
|
||||
</ul>
|
||||
{:else}
|
||||
{info}
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
@@ -175,7 +214,7 @@
|
||||
</p>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="bg-white text-black rounded-lg p-4 mb-2">
|
||||
<div class="bg-base-100 text-base-content rounded-lg p-4 mb-2">
|
||||
<p>
|
||||
<strong>Where to catch: </strong>Currently missing - can you
|
||||
<a
|
||||
@@ -185,39 +224,22 @@
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if pokedexEntry.notes}
|
||||
<div class="bg-base-100 text-base-content rounded-lg p-4 mb-2">
|
||||
<p><strong>Dex Notes:</strong> {pokedexEntry.notes}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.dex-column {
|
||||
width: 300px;
|
||||
flex: 1;
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.sprite-container {
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
|
||||
.form-checkbox {
|
||||
appearance: none;
|
||||
background-color: #fff;
|
||||
border: 2px solid #000;
|
||||
border-radius: 0.25rem;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-checkbox:checked {
|
||||
background-color: #00bfff;
|
||||
background-size: 100% 100%;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
min-height: 3rem;
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import type { Pokedex } from '$lib/models/Pokedex';
|
||||
|
||||
export let pokedex: Partial<Pokedex> = {
|
||||
name: '',
|
||||
description: '',
|
||||
isLivingDex: false,
|
||||
isShinyDex: false,
|
||||
isOriginDex: false,
|
||||
isFormDex: false,
|
||||
gameScope: null,
|
||||
dexScopes: []
|
||||
};
|
||||
export let mode: 'create' | 'edit' = 'create';
|
||||
export let onSubmit: () => void;
|
||||
export let onCancel: () => void;
|
||||
|
||||
type GameDex = {
|
||||
id: string;
|
||||
displayName: string;
|
||||
sortOrder: number;
|
||||
isDlc: boolean;
|
||||
parentDexId: string | null;
|
||||
};
|
||||
type GameSummary = {
|
||||
displayName: string;
|
||||
releaseYear: number;
|
||||
};
|
||||
|
||||
let gameDexes: Record<string, GameDex[]> = {};
|
||||
let gameOrder: string[] = [];
|
||||
let gameList: GameSummary[] = [];
|
||||
let availableDexes: GameDex[] = [];
|
||||
let loadingDexes = true;
|
||||
let lastGameScope: string | null = null;
|
||||
let dexScopesInitialized = false;
|
||||
let hasSeenGameScope = false;
|
||||
|
||||
// Fetch available game dexes from the database
|
||||
onMount(async () => {
|
||||
try {
|
||||
const response = await fetch('/api/game-dexes');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
gameDexes = data.gameDexes || {};
|
||||
gameOrder = data.gameOrder || Object.keys(gameDexes);
|
||||
gameList = data.games || [];
|
||||
} else {
|
||||
console.error('Failed to fetch game dexes');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching game dexes:', error);
|
||||
} finally {
|
||||
loadingDexes = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Validation
|
||||
$: hasAtLeastOneType =
|
||||
pokedex.isLivingDex || pokedex.isShinyDex || pokedex.isOriginDex || pokedex.isFormDex;
|
||||
$: hasDexScope =
|
||||
!pokedex.gameScope || (pokedex.dexScopes && pokedex.dexScopes.length > 0);
|
||||
$: canSubmit =
|
||||
pokedex.name && pokedex.name.trim() !== '' && hasAtLeastOneType && hasDexScope;
|
||||
|
||||
$: if (pokedex.gameScope !== lastGameScope) {
|
||||
const shouldResetDexes = mode === 'create' || hasSeenGameScope;
|
||||
lastGameScope = pokedex.gameScope || null;
|
||||
dexScopesInitialized = false;
|
||||
if (shouldResetDexes) {
|
||||
pokedex.dexScopes = [];
|
||||
}
|
||||
if (!pokedex.gameScope) {
|
||||
availableDexes = [];
|
||||
}
|
||||
hasSeenGameScope = true;
|
||||
}
|
||||
|
||||
$: if (!loadingDexes && pokedex.gameScope) {
|
||||
availableDexes = gameDexes[pokedex.gameScope] || [];
|
||||
if (!dexScopesInitialized) {
|
||||
if (!pokedex.dexScopes || pokedex.dexScopes.length === 0) {
|
||||
pokedex.dexScopes = availableDexes.map((dex) => dex.id);
|
||||
}
|
||||
dexScopesInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
if (canSubmit) {
|
||||
onSubmit();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="form-control w-full">
|
||||
<label class="label" for="pokedex-name">
|
||||
<span class="label-text">Name</span>
|
||||
</label>
|
||||
<input
|
||||
id="pokedex-name"
|
||||
type="text"
|
||||
placeholder="My Living Dex"
|
||||
class="input input-bordered w-full"
|
||||
bind:value={pokedex.name}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control w-full">
|
||||
<label class="label" for="pokedex-description">
|
||||
<span class="label-text">Description (optional)</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="pokedex-description"
|
||||
class="textarea textarea-bordered h-24"
|
||||
placeholder="Describe your pokédex..."
|
||||
bind:value={pokedex.description}
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-control w-full">
|
||||
<fieldset class="w-full">
|
||||
<legend class="label">
|
||||
<span class="label-text">Type(s)</span>
|
||||
<span class="label-text-alt text-error"
|
||||
>{!hasAtLeastOneType ? 'At least one type required' : ''}</span
|
||||
>
|
||||
</legend>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox" class="checkbox" bind:checked={pokedex.isLivingDex} />
|
||||
<span class="label-text">Living Dex (one of each Pokémon)</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox" class="checkbox" bind:checked={pokedex.isShinyDex} />
|
||||
<span class="label-text">Shiny Dex (shiny variants only)</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox" class="checkbox" bind:checked={pokedex.isOriginDex} />
|
||||
<span class="label-text">Origin Dex (caught in native regions)</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox" class="checkbox" bind:checked={pokedex.isFormDex} />
|
||||
<span class="label-text">Form Dex (all forms included)</span>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="form-control w-full">
|
||||
<label class="label" for="game-scope">
|
||||
<span class="label-text">Game Scope</span>
|
||||
</label>
|
||||
<select
|
||||
id="game-scope"
|
||||
class="select select-bordered"
|
||||
bind:value={pokedex.gameScope}
|
||||
disabled={loadingDexes}
|
||||
>
|
||||
<option value={null}>All Games</option>
|
||||
{#if loadingDexes}
|
||||
<option disabled>Loading games...</option>
|
||||
{:else}
|
||||
{#if gameList.length > 0}
|
||||
{#each gameList as game}
|
||||
<option value={game.displayName}>{game.displayName}</option>
|
||||
{/each}
|
||||
{:else}
|
||||
{#each gameOrder.length > 0 ? gameOrder : Object.keys(gameDexes) as game}
|
||||
<option value={game}>{game}</option>
|
||||
{/each}
|
||||
{/if}
|
||||
{/if}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{#if pokedex.gameScope}
|
||||
<div class="form-control w-full">
|
||||
<fieldset class="w-full">
|
||||
<legend class="label">
|
||||
<span class="label-text">Dex Scope</span>
|
||||
<span class="label-text-alt text-error">{!hasDexScope ? 'Select at least one dex' : ''}</span>
|
||||
</legend>
|
||||
{#if availableDexes.length === 0}
|
||||
<p class="text-sm text-error">No dexes found for this game.</p>
|
||||
{:else}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each availableDexes as dex}
|
||||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
value={dex.id}
|
||||
bind:group={pokedex.dexScopes}
|
||||
/>
|
||||
<span class="label-text">{dex.displayName}</span>
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</fieldset>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="modal-action">
|
||||
<button class="btn btn-ghost" type="button" on:click={onCancel}>Cancel</button>
|
||||
<button class="btn btn-primary" type="button" on:click={handleSubmit} disabled={!canSubmit}>
|
||||
{mode === 'create' ? 'Create' : 'Save'}
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,111 @@
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
|
||||
export let isOpen: boolean;
|
||||
export let onClose: () => void;
|
||||
|
||||
function handleBackdropClick() {
|
||||
onClose();
|
||||
}
|
||||
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape' && isOpen) {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if isOpen}
|
||||
<div class="modal modal-open" role="dialog" aria-modal="true">
|
||||
<div class="modal-box-custom bg-primary text-primary-content">
|
||||
<button class="close-button" on:click={onClose} aria-label="Close"> ✕ </button>
|
||||
<div class="modal-content">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="modal-backdrop bg-black/50"
|
||||
aria-label="Close modal"
|
||||
on:click={handleBackdropClick}
|
||||
></button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.modal-box-custom {
|
||||
max-width: 72rem;
|
||||
width: 100%;
|
||||
max-height: 90vh;
|
||||
border: none;
|
||||
box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.5);
|
||||
outline: none;
|
||||
position: relative;
|
||||
border-radius: 1rem;
|
||||
padding: 0.5rem;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
top: 1rem;
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
color: white;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s;
|
||||
z-index: 10;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.close-button:hover {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Remove margin and background from card inside modal */
|
||||
.modal-content :global(.dex-entry) {
|
||||
margin-bottom: 0;
|
||||
background-color: transparent !important;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.modal-box-custom {
|
||||
width: 91.666667%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,129 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Pagination from '$lib/components/Pagination.svelte';
|
||||
|
||||
export let viewAsBoxes = false;
|
||||
export let currentPage = 1;
|
||||
export let itemsPerPage = 20;
|
||||
export let totalPages = 0;
|
||||
export let showForms = true;
|
||||
export let showOrigins = true;
|
||||
export let showShiny = false;
|
||||
export let catchRegion = '';
|
||||
export let catchGame = '';
|
||||
export let toggleForms = () => {};
|
||||
export let toggleOrigins = () => {};
|
||||
export let toggleShiny = () => {};
|
||||
export let getData = () => {};
|
||||
export let toggleViewAsBoxes = () => {};
|
||||
</script>
|
||||
|
||||
<aside
|
||||
class="menu bg-gray-800 text-white min-h-full w-64 p-4 lg:fixed xs:top-0 lg:left-0 h-full lg:h-5/6"
|
||||
>
|
||||
<h2 class="text-2xl font-semibold mb-4">Views</h2>
|
||||
<ul>
|
||||
<li class="mb-2">
|
||||
<button class="block p-2 hover:bg-gray-700 rounded" on:click={toggleViewAsBoxes}>
|
||||
{viewAsBoxes ? 'Switch to List View' : 'Switch to Box View'}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 class="text-2xl font-semibold mb-4">Filters</h2>
|
||||
<ul>
|
||||
<li class="mb-2">
|
||||
<button class="block p-2 hover:bg-gray-700 rounded" on:click={toggleForms}>
|
||||
Toggle Forms (Currently {showForms ? 'On' : 'Off'})
|
||||
</button>
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<button class="block p-2 hover:bg-gray-700 rounded" on:click={toggleOrigins}>
|
||||
Toggle Origins (Currently {showOrigins ? 'On' : 'Off'})
|
||||
</button>
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<button class="block p-2 hover:bg-gray-700 rounded" on:click={toggleShiny}>
|
||||
Toggle Shiny (Currently {showShiny ? 'On' : 'Off'})
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="mb-4">
|
||||
<label for="catchRegionSelect">Region to catch in:</label>
|
||||
<select
|
||||
id="catchRegionSelect"
|
||||
class="select select-bordered w-full max-w-xs text-black"
|
||||
bind:value={catchRegion}
|
||||
on:change={getData}
|
||||
>
|
||||
<option value="">All</option>
|
||||
<option value="Kanto">Kanto (Red, Blue, Yellow, LG: Pikachu, LG: Eevee)</option>
|
||||
<option value="Johto">Johto (Gold, Silver, Crystal, HG, SS)</option>
|
||||
<option value="Hoenn">Hoenn (Ruby, Sapphire, Emerald, OR, AS)</option>
|
||||
<option value="Sinnoh">Sinnoh (Diamond, Pearl, Platinum, BD, SP)</option>
|
||||
<option value="Unova">Unova (Black, White, Black2, White2, Dream Radar)</option>
|
||||
<option value="Kalos">Kalos (X, Y)</option>
|
||||
<option value="Alola">Alola (Sun, Moon, Moon Demo, US, UM)</option>
|
||||
<option value="Galar">Galar (Sword, Shield)</option>
|
||||
<option value="Hisui">Hisui (PLA)</option>
|
||||
<option value="Paldea">Paldea (Scarlet, Violet)</option>
|
||||
<option value="Unknown">Unknown (Home, Go)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="catchGameSelect">Game to catch in: {catchGame}</label>
|
||||
<select
|
||||
id="catchGameSelect"
|
||||
class="select select-bordered w-full max-w-xs text-black"
|
||||
bind:value={catchGame}
|
||||
on:change={getData}
|
||||
>
|
||||
<option value="">All</option>
|
||||
<option value="Red">Red (Kanto)</option>
|
||||
<option value="Blue">Blue (Kanto)</option>
|
||||
<option value="Yellow">Yellow (Kanto)</option>
|
||||
<option value="LG: Pikachu">LG: Pikachu (Kanto)</option>
|
||||
<option value="LG: Eevee">LG: Eevee (Kanto)</option>
|
||||
<option value="Gold">Gold (Johto)</option>
|
||||
<option value="Silver">Silver (Johto)</option>
|
||||
<option value="Crystal">Crystal (Johto)</option>
|
||||
<option value="HG">HG (Johto)</option>
|
||||
<option value="SS">SS (Johto)</option>
|
||||
<option value="Ruby">Ruby (Hoenn)</option>
|
||||
<option value="Sapphire">Sapphire (Hoenn)</option>
|
||||
<option value="Emerald">Emerald (Hoenn)</option>
|
||||
<option value="OR">OR (Hoenn)</option>
|
||||
<option value="AS">AS (Hoenn)</option>
|
||||
<option value="Diamond">Diamond (Sinnoh)</option>
|
||||
<option value="Pearl">Pearl (Sinnoh)</option>
|
||||
<option value="Platinum">Platinum (Sinnoh)</option>
|
||||
<option value="BD">BD (Sinnoh)</option>
|
||||
<option value="SP">SP (Sinnoh)</option>
|
||||
<option value="Black">Black (Unova)</option>
|
||||
<option value="White">White (Unova)</option>
|
||||
<option value="Black2">Black2 (Unova)</option>
|
||||
<option value="White2">White2 (Unova)</option>
|
||||
<option value="Dream Radar">Dream Radar (Unova)</option>
|
||||
<option value="X">X (Kalos)</option>
|
||||
<option value="Y">Y (Kalos)</option>
|
||||
<option value="Sun">Sun (Alola)</option>
|
||||
<option value="Moon">Moon (Alola)</option>
|
||||
<option value="Moon Demo">Moon Demo (Alola)</option>
|
||||
<option value="US">US (Alola)</option>
|
||||
<option value="UM">UM (Alola)</option>
|
||||
<option value="Sword">Sword (Galar)</option>
|
||||
<option value="Shield">Shield (Galar)</option>
|
||||
<option value="PLA">PLA (Hisui)</option>
|
||||
<option value="Scarlet">Scarlet (Paldea)</option>
|
||||
<option value="Violet">Violet (Paldea)</option>
|
||||
<option value="Home">Home (Unknown)</option>
|
||||
<option value="Go">Go (Unknown)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{#if !viewAsBoxes}
|
||||
<h2 class="text-2xl font-semibold mb-4">Paging</h2>
|
||||
<div>
|
||||
<Pagination bind:currentPage bind:itemsPerPage bind:totalPages />
|
||||
</div>
|
||||
{/if}
|
||||
</aside>
|
||||
@@ -1,14 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import type { CatchRecord } from '$lib/models/CatchRecord';
|
||||
import type { CombinedData } from '$lib/models/CombinedData';
|
||||
import type { PokedexEntry } from '$lib/models/PokedexEntry';
|
||||
import { calculateBoxPlacement } from '$lib/utils/boxPlacement';
|
||||
import PokemonSprite from '$lib/components/PokemonSprite.svelte';
|
||||
import Tooltip from '$lib/components/Tooltip.svelte';
|
||||
|
||||
export let showShiny = false;
|
||||
export let combinedData: CombinedData[] | null;
|
||||
export let boxNumbers = Array<number>;
|
||||
export let currentPlacement = 'boxPlacementForms';
|
||||
export let boxNumbers: number[] = [];
|
||||
export let creatingRecords = false;
|
||||
export let totalRecordsCreated = 0;
|
||||
export let failedToLoad = false;
|
||||
@@ -18,77 +18,522 @@
|
||||
export let markBoxAsInHome = (boxNumber: number) => {};
|
||||
export let markBoxAsNotInHome = (boxNumber: number) => {};
|
||||
export let createCatchRecords = () => {};
|
||||
export let onPokemonClick: (pokemon: CombinedData) => void = () => {};
|
||||
|
||||
function cellBackgroundColourClass(catchRecord: CatchRecord) {
|
||||
if (catchRecord.caught) {
|
||||
return 'bg-green-100/50';
|
||||
} else if (catchRecord.haveToEvolve) {
|
||||
return 'bg-yellow-100/50';
|
||||
} else {
|
||||
return '';
|
||||
let filterNotCaught = false;
|
||||
let filterNeedsToEvolve = false;
|
||||
let filterInHome = false;
|
||||
let filterNotInHome = false;
|
||||
|
||||
// Bulk actions menu state (one open menu at a time)
|
||||
let openBulkMenuForBox: number | null = null;
|
||||
|
||||
onMount(() => {
|
||||
const close = () => {
|
||||
openBulkMenuForBox = null;
|
||||
};
|
||||
window.addEventListener('click', close);
|
||||
return () => window.removeEventListener('click', close);
|
||||
});
|
||||
|
||||
let filteredCombinedData: CombinedData[] = [];
|
||||
let filteredTotal = 0;
|
||||
let overallTotal = 0;
|
||||
let overallCaughtCount = 0;
|
||||
let overallNotCaughtCount = 0;
|
||||
let overallNeedsToEvolveCount = 0;
|
||||
let overallInHomeCount = 0;
|
||||
let overallNotInHomeCount = 0;
|
||||
let filtersActive = false;
|
||||
let filtersKey = '';
|
||||
|
||||
function normalizedStatus(catchRecord: CatchRecord | null) {
|
||||
return {
|
||||
caught: !!catchRecord?.caught,
|
||||
needsToEvolve: !!catchRecord?.haveToEvolve,
|
||||
inHome: !!catchRecord?.inHome
|
||||
};
|
||||
}
|
||||
|
||||
function matchesFilters(catchRecord: CatchRecord | null) {
|
||||
const status = normalizedStatus(catchRecord);
|
||||
if (!filtersActive) return true;
|
||||
|
||||
const isCaught = status.caught || status.needsToEvolve;
|
||||
const isNotCaught = !isCaught;
|
||||
const isNeedsToEvolve = status.needsToEvolve;
|
||||
const isInHome = status.inHome;
|
||||
const isNotInHome = !status.inHome;
|
||||
|
||||
// OR within each group, AND between groups.
|
||||
const progressGroupActive = filterNotCaught || filterNeedsToEvolve;
|
||||
const homeGroupActive = filterInHome || filterNotInHome;
|
||||
|
||||
const progressMatch =
|
||||
!progressGroupActive ||
|
||||
(filterNotCaught && isNotCaught) ||
|
||||
(filterNeedsToEvolve && isNeedsToEvolve);
|
||||
|
||||
const homeMatch =
|
||||
!homeGroupActive || (filterInHome && isInHome) || (filterNotInHome && isNotInHome);
|
||||
|
||||
return progressMatch && homeMatch;
|
||||
}
|
||||
|
||||
$: filtersActive = filterNotCaught || filterNeedsToEvolve || filterInHome || filterNotInHome;
|
||||
$: filtersKey = `${filterNotCaught}-${filterNeedsToEvolve}-${filterInHome}-${filterNotInHome}`;
|
||||
|
||||
$: {
|
||||
// Ensure this recalculates when any filter changes (Svelte doesn't track function internals).
|
||||
filtersKey;
|
||||
filteredCombinedData = combinedData
|
||||
? combinedData.filter(({ catchRecord }) => matchesFilters(catchRecord))
|
||||
: [];
|
||||
}
|
||||
|
||||
$: filteredTotal = filteredCombinedData.length;
|
||||
$: overallTotal = combinedData?.length ?? 0;
|
||||
|
||||
$: overallCaughtCount = (combinedData ?? []).reduce((acc, { catchRecord }) => {
|
||||
const status = normalizedStatus(catchRecord);
|
||||
// Treat "needs to evolve" as a subset of "caught" (it is caught, just not finished).
|
||||
return acc + (status.caught || status.needsToEvolve ? 1 : 0);
|
||||
}, 0);
|
||||
|
||||
$: overallNotCaughtCount = overallTotal - overallCaughtCount;
|
||||
|
||||
$: overallNeedsToEvolveCount = (combinedData ?? []).reduce((acc, { catchRecord }) => {
|
||||
return acc + (normalizedStatus(catchRecord).needsToEvolve ? 1 : 0);
|
||||
}, 0);
|
||||
|
||||
$: overallInHomeCount = (combinedData ?? []).reduce((acc, { catchRecord }) => {
|
||||
return acc + (normalizedStatus(catchRecord).inHome ? 1 : 0);
|
||||
}, 0);
|
||||
|
||||
$: overallNotInHomeCount = overallTotal - overallInHomeCount;
|
||||
|
||||
const BOX_VIEW_LAYOUT_STORAGE_KEY = 'livingdex:boxViewLayout:v1';
|
||||
type BoxViewLayout = 'comfortable' | 'compact' | 'ultra';
|
||||
let boxViewLayout: BoxViewLayout = 'comfortable';
|
||||
|
||||
onMount(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem(BOX_VIEW_LAYOUT_STORAGE_KEY);
|
||||
if (stored === 'comfortable' || stored === 'compact' || stored === 'ultra') {
|
||||
boxViewLayout = stored;
|
||||
}
|
||||
} catch {
|
||||
// ignore (privacy mode / disabled storage)
|
||||
}
|
||||
});
|
||||
|
||||
function persistBoxViewLayout(next: BoxViewLayout) {
|
||||
boxViewLayout = next;
|
||||
try {
|
||||
localStorage.setItem(BOX_VIEW_LAYOUT_STORAGE_KEY, next);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
function cellBackgroundColourStyle(pokedexEntry: PokedexEntry, catchRecord: CatchRecord) {
|
||||
if (catchRecord.caught || catchRecord.haveToEvolve) {
|
||||
function onBoxViewLayoutChange(event: Event) {
|
||||
const next = (event.currentTarget as HTMLSelectElement).value;
|
||||
if (next === 'comfortable' || next === 'compact' || next === 'ultra') {
|
||||
persistBoxViewLayout(next);
|
||||
}
|
||||
}
|
||||
|
||||
$: boxesPerRow = boxViewLayout === 'comfortable' ? 2 : boxViewLayout === 'compact' ? 3 : 4;
|
||||
$: cellPaddingRem =
|
||||
boxViewLayout === 'comfortable' ? 1 : boxViewLayout === 'compact' ? 0.6 : 0.45;
|
||||
$: spriteSizePx = boxViewLayout === 'comfortable' ? 64 : boxViewLayout === 'compact' ? 52 : 44;
|
||||
|
||||
function cellStatusClasses(catchRecord: CatchRecord | null) {
|
||||
// Keep borders/layout unchanged; rely on clearer fills + badges instead.
|
||||
if (catchRecord?.caught) {
|
||||
// Match legend (green-600) while keeping sprites readable.
|
||||
return 'bg-green-600/15';
|
||||
}
|
||||
if (catchRecord?.haveToEvolve) {
|
||||
// Match legend (yellow-500) while keeping sprites readable.
|
||||
return 'bg-yellow-500/20';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function statusLabel(catchRecord: CatchRecord | null) {
|
||||
const parts: string[] = [];
|
||||
if (catchRecord?.caught) parts.push('Caught');
|
||||
if (catchRecord?.haveToEvolve) parts.push('Needs to evolve');
|
||||
if (catchRecord?.inHome) parts.push('In HOME');
|
||||
return parts.length ? parts.join(', ') : 'Not caught';
|
||||
}
|
||||
|
||||
function cellBackgroundColourStyle(index: number, catchRecord: CatchRecord | null) {
|
||||
if (catchRecord?.caught || catchRecord?.haveToEvolve) {
|
||||
return '';
|
||||
} else {
|
||||
if (pokedexEntry[currentPlacement].column % 2 === 0) {
|
||||
return 'background-color: #ffffff';
|
||||
const placement = calculateBoxPlacement(index);
|
||||
if (placement.column % 2 === 0) {
|
||||
return 'background-color: var(--ld-box-bg-even);';
|
||||
} else {
|
||||
return 'background-color: #f9f9f9;';
|
||||
return 'background-color: var(--ld-box-bg-odd);';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onInHomeFilterChange(event: Event) {
|
||||
const checked = (event.currentTarget as HTMLInputElement).checked;
|
||||
if (checked) filterNotInHome = false;
|
||||
}
|
||||
|
||||
function onNotInHomeFilterChange(event: Event) {
|
||||
const checked = (event.currentTarget as HTMLInputElement).checked;
|
||||
if (checked) filterInHome = false;
|
||||
}
|
||||
|
||||
const POKEMON_PER_BOX = 30;
|
||||
const BOX_POSITIONS = Array.from({ length: POKEMON_PER_BOX }, (_, i) => i);
|
||||
</script>
|
||||
|
||||
<main class="flex-1 p-4 w-full">
|
||||
<div class="max-w-fit mx-auto">
|
||||
{#if combinedData && combinedData.length > 0}
|
||||
<div class="container mx-auto">
|
||||
<div class="flex flex-wrap -mx-2">
|
||||
<div class="card bg-base-100 shadow mb-4">
|
||||
<div class="card-body p-4 flex flex-col gap-3">
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<label class="label p-0" for="box-view-layout">
|
||||
<span class="label-text font-semibold">Box view layout</span>
|
||||
</label>
|
||||
<select
|
||||
id="box-view-layout"
|
||||
class="select select-bordered select-sm"
|
||||
bind:value={boxViewLayout}
|
||||
on:change={onBoxViewLayoutChange}
|
||||
aria-label="Choose box view layout density"
|
||||
>
|
||||
<option value="comfortable">Comfortable (2 boxes/row)</option>
|
||||
<option value="compact">Compact (3 boxes/row)</option>
|
||||
<option value="ultra">Ultra (4 boxes/row)</option>
|
||||
</select>
|
||||
|
||||
<div class="flex flex-wrap items-center gap-2 text-sm">
|
||||
<span class="font-semibold">Legend:</span>
|
||||
<span
|
||||
class="inline-flex items-center gap-1 rounded-full border border-green-700 bg-green-600 px-2 py-0.5 text-white"
|
||||
>
|
||||
<span class="status-badge status-badge--caught" aria-hidden="true">
|
||||
<svg
|
||||
class="status-icon"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#ffffff"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</span>
|
||||
<span>Caught</span>
|
||||
</span>
|
||||
<span
|
||||
class="inline-flex items-center gap-1 rounded-full border border-yellow-700 bg-yellow-500 px-2 py-0.5 text-white"
|
||||
>
|
||||
<span class="status-badge status-badge--evolve" aria-hidden="true">
|
||||
<svg
|
||||
class="status-icon"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#ffffff"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M12 19V5" />
|
||||
<path d="M5 12l7-7 7 7" />
|
||||
</svg>
|
||||
</span>
|
||||
<span>Caught but needs to evolve</span>
|
||||
</span>
|
||||
<span
|
||||
class="inline-flex items-center gap-1 rounded-full border border-sky-700 bg-sky-600 px-2 py-0.5 text-white"
|
||||
>
|
||||
<span class="status-badge status-badge--home" aria-hidden="true">
|
||||
<svg
|
||||
class="status-icon"
|
||||
viewBox="0 0 24 24"
|
||||
fill="#ffffff"
|
||||
stroke="#ffffff"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M12 3 3 10.5V21a1 1 0 0 0 1 1h5v-6h6v6h5a1 1 0 0 0 1-1V10.5L12 3Z" />
|
||||
</svg>
|
||||
</span>
|
||||
<span>In Home</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex flex-wrap items-center gap-4">
|
||||
<span class="font-semibold">Filters:</span>
|
||||
<label class="label cursor-pointer gap-2 p-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm"
|
||||
bind:checked={filterNotCaught}
|
||||
/>
|
||||
<span class="label-text">Not caught</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-2 p-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm"
|
||||
bind:checked={filterNeedsToEvolve}
|
||||
/>
|
||||
<span class="label-text">Needs to evolve</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-2 p-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm"
|
||||
bind:checked={filterInHome}
|
||||
on:change={onInHomeFilterChange}
|
||||
/>
|
||||
<span class="label-text">In HOME</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-2 p-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm"
|
||||
bind:checked={filterNotInHome}
|
||||
on:change={onNotInHomeFilterChange}
|
||||
/>
|
||||
<span class="label-text">Not in HOME</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-wrap items-center justify-between gap-2 rounded-box bg-base-200/60 px-3 py-2"
|
||||
>
|
||||
<div class="text-sm text-base-content/70">
|
||||
<span class="font-semibold text-base-content">Caught</span>
|
||||
{overallCaughtCount}
|
||||
<span class="mx-2">•</span>
|
||||
<span class="font-semibold text-base-content">Not caught</span>
|
||||
{overallNotCaughtCount}
|
||||
<span class="mx-2">•</span>
|
||||
<span class="font-semibold text-base-content">Needs to evolve</span>
|
||||
{overallNeedsToEvolveCount}
|
||||
<span class="mx-2">•</span>
|
||||
<span class="font-semibold text-base-content">In HOME</span>
|
||||
{overallInHomeCount}
|
||||
<span class="mx-2">•</span>
|
||||
<span class="font-semibold text-base-content">Not in HOME</span>
|
||||
{overallNotInHomeCount}
|
||||
</div>
|
||||
<div class="badge badge-outline">
|
||||
Showing {filteredTotal} of {overallTotal}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="boxes-grid"
|
||||
style="--boxes-per-row: {boxesPerRow}; --cell-padding: {cellPaddingRem}rem; --sprite-size: {spriteSizePx}px;"
|
||||
>
|
||||
{#each boxNumbers as boxNumber}
|
||||
<div class="mb-8 md:w-1/2 px-2">
|
||||
<h2 class="text-xl font-bold mb-4">Box {boxNumber}</h2>
|
||||
<button class="btn" on:click={markBoxAsNotCaught(boxNumber)}>
|
||||
Mark box as not 'caught'
|
||||
</button>
|
||||
<button class="btn" on:click={markBoxAsCaught(boxNumber)}>
|
||||
Mark box as 'caught'
|
||||
</button>
|
||||
<button class="btn" on:click={markBoxAsNeedsToEvolve(boxNumber)}
|
||||
>Mark box as 'needs to evolve'</button
|
||||
>
|
||||
<button class="btn" on:click={markBoxAsInHome(boxNumber)}
|
||||
>Mark box as 'in Home'</button
|
||||
>
|
||||
<button class="btn" on:click={markBoxAsNotInHome(boxNumber)}
|
||||
>Mark box as not 'in Home'</button
|
||||
>
|
||||
{@const bulkMenuId = `box-${boxNumber}-bulk-menu`}
|
||||
<div class="mb-8">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3 mb-4 relative z-20">
|
||||
<h2 class="text-xl font-bold">Box {boxNumber}</h2>
|
||||
<div class="relative">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline relative z-[210]"
|
||||
aria-label="Open bulk actions menu"
|
||||
aria-haspopup="menu"
|
||||
aria-controls={bulkMenuId}
|
||||
aria-expanded={openBulkMenuForBox === boxNumber}
|
||||
on:click={(event) => {
|
||||
event.stopPropagation();
|
||||
openBulkMenuForBox = openBulkMenuForBox === boxNumber ? null : boxNumber;
|
||||
}}
|
||||
on:keydown={(event) => {
|
||||
if (event.key === 'Escape') openBulkMenuForBox = null;
|
||||
}}
|
||||
>
|
||||
⋯
|
||||
</button>
|
||||
|
||||
{#if openBulkMenuForBox === boxNumber}
|
||||
<ul
|
||||
id={bulkMenuId}
|
||||
class="menu bg-base-100 rounded-box absolute right-0 mt-2 z-[220] w-56 p-2 shadow border border-base-300"
|
||||
>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
on:click|stopPropagation={() => {
|
||||
markBoxAsNotCaught(boxNumber);
|
||||
openBulkMenuForBox = null;
|
||||
}}
|
||||
>
|
||||
Mark box as Not caught
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
on:click|stopPropagation={() => {
|
||||
markBoxAsCaught(boxNumber);
|
||||
openBulkMenuForBox = null;
|
||||
}}
|
||||
>
|
||||
Mark box as Caught
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
on:click|stopPropagation={() => {
|
||||
markBoxAsNeedsToEvolve(boxNumber);
|
||||
openBulkMenuForBox = null;
|
||||
}}
|
||||
>
|
||||
Mark box as Needs to evolve
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
on:click|stopPropagation={() => {
|
||||
markBoxAsInHome(boxNumber);
|
||||
openBulkMenuForBox = null;
|
||||
}}
|
||||
>
|
||||
Mark box as In HOME
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
on:click|stopPropagation={() => {
|
||||
markBoxAsNotInHome(boxNumber);
|
||||
openBulkMenuForBox = null;
|
||||
}}
|
||||
>
|
||||
Mark box as Not in HOME
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-6">
|
||||
{#each combinedData as { pokedexEntry, catchRecord }}
|
||||
{#if pokedexEntry[currentPlacement].box === boxNumber}
|
||||
<div
|
||||
class="pokemon-box {cellBackgroundColourClass(catchRecord)}"
|
||||
style="grid-column-start: {pokedexEntry[currentPlacement]
|
||||
.column}; grid-row-start: {pokedexEntry[currentPlacement].row};
|
||||
{cellBackgroundColourStyle(pokedexEntry, catchRecord)}"
|
||||
{#each BOX_POSITIONS as positionInBox}
|
||||
{@const globalIndex = (boxNumber - 1) * POKEMON_PER_BOX + positionInBox}
|
||||
{@const placement = calculateBoxPlacement(globalIndex)}
|
||||
{@const entry = combinedData?.[globalIndex]}
|
||||
{@const pokedexEntry = entry?.pokedexEntry}
|
||||
{@const catchRecord = entry?.catchRecord ?? null}
|
||||
{@const isFilteredOut =
|
||||
!!entry && filtersActive && !!filtersKey && !matchesFilters(catchRecord)}
|
||||
{#if entry && pokedexEntry}
|
||||
<button
|
||||
type="button"
|
||||
class="pokemon-box {cellStatusClasses(catchRecord)} {isFilteredOut
|
||||
? 'pokemon-box--filtered-out'
|
||||
: 'hover:scale-105 hover:shadow-lg hover:z-50'} transition-all cursor-pointer relative"
|
||||
style="grid-column-start: {placement.column}; grid-row-start: {placement.row};
|
||||
{cellBackgroundColourStyle(globalIndex, catchRecord)}"
|
||||
aria-disabled={isFilteredOut}
|
||||
on:click={() => {
|
||||
if (!isFilteredOut) onPokemonClick({ pokedexEntry, catchRecord });
|
||||
}}
|
||||
aria-label="View details for {pokedexEntry.pokemon}. Status: {statusLabel(
|
||||
catchRecord
|
||||
)}"
|
||||
>
|
||||
<Tooltip>
|
||||
<div slot="hover-target">
|
||||
{#if catchRecord.inHome}
|
||||
<div slot="hover-target" class="w-full h-full">
|
||||
{#if catchRecord?.caught}
|
||||
<span
|
||||
class="absolute -top-5 -right-4 z-2 p-1 text-secondary text-lg font-extrabold"
|
||||
>✓</span
|
||||
class="status-badge status-badge--caught absolute left-0.5 status-badge-top z-10"
|
||||
title="Caught"
|
||||
>
|
||||
<svg
|
||||
class="status-icon"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<span class="sr-only">Caught</span>
|
||||
</span>
|
||||
{:else if catchRecord?.haveToEvolve}
|
||||
<span
|
||||
class="status-badge status-badge--evolve absolute left-0.5 status-badge-top z-10"
|
||||
title="Caught but needs to evolve"
|
||||
>
|
||||
<svg
|
||||
class="status-icon"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M12 19V5" />
|
||||
<path d="M5 12l7-7 7 7" />
|
||||
</svg>
|
||||
<span class="sr-only">Caught but needs to evolve</span>
|
||||
</span>
|
||||
{/if}
|
||||
<PokemonSprite
|
||||
pokemonName={pokedexEntry.pokemon}
|
||||
pokedexNumber={pokedexEntry.pokedexNumber}
|
||||
form={pokedexEntry.form}
|
||||
shiny={showShiny}
|
||||
/>
|
||||
<span class="md:hidden">ⓘ</span>
|
||||
{#if catchRecord?.inHome}
|
||||
<span
|
||||
class="status-badge status-badge--home absolute right-0.5 status-badge-top z-10"
|
||||
title="In Pokémon HOME"
|
||||
>
|
||||
<svg
|
||||
class="status-icon"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M12 3 3 10.5V21a1 1 0 0 0 1 1h5v-6h6v6h5a1 1 0 0 0 1-1V10.5L12 3Z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="sr-only">In HOME</span>
|
||||
</span>
|
||||
{/if}
|
||||
<div class="pokemon-box-inner">
|
||||
<PokemonSprite
|
||||
pokemonName={pokedexEntry.pokemon}
|
||||
pokedexNumber={pokedexEntry.pokedexNumber}
|
||||
form={pokedexEntry.form}
|
||||
spriteKey={pokedexEntry.spriteKey}
|
||||
shiny={showShiny}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="tooltip">
|
||||
<div class="font-bold">
|
||||
@@ -97,13 +542,27 @@
|
||||
</div>
|
||||
<div>{pokedexEntry.pokedexNumber.toString().padStart(3, '0')}</div>
|
||||
<div>
|
||||
Caught: {catchRecord.caught ? 'Yes' : 'No'} <br />
|
||||
Needs to Evolve: {catchRecord.haveToEvolve ? 'Yes' : 'No'} <br />
|
||||
In Home: {catchRecord.inHome ? 'Yes' : 'No'}
|
||||
Caught: {catchRecord?.caught ? 'Yes' : 'No'} <br />
|
||||
Caught but needs to Evolve: {catchRecord?.haveToEvolve ? 'Yes' : 'No'}
|
||||
<br />
|
||||
In Home: {catchRecord?.inHome ? 'Yes' : 'No'}
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
class="pokemon-box pokemon-box--empty"
|
||||
disabled
|
||||
style="grid-column-start: {placement.column}; grid-row-start: {placement.row};
|
||||
{cellBackgroundColourStyle(globalIndex, null)}"
|
||||
aria-label="Empty box slot"
|
||||
>
|
||||
<div class="pokemon-box-inner" aria-hidden="true">
|
||||
<span class="sprite-placeholder" />
|
||||
</div>
|
||||
</button>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
@@ -136,8 +595,150 @@
|
||||
</main>
|
||||
|
||||
<style>
|
||||
/*
|
||||
Theme-aware backgrounds for non-caught box slots.
|
||||
- Light mode (`pokeball`) keeps the original exact colors.
|
||||
- Dark mode maps to DaisyUI theme base tokens so it stays consistent with the active theme.
|
||||
*/
|
||||
:global(:root) {
|
||||
--ld-box-bg-even: var(--fallback-b1, oklch(var(--b1) / 1));
|
||||
--ld-box-bg-odd: var(--fallback-b3, oklch(var(--b3) / 1));
|
||||
}
|
||||
|
||||
:global([data-theme='pokeball']) {
|
||||
--ld-box-bg-even: #ffffff;
|
||||
--ld-box-bg-odd: #f9f9f9;
|
||||
}
|
||||
|
||||
.boxes-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.boxes-grid {
|
||||
grid-template-columns: repeat(var(--boxes-per-row), minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.pokemon-box {
|
||||
border: 1px solid #ddd;
|
||||
padding: 1rem;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
/*
|
||||
On small screens the grid columns get narrow; without an explicit ratio,
|
||||
the button height becomes content-driven (padding + sprite) and you end up
|
||||
with rectangular cells. Force each slot to be square.
|
||||
*/
|
||||
aspect-ratio: 1 / 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pokemon-box--filtered-out {
|
||||
opacity: 0.25;
|
||||
filter: grayscale(1);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.pokemon-box--empty {
|
||||
opacity: 0.55;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.pokemon-box-inner {
|
||||
padding: var(--cell-padding, 1rem);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pokemon-box :global(img) {
|
||||
width: var(--sprite-size, 64px);
|
||||
height: var(--sprite-size, 64px);
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
display: block;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.sprite-placeholder {
|
||||
width: var(--sprite-size, 64px);
|
||||
height: var(--sprite-size, 64px);
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Mobile: keep 6 columns but prevent sprite/padding from forcing tall cells */
|
||||
@media (max-width: 767px) {
|
||||
.pokemon-box-inner {
|
||||
/* cap padding so the sprite can fit inside small squares */
|
||||
padding: min(var(--cell-padding, 1rem), 0.35rem);
|
||||
}
|
||||
|
||||
.pokemon-box :global(img) {
|
||||
/* allow the sprite to shrink with the square cell */
|
||||
width: min(var(--sprite-size, 64px), 100%);
|
||||
height: min(var(--sprite-size, 64px), 100%);
|
||||
}
|
||||
|
||||
.sprite-placeholder {
|
||||
width: min(var(--sprite-size, 64px), 100%);
|
||||
height: min(var(--sprite-size, 64px), 100%);
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
width: 0.95rem;
|
||||
height: 0.95rem;
|
||||
}
|
||||
|
||||
.status-badge-top {
|
||||
top: 0.35rem;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
width: 0.85rem;
|
||||
height: 0.85rem;
|
||||
}
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1.15rem;
|
||||
height: 1.15rem;
|
||||
border-radius: 0.35rem;
|
||||
font-weight: 900;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.status-badge-top {
|
||||
top: 0.7rem;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.status-badge--caught {
|
||||
color: #16a34a; /* green-600 */
|
||||
}
|
||||
|
||||
.status-badge--evolve {
|
||||
color: #eab308; /* yellow-500 */
|
||||
}
|
||||
|
||||
.status-badge--home {
|
||||
color: #0284c7; /* sky-600 */
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<script lang="ts">
|
||||
import PokedexEntryCatchRecord from './PokedexEntryCatchRecord.svelte';
|
||||
import type { CombinedData } from '$lib/models/CombinedData';
|
||||
|
||||
export let showOrigins = true;
|
||||
export let showForms = true;
|
||||
export let showShiny = false;
|
||||
export let combinedData: CombinedData[] | null;
|
||||
export let creatingRecords = false;
|
||||
export let totalRecordsCreated = 0;
|
||||
export let failedToLoad = false;
|
||||
export let updateACatch = (event: any) => {};
|
||||
export let createCatchRecords = () => {};
|
||||
</script>
|
||||
|
||||
<main class="flex-1 p-4 w-full">
|
||||
<div class="max-w-min mx-auto">
|
||||
{#if combinedData && combinedData.length > 0}
|
||||
{#each combinedData as { pokedexEntry, catchRecord }}
|
||||
<PokedexEntryCatchRecord
|
||||
{pokedexEntry}
|
||||
{showOrigins}
|
||||
{showForms}
|
||||
{showShiny}
|
||||
bind:catchRecord
|
||||
on:updateCatch={updateACatch}
|
||||
/>
|
||||
{/each}
|
||||
{:else if failedToLoad}
|
||||
{#if creatingRecords && totalRecordsCreated > 0}
|
||||
<p>Processed {totalRecordsCreated} Pokédex entries so far...</p>
|
||||
<p>Please be patient, this may take some time.</p>
|
||||
{:else if creatingRecords}
|
||||
<p>Processing...</p>
|
||||
<p>Please be patient, this may take some time.</p>
|
||||
{:else}
|
||||
<h1>Failed to load</h1>
|
||||
<p>
|
||||
If you're seeing this, you probably haven't created your Pokédex data yet. Please do so by
|
||||
clicking this button.
|
||||
</p>
|
||||
<button class="btn" on:click={createCatchRecords}>Create Pokédex data</button>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="min-w-max mx-auto">
|
||||
<h1>Loading Pokédex</h1>
|
||||
<span class="loading loading-spinner loading-xl"></span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</main>
|
||||
@@ -1,8 +1,9 @@
|
||||
import mongoose, { Schema, Document, Types } from 'mongoose';
|
||||
|
||||
export interface CatchRecord extends Document {
|
||||
// Supabase-based CatchRecord interface
|
||||
export interface CatchRecord {
|
||||
_id: string; // Maps to Supabase 'id' field for frontend compatibility
|
||||
userId: string;
|
||||
pokedexEntryId: Types.ObjectId;
|
||||
pokemonId: string;
|
||||
pokedexId: string;
|
||||
haveToEvolve: boolean;
|
||||
caught: boolean;
|
||||
inHome: boolean;
|
||||
@@ -10,15 +11,18 @@ export interface CatchRecord extends Document {
|
||||
personalNotes: string;
|
||||
}
|
||||
|
||||
const catchRecordSchema = new Schema<CatchRecord>({
|
||||
userId: String,
|
||||
pokedexEntryId: { type: Schema.Types.ObjectId, ref: 'PokedexEntry', required: true },
|
||||
haveToEvolve: { type: Boolean, default: false },
|
||||
caught: { type: Boolean, default: false },
|
||||
inHome: { type: Boolean, default: false },
|
||||
hasGigantamaxed: { type: Boolean, default: false },
|
||||
personalNotes: String
|
||||
});
|
||||
|
||||
const CatchRecordModel = mongoose.model<CatchRecord>('CatchRecord', catchRecordSchema);
|
||||
export default CatchRecordModel;
|
||||
// Database record type for Supabase
|
||||
export interface CatchRecordDB {
|
||||
id: string;
|
||||
userId: string;
|
||||
/** Numeric foreign key in database (references `pokemon.id`) */
|
||||
pokemonId: number;
|
||||
pokedexId: string; // NEW: Foreign key to pokedexes table
|
||||
haveToEvolve: boolean;
|
||||
caught: boolean;
|
||||
inHome: boolean;
|
||||
hasGigantamaxed: boolean;
|
||||
personalNotes: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ import { type CatchRecord } from './CatchRecord';
|
||||
|
||||
export interface CombinedData {
|
||||
pokedexEntry: PokedexEntry;
|
||||
catchRecord: CatchRecord;
|
||||
catchRecord: CatchRecord | null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
export interface Pokedex {
|
||||
_id: string;
|
||||
userId: string;
|
||||
name: string;
|
||||
description: string;
|
||||
isLivingDex: boolean;
|
||||
isShinyDex: boolean;
|
||||
isOriginDex: boolean;
|
||||
isFormDex: boolean;
|
||||
gameScope: string | null;
|
||||
dexScopes: string[];
|
||||
}
|
||||
|
||||
export interface PokedexDB {
|
||||
id: string;
|
||||
userId: string;
|
||||
name: string;
|
||||
description: string;
|
||||
isLivingDex: boolean;
|
||||
isShinyDex: boolean;
|
||||
isOriginDex: boolean;
|
||||
isFormDex: boolean;
|
||||
gameScope: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
@@ -1,51 +1,41 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
// Supabase-based PokedexEntry interface
|
||||
export type CatchInformationItem = {
|
||||
game: string;
|
||||
location: string;
|
||||
notes: string;
|
||||
};
|
||||
|
||||
export interface PokedexEntry extends Document {
|
||||
export interface PokedexEntry {
|
||||
_id: string; // Maps to Supabase 'id' field for frontend compatibility
|
||||
pokedexNumber: number;
|
||||
boxPlacement: { box: number; row: number; column: number };
|
||||
boxPlacementForms: { box: number; row: number; column: number };
|
||||
pokemon: string;
|
||||
form: string;
|
||||
spriteKey: string;
|
||||
canGigantamax: boolean;
|
||||
regionToCatchIn: string;
|
||||
gamesToCatchIn: string[];
|
||||
regionToEvolveIn: string;
|
||||
evolutionInformation: string;
|
||||
catchInformation: [
|
||||
{
|
||||
game: string;
|
||||
location: string;
|
||||
notes: string;
|
||||
}
|
||||
];
|
||||
catchInformation: Array<string | CatchInformationItem>;
|
||||
notes: string;
|
||||
// Note: Regional dex numbers stored in separate regional_dex_numbers table
|
||||
}
|
||||
|
||||
const pokedexEntrySchema = new Schema<PokedexEntry>({
|
||||
pokedexNumber: Number,
|
||||
boxPlacement: {
|
||||
box: Number,
|
||||
row: Number,
|
||||
column: Number
|
||||
},
|
||||
boxPlacementForms: {
|
||||
box: Number,
|
||||
row: Number,
|
||||
column: Number
|
||||
},
|
||||
pokemon: String,
|
||||
form: String,
|
||||
canGigantamax: Boolean,
|
||||
regionToCatchIn: String,
|
||||
gamesToCatchIn: Array<string>,
|
||||
regionToEvolveIn: String,
|
||||
evolutionInformation: String,
|
||||
catchInformation: [
|
||||
{
|
||||
game: String,
|
||||
location: String,
|
||||
notes: String
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
export default mongoose.model<PokedexEntry>('PokedexEntry', pokedexEntrySchema);
|
||||
// Database record type for Supabase
|
||||
export interface PokedexEntryDB {
|
||||
id: number;
|
||||
pokedexNumber: number;
|
||||
pokemon: string;
|
||||
form: string | null;
|
||||
spriteKey: string | null;
|
||||
canGigantamax: boolean;
|
||||
regionToCatchIn: string | null;
|
||||
gamesToCatchIn: string[] | null;
|
||||
regionToEvolveIn: string | null;
|
||||
evolutionInformation: string | null;
|
||||
catchInformation: string[] | null;
|
||||
notes: string | null;
|
||||
// Note: Regional dex numbers stored in separate regional_dex_numbers table
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
export type ExportProvider = 'google_drive' | 'dropbox';
|
||||
|
||||
export interface PokedexExportIntegration {
|
||||
_id: string;
|
||||
userId: string;
|
||||
pokedexId: string | null;
|
||||
provider: ExportProvider;
|
||||
enabled: boolean;
|
||||
fileName: string | null;
|
||||
folderId: string | null;
|
||||
path: string | null;
|
||||
accessToken: string;
|
||||
refreshToken: string | null;
|
||||
accessTokenExpiresAt: string | null;
|
||||
metadata: Record<string, unknown> | null;
|
||||
lastExportedAt: string | null;
|
||||
lastError: string | null;
|
||||
}
|
||||
|
||||
export interface PokedexExportIntegrationDB {
|
||||
id: string;
|
||||
userId: string;
|
||||
pokedexId: string | null;
|
||||
provider: ExportProvider;
|
||||
enabled: boolean;
|
||||
fileName: string | null;
|
||||
folderId: string | null;
|
||||
path: string | null;
|
||||
accessToken: string;
|
||||
refreshToken: string | null;
|
||||
accessTokenExpiresAt: string | null;
|
||||
metadata: Record<string, unknown> | null;
|
||||
lastExportedAt: string | null;
|
||||
lastError: string | null;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface PokedexMetadata extends Document {
|
||||
lastModified: Date;
|
||||
}
|
||||
|
||||
const pokedexMetadataSchema = new Schema<PokedexMetadata>({
|
||||
lastModified: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
}
|
||||
});
|
||||
|
||||
export default mongoose.model<PokedexMetadata>('PokedexMetadata', pokedexMetadataSchema);
|
||||
@@ -1,13 +1,13 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface RegionGameMapping extends Document {
|
||||
// Supabase-based RegionGameMapping interface
|
||||
export interface RegionGameMapping {
|
||||
id?: number;
|
||||
region: string;
|
||||
games: string[];
|
||||
game: string; // Note: Different from MongoDB version which had 'games' array
|
||||
}
|
||||
|
||||
const regionGameMappingSchema = new Schema<RegionGameMapping>({
|
||||
region: String,
|
||||
games: Array<string>
|
||||
});
|
||||
|
||||
export default mongoose.model<RegionGameMapping>('RegionGameMapping', regionGameMappingSchema);
|
||||
// Database record type for Supabase
|
||||
export interface RegionGameMappingDB {
|
||||
id: number;
|
||||
region: string;
|
||||
game: string;
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface User extends Document {
|
||||
username: string;
|
||||
// Add other user-related fields as needed
|
||||
}
|
||||
|
||||
const userSchema = new Schema<User>({
|
||||
username: String
|
||||
// Add other user-related fields as needed
|
||||
});
|
||||
|
||||
export default mongoose.model<User>('User', userSchema);
|
||||
@@ -1,19 +0,0 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface UserCatchEntry extends Document {
|
||||
userId: mongoose.Types.ObjectId; // Reference to the user
|
||||
pokedexEntryId: mongoose.Types.ObjectId; // Reference to the pokedex entry
|
||||
haveToEvolve: boolean;
|
||||
caught: boolean;
|
||||
inHome: boolean;
|
||||
}
|
||||
|
||||
const userCatchEntrySchema = new Schema<UserCatchEntry>({
|
||||
userId: { type: mongoose.Types.ObjectId, ref: 'User' },
|
||||
pokedexEntryId: { type: mongoose.Types.ObjectId, ref: 'PokedexEntry' },
|
||||
haveToEvolve: Boolean,
|
||||
caught: Boolean,
|
||||
inHome: Boolean
|
||||
});
|
||||
|
||||
export default mongoose.model<UserCatchEntry>('UserCatchEntry', userCatchEntrySchema);
|
||||
@@ -1,34 +1,234 @@
|
||||
import CatchRecordModel, { type CatchRecord } from '$lib/models/CatchRecord';
|
||||
import type { CatchRecord, CatchRecordDB } from '$lib/models/CatchRecord';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
type PartialExcept<T, K extends keyof T> = Partial<T> & Pick<T, K>;
|
||||
|
||||
class CatchRecordRepository {
|
||||
constructor(
|
||||
private supabase: SupabaseClient,
|
||||
private userId: string,
|
||||
private pokedexId: string
|
||||
) {}
|
||||
|
||||
// Transform Supabase data to frontend format (minimal transformation)
|
||||
private transformCatchRecord(record: CatchRecordDB): CatchRecord {
|
||||
return {
|
||||
_id: record.id,
|
||||
userId: record.userId,
|
||||
pokemonId: record.pokemonId.toString(),
|
||||
pokedexId: record.pokedexId,
|
||||
haveToEvolve: record.haveToEvolve,
|
||||
caught: record.caught,
|
||||
inHome: record.inHome,
|
||||
hasGigantamaxed: record.hasGigantamaxed,
|
||||
personalNotes: record.personalNotes
|
||||
};
|
||||
}
|
||||
|
||||
// Transform frontend data to database format (minimal transformation)
|
||||
private transformToDatabase(data: Partial<CatchRecord>): Partial<CatchRecordDB> {
|
||||
const dbData: Partial<CatchRecordDB> = {};
|
||||
if (data.pokemonId !== undefined && data.pokemonId !== null) {
|
||||
const numericId = Number(data.pokemonId);
|
||||
if (isNaN(numericId)) {
|
||||
throw new Error(`Invalid pokemonId: ${data.pokemonId}`);
|
||||
}
|
||||
dbData.pokemonId = numericId;
|
||||
}
|
||||
if (data.pokedexId !== undefined) dbData.pokedexId = data.pokedexId;
|
||||
if (data.haveToEvolve !== undefined) dbData.haveToEvolve = data.haveToEvolve;
|
||||
if (data.caught !== undefined) dbData.caught = data.caught;
|
||||
if (data.inHome !== undefined) dbData.inHome = data.inHome;
|
||||
if (data.hasGigantamaxed !== undefined) dbData.hasGigantamaxed = data.hasGigantamaxed;
|
||||
if (data.personalNotes !== undefined) dbData.personalNotes = data.personalNotes;
|
||||
|
||||
return dbData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk upsert catch records in a single request when possible.
|
||||
*
|
||||
* Requires a unique constraint matching the `onConflict` columns.
|
||||
* If the database is not configured with that constraint, the caller should
|
||||
* catch the error and fall back to per-record upserts.
|
||||
*/
|
||||
async bulkUpsert(
|
||||
records: Array<PartialExcept<CatchRecord, 'pokemonId'>>
|
||||
): Promise<CatchRecord[]> {
|
||||
if (records.length === 0) return [];
|
||||
|
||||
const dbRows: Partial<CatchRecordDB>[] = records.map((r, index) => {
|
||||
if (r.pokemonId === undefined || r.pokemonId === null || r.pokemonId === '') {
|
||||
throw new Error(
|
||||
`CatchRecordRepository.bulkUpsert: record at index ${index} is missing required field "pokemonId"`
|
||||
);
|
||||
}
|
||||
|
||||
// Preserve repository scoping; if a caller supplies ids, they must match the repo scope.
|
||||
if (r.userId !== undefined && r.userId !== this.userId) {
|
||||
throw new Error(
|
||||
`CatchRecordRepository.bulkUpsert: record at index ${index} has userId "${r.userId}" but repository is scoped to "${this.userId}"`
|
||||
);
|
||||
}
|
||||
if (r.pokedexId !== undefined && r.pokedexId !== this.pokedexId) {
|
||||
throw new Error(
|
||||
`CatchRecordRepository.bulkUpsert: record at index ${index} has pokedexId "${r.pokedexId}" but repository is scoped to "${this.pokedexId}"`
|
||||
);
|
||||
}
|
||||
|
||||
const mapped = this.transformToDatabase(r);
|
||||
// Enforce repo scope after mapping so per-record input cannot override it.
|
||||
mapped.userId = this.userId;
|
||||
mapped.pokedexId = this.pokedexId;
|
||||
|
||||
if (mapped.pokemonId === undefined || mapped.pokemonId === null) {
|
||||
throw new Error(
|
||||
`CatchRecordRepository.bulkUpsert: record at index ${index} produced no pokemonId after transform`
|
||||
);
|
||||
}
|
||||
|
||||
return mapped;
|
||||
});
|
||||
|
||||
const { data: result, error } = await this.supabase
|
||||
.from('catch_records')
|
||||
.upsert(dbRows, {
|
||||
onConflict: '"userId","pokedexId","pokemonId"'
|
||||
})
|
||||
.select();
|
||||
|
||||
if (error) {
|
||||
console.error('Supabase error bulk upserting catch records:', error);
|
||||
throw new Error(`Failed to bulk upsert catch records: ${error.message}`);
|
||||
}
|
||||
|
||||
return (result ?? []).map((row) => this.transformCatchRecord(row));
|
||||
}
|
||||
|
||||
async findById(id: string): Promise<CatchRecord | null> {
|
||||
return CatchRecordModel.findById(id).exec();
|
||||
const { data, error } = await this.supabase
|
||||
.from('catch_records')
|
||||
.select('*')
|
||||
.eq('id', id)
|
||||
.eq('userId', this.userId)
|
||||
.eq('pokedexId', this.pokedexId)
|
||||
.single();
|
||||
|
||||
if (error || !data) return null;
|
||||
return this.transformCatchRecord(data);
|
||||
}
|
||||
|
||||
async findAll(): Promise<CatchRecord[]> {
|
||||
return CatchRecordModel.find().exec();
|
||||
const { data, error } = await this.supabase
|
||||
.from('catch_records')
|
||||
.select('*')
|
||||
.eq('userId', this.userId)
|
||||
.eq('pokedexId', this.pokedexId);
|
||||
|
||||
if (error || !data) return [];
|
||||
return data.map((record) => this.transformCatchRecord(record));
|
||||
}
|
||||
|
||||
async findByUserId(userId: string): Promise<CatchRecord[]> {
|
||||
const { data, error } = await this.supabase
|
||||
.from('catch_records')
|
||||
.select('*')
|
||||
.eq('userId', userId)
|
||||
.eq('pokedexId', this.pokedexId);
|
||||
|
||||
if (error || !data) return [];
|
||||
return data.map((record) => this.transformCatchRecord(record));
|
||||
}
|
||||
|
||||
async create(data: Partial<CatchRecord>): Promise<CatchRecord> {
|
||||
return CatchRecordModel.create(data);
|
||||
const dbData = {
|
||||
userId: this.userId,
|
||||
pokedexId: this.pokedexId,
|
||||
...this.transformToDatabase(data)
|
||||
};
|
||||
|
||||
const { data: result, error } = await this.supabase
|
||||
.from('catch_records')
|
||||
.insert(dbData)
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
console.error('Supabase error creating catch record:', error);
|
||||
throw new Error(`Failed to create catch record: ${error.message}`);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
throw new Error('Failed to create catch record: No result returned');
|
||||
}
|
||||
|
||||
return this.transformCatchRecord(result);
|
||||
}
|
||||
|
||||
async update(id: string, data: Partial<CatchRecord>): Promise<CatchRecord | null> {
|
||||
return CatchRecordModel.findByIdAndUpdate(id, data, { new: true }).exec();
|
||||
const dbData = this.transformToDatabase(data);
|
||||
|
||||
const { data: result, error } = await this.supabase
|
||||
.from('catch_records')
|
||||
.update(dbData)
|
||||
.eq('id', id)
|
||||
.eq('userId', this.userId)
|
||||
.eq('pokedexId', this.pokedexId)
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error || !result) return null;
|
||||
return this.transformCatchRecord(result);
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await CatchRecordModel.findByIdAndDelete(id).exec();
|
||||
const { error } = await this.supabase
|
||||
.from('catch_records')
|
||||
.delete()
|
||||
.eq('id', id)
|
||||
.eq('userId', this.userId)
|
||||
.eq('pokedexId', this.pokedexId);
|
||||
|
||||
if (error) {
|
||||
console.error('Error deleting catch record:', error);
|
||||
throw new Error(`Failed to delete catch record: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async upsert(data: Partial<CatchRecord>): Promise<CatchRecord | null> {
|
||||
if (data._id) {
|
||||
// Update existing record
|
||||
return CatchRecordModel.findByIdAndUpdate(data._id, data, { new: true }).exec();
|
||||
} else {
|
||||
// Create new record
|
||||
return CatchRecordModel.create(data);
|
||||
return this.update(data._id, data);
|
||||
} else if (data.pokemonId) {
|
||||
// Try to find existing record for this user, pokemon, and pokedex
|
||||
const existing = await this.findByUserAndPokemon(this.userId, data.pokemonId, this.pokedexId);
|
||||
if (existing) {
|
||||
return this.update(existing._id, data);
|
||||
} else {
|
||||
return this.create(data);
|
||||
}
|
||||
}
|
||||
return this.create(data);
|
||||
}
|
||||
|
||||
async findByUserAndPokemon(
|
||||
userId: string,
|
||||
pokemonId: string,
|
||||
pokedexId: string
|
||||
): Promise<CatchRecord | null> {
|
||||
const numericId = Number(pokemonId);
|
||||
if (isNaN(numericId)) {
|
||||
return null;
|
||||
}
|
||||
const { data, error } = await this.supabase
|
||||
.from('catch_records')
|
||||
.select('*')
|
||||
.eq('userId', userId)
|
||||
.eq('pokemonId', numericId)
|
||||
.eq('pokedexId', pokedexId)
|
||||
.single();
|
||||
|
||||
if (error || !data) return null;
|
||||
return this.transformCatchRecord(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,163 +1,495 @@
|
||||
import PokedexEntryModel, { type PokedexEntry } from '$lib/models/PokedexEntry';
|
||||
import CatchRecordModel, { type CatchRecord } from '$lib/models/CatchRecord';
|
||||
import { CombinedData } from '$lib/models/CombinedData';
|
||||
import { type PokedexEntry, type PokedexEntryDB } from '$lib/models/PokedexEntry';
|
||||
import { type CatchRecord, type CatchRecordDB } from '$lib/models/CatchRecord';
|
||||
import { type CombinedData } from '$lib/models/CombinedData';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
// Raw row from game_pokedex_entry_details includes extra ordering columns not in PokedexEntryDB.
|
||||
type RawDexEntry = PokedexEntryDB & {
|
||||
dexNumber: number;
|
||||
dexSortOrder: number;
|
||||
formSortBucket: number;
|
||||
formSortRegionOrder: number;
|
||||
formSortRegionalSub: number;
|
||||
formSortLabel: string;
|
||||
unownSortOrder: number;
|
||||
};
|
||||
|
||||
class CombinedDataRepository {
|
||||
async findAllCombinedData(
|
||||
enableForms: boolean = true,
|
||||
region: string = '',
|
||||
game: string = ''
|
||||
): Promise<CombinedData[]> {
|
||||
const pipeline: any[] = [
|
||||
{
|
||||
$lookup: {
|
||||
from: 'catchrecords',
|
||||
localField: '_id',
|
||||
foreignField: 'pokedexEntryId',
|
||||
as: 'catchRecord'
|
||||
}
|
||||
},
|
||||
{
|
||||
$unwind: {
|
||||
path: '$catchRecord',
|
||||
preserveNullAndEmptyArrays: true
|
||||
}
|
||||
},
|
||||
{
|
||||
$sort: {
|
||||
'boxPlacementForms.box': 1,
|
||||
'boxPlacementForms.row': 1,
|
||||
'boxPlacementForms.column': 1
|
||||
}
|
||||
}
|
||||
];
|
||||
private static readonly MAX_ROWS_PER_REQUEST = 1000;
|
||||
|
||||
constructor(
|
||||
private supabase: SupabaseClient,
|
||||
private userId: string | null,
|
||||
private pokedexId: string | null
|
||||
) {}
|
||||
|
||||
// Transform Supabase data to match frontend expectations (minimal transformation)
|
||||
private transformPokedexEntry(entry: PokedexEntryDB): PokedexEntry {
|
||||
return {
|
||||
_id: entry.id.toString(),
|
||||
pokedexNumber: entry.pokedexNumber,
|
||||
pokemon: entry.pokemon,
|
||||
form: entry.form || '',
|
||||
spriteKey: entry.spriteKey || '',
|
||||
canGigantamax: entry.canGigantamax,
|
||||
regionToCatchIn: entry.regionToCatchIn || '',
|
||||
gamesToCatchIn: entry.gamesToCatchIn || [],
|
||||
regionToEvolveIn: entry.regionToEvolveIn || '',
|
||||
evolutionInformation: entry.evolutionInformation || '',
|
||||
catchInformation: entry.catchInformation || [],
|
||||
notes: entry.notes || ''
|
||||
// Note: Regional dex numbers are stored in separate regional_dex_numbers table
|
||||
};
|
||||
}
|
||||
|
||||
private transformCatchRecord(record: CatchRecordDB): CatchRecord {
|
||||
return {
|
||||
_id: record.id,
|
||||
userId: record.userId,
|
||||
pokemonId: record.pokemonId.toString(),
|
||||
pokedexId: record.pokedexId,
|
||||
haveToEvolve: record.haveToEvolve,
|
||||
caught: record.caught,
|
||||
inHome: record.inHome,
|
||||
hasGigantamaxed: record.hasGigantamaxed,
|
||||
personalNotes: record.personalNotes
|
||||
};
|
||||
}
|
||||
|
||||
private buildEntriesQuery(enableForms: boolean, region: string, game: string) {
|
||||
let query = this.supabase.from('pokedex_entries').select('*');
|
||||
|
||||
if (!enableForms) {
|
||||
pipeline.unshift({
|
||||
$match: {
|
||||
'boxPlacement.box': { $ne: null }
|
||||
}
|
||||
});
|
||||
// Filter to base forms: NULL or 'male' (gendered species), plus Unown "A".
|
||||
query = query.or('form.is.null,form.eq.male,and(pokemon.eq.Unown,form.eq.A)');
|
||||
}
|
||||
|
||||
if (region.length > 0) {
|
||||
pipeline.unshift({
|
||||
$match: {
|
||||
regionToCatchIn: region
|
||||
}
|
||||
});
|
||||
if (region) {
|
||||
query = query.eq('regionToCatchIn', region);
|
||||
}
|
||||
|
||||
if (game.length > 0) {
|
||||
pipeline.unshift({
|
||||
$match: {
|
||||
gamesToCatchIn: { $in: [game] }
|
||||
}
|
||||
});
|
||||
if (game) {
|
||||
query = query.contains('gamesToCatchIn', [game]);
|
||||
}
|
||||
|
||||
const combinedData: CombinedData[] = await PokedexEntryModel.aggregate(pipeline).exec();
|
||||
// Stable ordering from the database: national dex, Unown order, base/female/temporal, then form label.
|
||||
query = query
|
||||
.order('pokedexNumber', { ascending: true })
|
||||
.order('unownSortOrder', { ascending: true })
|
||||
.order('formSortBucket', { ascending: true })
|
||||
.order('formSortRegionOrder', { ascending: true })
|
||||
.order('formSortRegionalSub', { ascending: true })
|
||||
.order('formSortLabel', { ascending: true });
|
||||
|
||||
// Filter out entries with no catch records
|
||||
const filteredData = combinedData.filter((data) => data.catchRecord);
|
||||
return query;
|
||||
}
|
||||
|
||||
return filteredData.map((data) => ({
|
||||
pokedexEntry: data as PokedexEntry,
|
||||
catchRecord: data.catchRecord as CatchRecord
|
||||
}));
|
||||
private buildDexEntriesQuery(dexScopes: string[], enableForms: boolean, region: string) {
|
||||
let query = this.supabase.from('game_pokedex_entry_details').select('*').in('dexId', dexScopes);
|
||||
|
||||
if (!enableForms) {
|
||||
// Filter to base forms: NULL or 'male' (gendered species), plus Unown "A".
|
||||
query = query.or('form.is.null,form.eq.male,and(pokemon.eq.Unown,form.eq.A)');
|
||||
}
|
||||
|
||||
if (region) {
|
||||
query = query.eq('regionToCatchIn', region);
|
||||
}
|
||||
|
||||
// Stable ordering: dex order, dex number, Unown order, base/female/temporal, then form label.
|
||||
query = query
|
||||
.order('dexSortOrder', { ascending: true })
|
||||
.order('dexNumber', { ascending: true })
|
||||
.order('unownSortOrder', { ascending: true })
|
||||
.order('formSortBucket', { ascending: true })
|
||||
.order('formSortRegionOrder', { ascending: true })
|
||||
.order('formSortRegionalSub', { ascending: true })
|
||||
.order('formSortLabel', { ascending: true });
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
// Fetch all non-base form entries for a game from pokedex_entries, excluding already-seen IDs.
|
||||
// game_pokedex_entries is seeded with base forms only, so forms must be supplemented from here.
|
||||
private async fetchFormsForGame(
|
||||
game: string,
|
||||
region: string,
|
||||
excludeIds: Set<number>
|
||||
): Promise<PokedexEntryDB[]> {
|
||||
const allForms: PokedexEntryDB[] = [];
|
||||
let start = 0;
|
||||
const maxRows = CombinedDataRepository.MAX_ROWS_PER_REQUEST;
|
||||
|
||||
while (true) {
|
||||
const end = start + maxRows - 1;
|
||||
let query = this.supabase.from('pokedex_entries').select('*').not('form', 'is', null);
|
||||
|
||||
if (game) {
|
||||
query = query.contains('gamesToCatchIn', [game]);
|
||||
}
|
||||
if (region) {
|
||||
query = query.eq('regionToCatchIn', region);
|
||||
}
|
||||
|
||||
const { data, error } = await query.order('id', { ascending: true }).range(start, end);
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching forms for game:', error);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!data || data.length === 0) break;
|
||||
|
||||
allForms.push(...(data as PokedexEntryDB[]).filter((e) => !excludeIds.has(e.id)));
|
||||
|
||||
if (data.length < maxRows) break;
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
return allForms;
|
||||
}
|
||||
|
||||
private async fetchAllDexEntries(
|
||||
dexScopes: string[],
|
||||
enableForms: boolean,
|
||||
region: string,
|
||||
game: string = ''
|
||||
): Promise<PokedexEntryDB[]> {
|
||||
if (dexScopes.length === 0) return [];
|
||||
|
||||
const entries: RawDexEntry[] = [];
|
||||
let start = 0;
|
||||
const maxRows = CombinedDataRepository.MAX_ROWS_PER_REQUEST;
|
||||
|
||||
while (true) {
|
||||
const end = start + maxRows - 1;
|
||||
const { data, error } = await this.buildDexEntriesQuery(dexScopes, enableForms, region).range(
|
||||
start,
|
||||
end
|
||||
);
|
||||
|
||||
if (error) {
|
||||
console.error('Error finding dex-scoped combined data:', error);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
entries.push(...(data as RawDexEntry[]));
|
||||
|
||||
if (data.length < maxRows) {
|
||||
break;
|
||||
}
|
||||
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
// When forms are enabled, game_pokedex_entries only has base forms, so supplement from pokedex_entries.
|
||||
if (!enableForms || !game) {
|
||||
return entries as PokedexEntryDB[];
|
||||
}
|
||||
|
||||
// Build lookup: pokedexNumber → dex position (from the raw game dex data)
|
||||
const dexInfoByPokedexNumber = new Map<number, { dexNumber: number; dexSortOrder: number }>();
|
||||
for (const entry of entries) {
|
||||
if (!dexInfoByPokedexNumber.has(entry.pokedexNumber)) {
|
||||
dexInfoByPokedexNumber.set(entry.pokedexNumber, {
|
||||
dexNumber: entry.dexNumber ?? 0,
|
||||
dexSortOrder: entry.dexSortOrder ?? 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch forms not already covered by game_pokedex_entries
|
||||
const existingIds = new Set(entries.map((e) => e.id));
|
||||
const formEntries = await this.fetchFormsForGame(game, region, existingIds);
|
||||
|
||||
if (formEntries.length === 0) {
|
||||
return entries as PokedexEntryDB[];
|
||||
}
|
||||
|
||||
// Merge and sort: dex entries first (they are the canonical base form for the regional dex),
|
||||
// then supplemented forms. Within each group, sort by form fields.
|
||||
type TaggedEntry = RawDexEntry & { _isDexEntry: boolean };
|
||||
const merged: TaggedEntry[] = [
|
||||
...entries.map((e) => ({ ...e, _isDexEntry: true })),
|
||||
...(formEntries as RawDexEntry[]).map((e) => ({ ...e, _isDexEntry: false }))
|
||||
];
|
||||
|
||||
merged.sort((a, b) => {
|
||||
const aDex = dexInfoByPokedexNumber.get(a.pokedexNumber) ?? {
|
||||
dexNumber: 9999,
|
||||
dexSortOrder: 9999
|
||||
};
|
||||
const bDex = dexInfoByPokedexNumber.get(b.pokedexNumber) ?? {
|
||||
dexNumber: 9999,
|
||||
dexSortOrder: 9999
|
||||
};
|
||||
if (aDex.dexSortOrder !== bDex.dexSortOrder) return aDex.dexSortOrder - bDex.dexSortOrder;
|
||||
if (aDex.dexNumber !== bDex.dexNumber) return aDex.dexNumber - bDex.dexNumber;
|
||||
if ((a.unownSortOrder ?? 0) !== (b.unownSortOrder ?? 0))
|
||||
return (a.unownSortOrder ?? 0) - (b.unownSortOrder ?? 0);
|
||||
// Dex entries (canonical regional base form) sort before supplemented forms.
|
||||
if (a._isDexEntry !== b._isDexEntry) return a._isDexEntry ? -1 : 1;
|
||||
if ((a.formSortBucket ?? 0) !== (b.formSortBucket ?? 0))
|
||||
return (a.formSortBucket ?? 0) - (b.formSortBucket ?? 0);
|
||||
if ((a.formSortRegionOrder ?? 0) !== (b.formSortRegionOrder ?? 0))
|
||||
return (a.formSortRegionOrder ?? 0) - (b.formSortRegionOrder ?? 0);
|
||||
if ((a.formSortRegionalSub ?? 0) !== (b.formSortRegionalSub ?? 0))
|
||||
return (a.formSortRegionalSub ?? 0) - (b.formSortRegionalSub ?? 0);
|
||||
return (a.formSortLabel ?? '').localeCompare(b.formSortLabel ?? '');
|
||||
});
|
||||
|
||||
return merged as PokedexEntryDB[];
|
||||
}
|
||||
|
||||
private dedupeEntries(entries: PokedexEntryDB[]): PokedexEntryDB[] {
|
||||
const seen = new Set<number>();
|
||||
const deduped: PokedexEntryDB[] = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
if (seen.has(entry.id)) continue;
|
||||
seen.add(entry.id);
|
||||
deduped.push(entry);
|
||||
}
|
||||
|
||||
return deduped;
|
||||
}
|
||||
|
||||
private async fetchEntriesByRange(
|
||||
from: number,
|
||||
to: number,
|
||||
enableForms: boolean,
|
||||
region: string,
|
||||
game: string
|
||||
): Promise<PokedexEntryDB[]> {
|
||||
const entries: PokedexEntryDB[] = [];
|
||||
let start = from;
|
||||
const maxRows = CombinedDataRepository.MAX_ROWS_PER_REQUEST;
|
||||
|
||||
while (start <= to) {
|
||||
const end = Math.min(to, start + maxRows - 1);
|
||||
const { data, error } = await this.buildEntriesQuery(enableForms, region, game).range(
|
||||
start,
|
||||
end
|
||||
);
|
||||
|
||||
if (error) {
|
||||
console.error('Error finding paginated combined data:', error);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
entries.push(...data);
|
||||
|
||||
if (data.length < end - start + 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private async fetchAllEntries(
|
||||
enableForms: boolean,
|
||||
region: string,
|
||||
game: string
|
||||
): Promise<PokedexEntryDB[]> {
|
||||
const entries: PokedexEntryDB[] = [];
|
||||
let start = 0;
|
||||
const maxRows = CombinedDataRepository.MAX_ROWS_PER_REQUEST;
|
||||
|
||||
while (true) {
|
||||
const end = start + maxRows - 1;
|
||||
const { data, error } = await this.buildEntriesQuery(enableForms, region, game).range(
|
||||
start,
|
||||
end
|
||||
);
|
||||
|
||||
if (error) {
|
||||
console.error('Error finding combined data:', error);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
entries.push(...data);
|
||||
|
||||
if (data.length < maxRows) {
|
||||
break;
|
||||
}
|
||||
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private async fetchCatchRecords(entryIds: number[], userId: string): Promise<CatchRecordDB[]> {
|
||||
if (!this.pokedexId) return [];
|
||||
if (entryIds.length === 0) return [];
|
||||
|
||||
const records: CatchRecordDB[] = [];
|
||||
const chunkSize = 1000;
|
||||
|
||||
for (let i = 0; i < entryIds.length; i += chunkSize) {
|
||||
const chunk = entryIds.slice(i, i + chunkSize);
|
||||
const { data, error } = await this.supabase
|
||||
.from('catch_records')
|
||||
.select('*')
|
||||
.eq('userId', userId)
|
||||
.eq('pokedexId', this.pokedexId)
|
||||
.in('pokemonId', chunk);
|
||||
|
||||
if (error) {
|
||||
console.error('Error loading catch records:', error);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
records.push(...data);
|
||||
}
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
async findAllCombinedData(
|
||||
userId: string,
|
||||
enableForms: boolean = true,
|
||||
region: string = '',
|
||||
game: string = '',
|
||||
dexScopes: string[] = []
|
||||
): Promise<CombinedData[]> {
|
||||
const entries =
|
||||
dexScopes.length > 0
|
||||
? this.dedupeEntries(await this.fetchAllDexEntries(dexScopes, enableForms, region, game))
|
||||
: await this.fetchAllEntries(enableForms, region, game);
|
||||
|
||||
if (!entries || entries.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Get catch records for all entries
|
||||
let catchRecords: CatchRecordDB[] = [];
|
||||
if (userId && this.pokedexId) {
|
||||
const entryIds = entries.map((entry) => entry.id);
|
||||
catchRecords = await this.fetchCatchRecords(entryIds, userId);
|
||||
}
|
||||
|
||||
// Combine the data exactly like master branch
|
||||
const combinedData = entries.map((entry) => {
|
||||
const userCatchRecord = catchRecords.find((record) => record.pokemonId === entry.id) || null;
|
||||
|
||||
const transformedEntry = this.transformPokedexEntry(entry);
|
||||
const transformedCatchRecord = userCatchRecord
|
||||
? this.transformCatchRecord(userCatchRecord)
|
||||
: null;
|
||||
|
||||
return {
|
||||
pokedexEntry: transformedEntry,
|
||||
catchRecord: transformedCatchRecord
|
||||
};
|
||||
});
|
||||
|
||||
// Box placement is calculated dynamically on the frontend based on the current sort order.
|
||||
return combinedData;
|
||||
}
|
||||
|
||||
async findCombinedData(
|
||||
userId: string,
|
||||
page: number = 1,
|
||||
limit: number = 20,
|
||||
enableForms: boolean = true,
|
||||
region: string = '',
|
||||
game: string = ''
|
||||
game: string = '',
|
||||
dexScopes: string[] = []
|
||||
): Promise<CombinedData[]> {
|
||||
const skip = (page - 1) * limit;
|
||||
const pipeline: any[] = [
|
||||
{
|
||||
$lookup: {
|
||||
from: 'catchrecords',
|
||||
localField: '_id',
|
||||
foreignField: 'pokedexEntryId',
|
||||
as: 'catchRecord'
|
||||
}
|
||||
},
|
||||
{
|
||||
$unwind: {
|
||||
path: '$catchRecord',
|
||||
preserveNullAndEmptyArrays: true
|
||||
}
|
||||
},
|
||||
{
|
||||
$sort: {
|
||||
'boxPlacementForms.box': 1,
|
||||
'boxPlacementForms.row': 1,
|
||||
'boxPlacementForms.column': 1
|
||||
}
|
||||
},
|
||||
{ $skip: skip },
|
||||
{ $limit: limit }
|
||||
];
|
||||
const from = (page - 1) * limit;
|
||||
const to = from + limit - 1;
|
||||
const entries =
|
||||
dexScopes.length > 0
|
||||
? this.dedupeEntries(
|
||||
await this.fetchAllDexEntries(dexScopes, enableForms, region, game)
|
||||
).slice(from, to + 1)
|
||||
: await this.fetchEntriesByRange(from, to, enableForms, region, game);
|
||||
|
||||
if (!enableForms) {
|
||||
pipeline.unshift({
|
||||
$match: {
|
||||
'boxPlacement.box': { $ne: null }
|
||||
}
|
||||
});
|
||||
if (!entries || entries.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (region.length > 0) {
|
||||
pipeline.unshift({
|
||||
$match: {
|
||||
regionToCatchIn: region
|
||||
}
|
||||
});
|
||||
// Get catch records for these entries
|
||||
let catchRecords: CatchRecordDB[] = [];
|
||||
if (userId && this.pokedexId) {
|
||||
const entryIds = entries.map((entry) => entry.id);
|
||||
catchRecords = await this.fetchCatchRecords(entryIds, userId);
|
||||
}
|
||||
|
||||
if (game.length > 0) {
|
||||
pipeline.unshift({
|
||||
$match: {
|
||||
gamesToCatchIn: { $in: [game] }
|
||||
}
|
||||
});
|
||||
}
|
||||
// Combine the data exactly like master branch
|
||||
const combinedData = entries.map((entry) => {
|
||||
const userCatchRecord = catchRecords.find((record) => record.pokemonId === entry.id) || null;
|
||||
|
||||
const combinedData: CombinedData[] = await PokedexEntryModel.aggregate(pipeline).exec();
|
||||
const transformedEntry = this.transformPokedexEntry(entry);
|
||||
const transformedCatchRecord = userCatchRecord
|
||||
? this.transformCatchRecord(userCatchRecord)
|
||||
: null;
|
||||
|
||||
// Filter out entries with no catch records
|
||||
const filteredData = combinedData.filter((data) => data.catchRecord);
|
||||
return {
|
||||
pokedexEntry: transformedEntry,
|
||||
catchRecord: transformedCatchRecord
|
||||
};
|
||||
});
|
||||
|
||||
return filteredData.map((data) => ({
|
||||
pokedexEntry: data as PokedexEntry,
|
||||
catchRecord: data.catchRecord as CatchRecord
|
||||
}));
|
||||
// Box placement is calculated dynamically on the frontend based on the current sort order.
|
||||
return combinedData;
|
||||
}
|
||||
|
||||
async countCombinedData(enableForms: boolean, region: string, game: string): Promise<number> {
|
||||
const filter: any = {};
|
||||
async countCombinedData(
|
||||
enableForms: boolean,
|
||||
region: string,
|
||||
game: string,
|
||||
dexScopes: string[] = []
|
||||
): Promise<number> {
|
||||
if (dexScopes.length > 0) {
|
||||
const entries = this.dedupeEntries(
|
||||
await this.fetchAllDexEntries(dexScopes, enableForms, region, game)
|
||||
);
|
||||
return entries.length;
|
||||
}
|
||||
|
||||
let query = this.supabase.from('pokedex_entries').select('id', { count: 'exact', head: true });
|
||||
|
||||
// Apply same filters as in findCombinedData
|
||||
if (!enableForms) {
|
||||
filter['boxPlacement.box'] = { $ne: null };
|
||||
// Filter to base forms: NULL or 'male' (gendered species), plus Unown "A".
|
||||
query = query.or('form.is.null,form.eq.male,and(pokemon.eq.Unown,form.eq.A)');
|
||||
}
|
||||
|
||||
if (region.length > 0) {
|
||||
filter['regionToCatchIn'] = region;
|
||||
if (region) {
|
||||
query = query.eq('regionToCatchIn', region);
|
||||
}
|
||||
|
||||
if (game.length > 0) {
|
||||
filter['gamesToCatchIn'] = { $in: [game] };
|
||||
if (game) {
|
||||
query = query.contains('gamesToCatchIn', [game]);
|
||||
}
|
||||
|
||||
try {
|
||||
const count = await PokedexEntryModel.countDocuments(filter).exec();
|
||||
return count;
|
||||
} catch (error) {
|
||||
console.error('Error counting documents:', error);
|
||||
throw error;
|
||||
const { count, error } = await query;
|
||||
|
||||
if (error) {
|
||||
console.error('Error counting combined data:', error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return count || 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,145 @@
|
||||
import PokedexEntryModel, { type PokedexEntry } from '$lib/models/PokedexEntry';
|
||||
import {
|
||||
type CatchInformationItem,
|
||||
type PokedexEntry,
|
||||
type PokedexEntryDB
|
||||
} from '$lib/models/PokedexEntry';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
class PokedexEntryRepository {
|
||||
constructor(private supabase: SupabaseClient) {}
|
||||
|
||||
private parseCatchInformation(
|
||||
values: string[] | null
|
||||
): Array<string | CatchInformationItem> {
|
||||
if (!values) return [];
|
||||
return values.map((value) => {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed.startsWith('{')) return value;
|
||||
try {
|
||||
const parsed = JSON.parse(trimmed) as Partial<CatchInformationItem>;
|
||||
if (
|
||||
parsed &&
|
||||
typeof parsed.game === 'string' &&
|
||||
typeof parsed.location === 'string' &&
|
||||
typeof parsed.notes === 'string'
|
||||
) {
|
||||
return {
|
||||
game: parsed.game,
|
||||
location: parsed.location,
|
||||
notes: parsed.notes
|
||||
};
|
||||
}
|
||||
} catch {
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
private serializeCatchInformation(values: Array<string | CatchInformationItem>): string[] {
|
||||
return values.map((value) => (typeof value === 'string' ? value : JSON.stringify(value)));
|
||||
}
|
||||
|
||||
// Transform Supabase data to match frontend expectations (minimal transformation)
|
||||
private transformPokedexEntry(entry: PokedexEntryDB): PokedexEntry {
|
||||
return {
|
||||
_id: entry.id.toString(),
|
||||
pokedexNumber: entry.pokedexNumber,
|
||||
pokemon: entry.pokemon,
|
||||
form: entry.form || '',
|
||||
spriteKey: entry.spriteKey || '',
|
||||
canGigantamax: entry.canGigantamax,
|
||||
regionToCatchIn: entry.regionToCatchIn || '',
|
||||
gamesToCatchIn: entry.gamesToCatchIn || [],
|
||||
regionToEvolveIn: entry.regionToEvolveIn || '',
|
||||
evolutionInformation: entry.evolutionInformation || '',
|
||||
catchInformation: this.parseCatchInformation(entry.catchInformation),
|
||||
notes: entry.notes || ''
|
||||
};
|
||||
}
|
||||
|
||||
async findById(id: string): Promise<PokedexEntry | null> {
|
||||
return PokedexEntryModel.findById(id).exec();
|
||||
const { data, error } = await this.supabase
|
||||
.from('pokedex_entries')
|
||||
.select('*')
|
||||
.eq('id', id)
|
||||
.single();
|
||||
|
||||
if (error || !data) return null;
|
||||
return this.transformPokedexEntry(data);
|
||||
}
|
||||
|
||||
async findAll(): Promise<PokedexEntry[]> {
|
||||
return PokedexEntryModel.find().exec();
|
||||
const { data, error } = await this.supabase
|
||||
.from('pokedex_entries')
|
||||
.select('*')
|
||||
.order('pokedexNumber', { ascending: true });
|
||||
|
||||
if (error || !data) return [];
|
||||
return data.map((entry) => this.transformPokedexEntry(entry));
|
||||
}
|
||||
|
||||
async create(data: Partial<PokedexEntry>): Promise<PokedexEntry> {
|
||||
return PokedexEntryModel.create(data);
|
||||
// Transform to database format (minimal transformation needed)
|
||||
const dbData: Partial<PokedexEntryDB> = {};
|
||||
if (data.pokedexNumber !== undefined) dbData.pokedexNumber = data.pokedexNumber;
|
||||
if (data.pokemon !== undefined) dbData.pokemon = data.pokemon;
|
||||
if (data.form !== undefined) dbData.form = data.form;
|
||||
if (data.spriteKey !== undefined) dbData.spriteKey = data.spriteKey;
|
||||
if (data.canGigantamax !== undefined) dbData.canGigantamax = data.canGigantamax;
|
||||
if (data.regionToCatchIn !== undefined) dbData.regionToCatchIn = data.regionToCatchIn;
|
||||
if (data.gamesToCatchIn !== undefined) dbData.gamesToCatchIn = data.gamesToCatchIn;
|
||||
if (data.regionToEvolveIn !== undefined) dbData.regionToEvolveIn = data.regionToEvolveIn;
|
||||
if (data.evolutionInformation !== undefined)
|
||||
dbData.evolutionInformation = data.evolutionInformation;
|
||||
if (data.catchInformation !== undefined) {
|
||||
dbData.catchInformation = this.serializeCatchInformation(data.catchInformation);
|
||||
}
|
||||
if (data.notes !== undefined) dbData.notes = data.notes;
|
||||
// Box placement is calculated dynamically - not stored in database
|
||||
|
||||
const { data: result, error } = await this.supabase
|
||||
.from('pokedex_entries')
|
||||
.insert(dbData)
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error || !result) throw new Error('Failed to create pokedex entry');
|
||||
return this.transformPokedexEntry(result);
|
||||
}
|
||||
|
||||
async update(id: string, data: Partial<PokedexEntry>): Promise<PokedexEntry | null> {
|
||||
return PokedexEntryModel.findByIdAndUpdate(id, data, { new: true }).exec();
|
||||
// Transform to database format (minimal transformation needed)
|
||||
const dbData: Partial<PokedexEntryDB> = {};
|
||||
if (data.pokedexNumber !== undefined) dbData.pokedexNumber = data.pokedexNumber;
|
||||
if (data.pokemon !== undefined) dbData.pokemon = data.pokemon;
|
||||
if (data.form !== undefined) dbData.form = data.form;
|
||||
if (data.spriteKey !== undefined) dbData.spriteKey = data.spriteKey;
|
||||
if (data.canGigantamax !== undefined) dbData.canGigantamax = data.canGigantamax;
|
||||
if (data.regionToCatchIn !== undefined) dbData.regionToCatchIn = data.regionToCatchIn;
|
||||
if (data.gamesToCatchIn !== undefined) dbData.gamesToCatchIn = data.gamesToCatchIn;
|
||||
if (data.regionToEvolveIn !== undefined) dbData.regionToEvolveIn = data.regionToEvolveIn;
|
||||
if (data.evolutionInformation !== undefined)
|
||||
dbData.evolutionInformation = data.evolutionInformation;
|
||||
if (data.catchInformation !== undefined) {
|
||||
dbData.catchInformation = this.serializeCatchInformation(data.catchInformation);
|
||||
}
|
||||
if (data.notes !== undefined) dbData.notes = data.notes;
|
||||
// Box placement is calculated dynamically - not stored in database
|
||||
|
||||
const { data: result, error } = await this.supabase
|
||||
.from('pokedex_entries')
|
||||
.update(dbData)
|
||||
.eq('id', id)
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error || !result) return null;
|
||||
return this.transformPokedexEntry(result);
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await PokedexEntryModel.findByIdAndDelete(id).exec();
|
||||
await this.supabase.from('pokedex_entries').delete().eq('id', id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
import type {
|
||||
PokedexExportIntegration,
|
||||
PokedexExportIntegrationDB
|
||||
} from '$lib/models/PokedexExportIntegration';
|
||||
|
||||
class PokedexExportIntegrationRepository {
|
||||
constructor(
|
||||
private supabase: SupabaseClient,
|
||||
private userId: string,
|
||||
private pokedexId: string | null
|
||||
) {}
|
||||
|
||||
private transform(db: PokedexExportIntegrationDB): PokedexExportIntegration {
|
||||
return {
|
||||
_id: db.id,
|
||||
userId: db.userId,
|
||||
pokedexId: db.pokedexId,
|
||||
provider: db.provider,
|
||||
enabled: db.enabled,
|
||||
fileName: db.fileName,
|
||||
folderId: db.folderId,
|
||||
path: db.path,
|
||||
accessToken: db.accessToken,
|
||||
refreshToken: db.refreshToken,
|
||||
accessTokenExpiresAt: db.accessTokenExpiresAt,
|
||||
metadata: db.metadata,
|
||||
lastExportedAt: db.lastExportedAt,
|
||||
lastError: db.lastError
|
||||
};
|
||||
}
|
||||
|
||||
private baseQuery() {
|
||||
return this.supabase.from('pokedex_export_integrations').select('*').eq('userId', this.userId);
|
||||
}
|
||||
|
||||
private addPokedexScope(query: ReturnType<SupabaseClient['from']>) {
|
||||
if (this.pokedexId) {
|
||||
return query.eq('pokedexId', this.pokedexId);
|
||||
}
|
||||
return query.is('pokedexId', null);
|
||||
}
|
||||
|
||||
async listEnabled(): Promise<PokedexExportIntegration[]> {
|
||||
const { data, error } = await this.addPokedexScope(this.baseQuery()).eq('enabled', true);
|
||||
|
||||
if (error) {
|
||||
console.error('Failed to load export integrations:', error);
|
||||
throw new Error(`Failed to load export integrations: ${error.message}`);
|
||||
}
|
||||
if (!data) return [];
|
||||
return data.map((row) => this.transform(row));
|
||||
}
|
||||
|
||||
async listAll(): Promise<PokedexExportIntegration[]> {
|
||||
const { data, error } = await this.addPokedexScope(this.baseQuery());
|
||||
|
||||
if (error) {
|
||||
console.error('Failed to load export integrations:', error);
|
||||
throw new Error(`Failed to load export integrations: ${error.message}`);
|
||||
}
|
||||
if (!data) return [];
|
||||
return data.map((row) => this.transform(row));
|
||||
}
|
||||
|
||||
async upsert(
|
||||
data: Partial<PokedexExportIntegrationDB> &
|
||||
Pick<PokedexExportIntegrationDB, 'provider'>
|
||||
): Promise<PokedexExportIntegration> {
|
||||
const payload: Partial<PokedexExportIntegrationDB> = {
|
||||
userId: this.userId,
|
||||
pokedexId: null,
|
||||
...data
|
||||
};
|
||||
const { data: result, error } = await this.supabase
|
||||
.from('pokedex_export_integrations')
|
||||
.upsert(payload, {
|
||||
onConflict: 'userId,provider'
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
console.error('Failed to upsert export integration:', error);
|
||||
throw new Error(`Failed to save export integration: ${error.message}`);
|
||||
}
|
||||
if (!result) {
|
||||
throw new Error('Failed to save export integration: No result returned');
|
||||
}
|
||||
return this.transform(result);
|
||||
}
|
||||
|
||||
async listEnabledForPokedexOrUser(): Promise<PokedexExportIntegration[]> {
|
||||
const base = this.supabase
|
||||
.from('pokedex_export_integrations')
|
||||
.select('*')
|
||||
.eq('userId', this.userId)
|
||||
.eq('enabled', true);
|
||||
const query = this.pokedexId
|
||||
? base.or(`pokedexId.eq.${this.pokedexId},pokedexId.is.null`)
|
||||
: base.is('pokedexId', null);
|
||||
const { data, error } = await query;
|
||||
if (error) {
|
||||
console.error('Failed to load export integrations:', error);
|
||||
throw new Error(`Failed to load export integrations: ${error.message}`);
|
||||
}
|
||||
if (!data) return [];
|
||||
return data.map((row) => this.transform(row));
|
||||
}
|
||||
|
||||
async updateTokens(
|
||||
id: string,
|
||||
patch: {
|
||||
accessToken?: string;
|
||||
refreshToken?: string | null;
|
||||
accessTokenExpiresAt?: string | null;
|
||||
}
|
||||
): Promise<void> {
|
||||
const query = this.supabase
|
||||
.from('pokedex_export_integrations')
|
||||
.update(patch)
|
||||
.eq('id', id)
|
||||
.eq('userId', this.userId);
|
||||
const { error } = this.pokedexId
|
||||
? await query.eq('pokedexId', this.pokedexId)
|
||||
: await query.is('pokedexId', null);
|
||||
|
||||
if (error) {
|
||||
console.error('Failed to update export integration tokens:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async updateExportStatus(
|
||||
id: string,
|
||||
patch: {
|
||||
lastExportedAt?: string | null;
|
||||
lastError?: string | null;
|
||||
metadata?: Record<string, unknown> | null;
|
||||
folderId?: string | null;
|
||||
path?: string | null;
|
||||
}
|
||||
): Promise<void> {
|
||||
const query = this.supabase
|
||||
.from('pokedex_export_integrations')
|
||||
.update(patch)
|
||||
.eq('id', id)
|
||||
.eq('userId', this.userId);
|
||||
const { error } = this.pokedexId
|
||||
? await query.eq('pokedexId', this.pokedexId)
|
||||
: await query.is('pokedexId', null);
|
||||
|
||||
if (error) {
|
||||
console.error('Failed to update export integration status:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default PokedexExportIntegrationRepository;
|
||||
@@ -0,0 +1,141 @@
|
||||
import type { Pokedex, PokedexDB } from '$lib/models/Pokedex';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
class PokedexRepository {
|
||||
constructor(
|
||||
private supabase: SupabaseClient,
|
||||
private userId: string
|
||||
) {}
|
||||
|
||||
private transform(db: PokedexDB, dexScopes: string[] = []): Pokedex {
|
||||
return {
|
||||
_id: db.id,
|
||||
userId: db.userId,
|
||||
name: db.name,
|
||||
description: db.description || '',
|
||||
isLivingDex: db.isLivingDex,
|
||||
isShinyDex: db.isShinyDex,
|
||||
isOriginDex: db.isOriginDex,
|
||||
isFormDex: db.isFormDex,
|
||||
gameScope: db.gameScope,
|
||||
dexScopes
|
||||
};
|
||||
}
|
||||
|
||||
private transformToDatabase(data: Partial<Pokedex>): Partial<PokedexDB> {
|
||||
const dbData: Partial<PokedexDB> = {};
|
||||
if (data.name !== undefined) dbData.name = data.name;
|
||||
if (data.description !== undefined) dbData.description = data.description;
|
||||
if (data.isLivingDex !== undefined) dbData.isLivingDex = data.isLivingDex;
|
||||
if (data.isShinyDex !== undefined) dbData.isShinyDex = data.isShinyDex;
|
||||
if (data.isOriginDex !== undefined) dbData.isOriginDex = data.isOriginDex;
|
||||
if (data.isFormDex !== undefined) dbData.isFormDex = data.isFormDex;
|
||||
if (data.gameScope !== undefined) dbData.gameScope = data.gameScope;
|
||||
return dbData;
|
||||
}
|
||||
|
||||
private async fetchDexScopesMap(pokedexIds: string[]): Promise<Map<string, string[]>> {
|
||||
if (pokedexIds.length === 0) return new Map();
|
||||
const { data, error } = await this.supabase
|
||||
.from('pokedex_dex_scopes')
|
||||
.select('pokedexId, dexId')
|
||||
.in('pokedexId', pokedexIds);
|
||||
|
||||
if (error || !data) return new Map();
|
||||
|
||||
const map = new Map<string, string[]>();
|
||||
for (const row of data) {
|
||||
if (!map.has(row.pokedexId)) map.set(row.pokedexId, []);
|
||||
map.get(row.pokedexId)?.push(row.dexId);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
async findById(id: string): Promise<Pokedex | null> {
|
||||
const { data, error } = await this.supabase
|
||||
.from('pokedexes')
|
||||
.select('*')
|
||||
.eq('id', id)
|
||||
.eq('userId', this.userId)
|
||||
.single();
|
||||
|
||||
if (error || !data) return null;
|
||||
const dexScopesMap = await this.fetchDexScopesMap([data.id]);
|
||||
return this.transform(data, dexScopesMap.get(data.id) || []);
|
||||
}
|
||||
|
||||
async findAll(): Promise<Pokedex[]> {
|
||||
const { data, error } = await this.supabase
|
||||
.from('pokedexes')
|
||||
.select('*')
|
||||
.eq('userId', this.userId)
|
||||
.order('createdAt', { ascending: true });
|
||||
|
||||
if (error || !data) return [];
|
||||
const dexScopesMap = await this.fetchDexScopesMap(data.map((d) => d.id));
|
||||
return data.map((d) => this.transform(d, dexScopesMap.get(d.id) || []));
|
||||
}
|
||||
|
||||
async create(data: Partial<Pokedex>): Promise<Pokedex> {
|
||||
const dbData = {
|
||||
userId: this.userId,
|
||||
...this.transformToDatabase(data)
|
||||
};
|
||||
|
||||
const { data: result, error } = await this.supabase
|
||||
.from('pokedexes')
|
||||
.insert(dbData)
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
console.error('Error creating pokedex:', error);
|
||||
// Preserve the Supabase error code so the API layer can map to a user-friendly response.
|
||||
throw Object.assign(new Error(`Failed to create pokedex: ${error.message}`), {
|
||||
code: error.code
|
||||
});
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
throw new Error('Failed to create pokedex: No result returned');
|
||||
}
|
||||
|
||||
return this.transform(result);
|
||||
}
|
||||
|
||||
async update(id: string, data: Partial<Pokedex>): Promise<Pokedex | null> {
|
||||
const dbData = this.transformToDatabase(data);
|
||||
|
||||
const { data: result, error } = await this.supabase
|
||||
.from('pokedexes')
|
||||
.update(dbData)
|
||||
.eq('id', id)
|
||||
.eq('userId', this.userId)
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
console.error('Error updating pokedex:', error);
|
||||
throw Object.assign(new Error(`Failed to update pokedex: ${error.message}`), {
|
||||
code: error.code
|
||||
});
|
||||
}
|
||||
if (!result) return null;
|
||||
return this.transform(result);
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
const { error } = await this.supabase
|
||||
.from('pokedexes')
|
||||
.delete()
|
||||
.eq('id', id)
|
||||
.eq('userId', this.userId);
|
||||
|
||||
if (error) {
|
||||
console.error('Error deleting pokedex:', error);
|
||||
throw new Error(`Failed to delete pokedex: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default PokedexRepository;
|
||||
@@ -1,24 +1,38 @@
|
||||
import RegionGameMappingModel, { type RegionGameMapping } from '$lib/models/RegionGameMapping';
|
||||
import type { RegionGameMapping } from '$lib/models/RegionGameMapping';
|
||||
|
||||
class RegionGameMappingRepository {
|
||||
async findById(id: string): Promise<RegionGameMapping | null> {
|
||||
return RegionGameMappingModel.findById(id).exec();
|
||||
void id;
|
||||
return null;
|
||||
}
|
||||
|
||||
async findAll(): Promise<RegionGameMapping[]> {
|
||||
return RegionGameMappingModel.find().exec();
|
||||
return [];
|
||||
}
|
||||
|
||||
async create(data: Partial<RegionGameMapping>): Promise<RegionGameMapping> {
|
||||
return RegionGameMappingModel.create(data);
|
||||
async create(data: Partial<RegionGameMapping>): Promise<RegionGameMapping | null> {
|
||||
if (!data.region || !data.game) return null;
|
||||
return {
|
||||
id: data.id,
|
||||
region: data.region,
|
||||
game: data.game
|
||||
};
|
||||
}
|
||||
|
||||
async update(id: string, data: Partial<RegionGameMapping>): Promise<RegionGameMapping | null> {
|
||||
return RegionGameMappingModel.findByIdAndUpdate(id, data, { new: true }).exec();
|
||||
if (!data.region || !data.game) return null;
|
||||
const normalizedId = Number(id);
|
||||
const resolvedId = Number.isFinite(normalizedId) ? normalizedId : data.id;
|
||||
if (typeof resolvedId !== 'number' || !Number.isFinite(resolvedId)) return null;
|
||||
return {
|
||||
id: resolvedId,
|
||||
region: data.region,
|
||||
game: data.game
|
||||
};
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await RegionGameMappingModel.findByIdAndDelete(id).exec();
|
||||
void id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
import type { Pokedex } from '$lib/models/Pokedex';
|
||||
|
||||
type GameDexRow = {
|
||||
id: string;
|
||||
displayName: string;
|
||||
sortOrder: number;
|
||||
isDlc: boolean;
|
||||
parentDexId: string | null;
|
||||
};
|
||||
|
||||
type GameSummary = {
|
||||
displayName: string;
|
||||
releaseYear: number;
|
||||
};
|
||||
|
||||
type GameDexRowWithGame = GameDexRow & {
|
||||
games: GameSummary | GameSummary[] | null;
|
||||
};
|
||||
|
||||
async function getGameIdForScope(
|
||||
supabase: SupabaseClient,
|
||||
gameScope: string
|
||||
): Promise<string | null> {
|
||||
const { data, error } = await supabase
|
||||
.from('games')
|
||||
.select('id')
|
||||
.eq('displayName', gameScope)
|
||||
.maybeSingle();
|
||||
|
||||
if (error || !data) return null;
|
||||
return data.id;
|
||||
}
|
||||
|
||||
export async function resolveDexScopes(
|
||||
supabase: SupabaseClient,
|
||||
pokedex: Pokedex
|
||||
): Promise<string[]> {
|
||||
if (!pokedex.gameScope) return [];
|
||||
if (pokedex.dexScopes && pokedex.dexScopes.length > 0) {
|
||||
return pokedex.dexScopes;
|
||||
}
|
||||
|
||||
const gameId = await getGameIdForScope(supabase, pokedex.gameScope);
|
||||
if (!gameId) return [];
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('game_dexes')
|
||||
.select('id')
|
||||
.eq('gameId', gameId)
|
||||
.order('sortOrder', { ascending: true })
|
||||
.order('displayName', { ascending: true });
|
||||
|
||||
if (error || !data) return [];
|
||||
return data.map((row) => row.id);
|
||||
}
|
||||
|
||||
export async function setPokedexDexScopes(
|
||||
supabase: SupabaseClient,
|
||||
pokedexId: string,
|
||||
dexIds: string[]
|
||||
): Promise<void> {
|
||||
const uniqueDexIds = Array.from(new Set(dexIds));
|
||||
|
||||
const { error: deleteError } = await supabase
|
||||
.from('pokedex_dex_scopes')
|
||||
.delete()
|
||||
.eq('pokedexId', pokedexId);
|
||||
|
||||
if (deleteError) {
|
||||
throw new Error(`Failed to clear dex scopes: ${deleteError.message}`);
|
||||
}
|
||||
|
||||
if (uniqueDexIds.length === 0) return;
|
||||
|
||||
const rows = uniqueDexIds.map((dexId) => ({
|
||||
pokedexId,
|
||||
dexId
|
||||
}));
|
||||
|
||||
const { error: insertError } = await supabase.from('pokedex_dex_scopes').insert(rows);
|
||||
if (insertError) {
|
||||
throw new Error(`Failed to save dex scopes: ${insertError.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function listGameDexes(
|
||||
supabase: SupabaseClient
|
||||
): Promise<{
|
||||
gameDexes: Record<string, GameDexRow[]>;
|
||||
gameOrder: string[];
|
||||
games: { displayName: string; releaseYear: number }[];
|
||||
}> {
|
||||
const { data, error } = await supabase
|
||||
.from('game_dexes')
|
||||
.select('id, displayName, sortOrder, isDlc, parentDexId, games!inner(displayName, releaseYear)')
|
||||
.order('sortOrder', { ascending: true })
|
||||
.order('displayName', { ascending: true });
|
||||
|
||||
if (error || !data) return { gameDexes: {}, gameOrder: [], games: [] };
|
||||
|
||||
const grouped: Record<string, GameDexRow[]> = {};
|
||||
const releaseYears: Record<string, number> = {};
|
||||
const rows = data as GameDexRowWithGame[];
|
||||
for (const row of rows) {
|
||||
const game = Array.isArray(row.games) ? row.games[0] : row.games;
|
||||
if (!game) continue;
|
||||
const gameName = game.displayName;
|
||||
if (!grouped[gameName]) grouped[gameName] = [];
|
||||
if (releaseYears[gameName] == null) {
|
||||
releaseYears[gameName] = game.releaseYear;
|
||||
}
|
||||
grouped[gameName].push({
|
||||
id: row.id,
|
||||
displayName: row.displayName,
|
||||
sortOrder: row.sortOrder,
|
||||
isDlc: row.isDlc,
|
||||
parentDexId: row.parentDexId
|
||||
});
|
||||
}
|
||||
|
||||
const games = Object.keys(grouped)
|
||||
.map((name) => ({
|
||||
displayName: name,
|
||||
releaseYear: releaseYears[name] ?? 0
|
||||
}))
|
||||
.sort((a, b) => {
|
||||
if (a.releaseYear !== b.releaseYear) return b.releaseYear - a.releaseYear;
|
||||
return a.displayName.localeCompare(b.displayName);
|
||||
});
|
||||
|
||||
const gameOrder = games.map((game) => game.displayName);
|
||||
|
||||
return { gameDexes: grouped, gameOrder, games };
|
||||
}
|
||||
@@ -0,0 +1,493 @@
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
import type { CombinedData } from '$lib/models/CombinedData';
|
||||
import type { Pokedex } from '$lib/models/Pokedex';
|
||||
import type { ExportProvider, PokedexExportIntegration } from '$lib/models/PokedexExportIntegration';
|
||||
import PokedexRepository from '$lib/repositories/PokedexRepository';
|
||||
import CombinedDataRepository from '$lib/repositories/CombinedDataRepository';
|
||||
import PokedexExportIntegrationRepository from '$lib/repositories/PokedexExportIntegrationRepository';
|
||||
import { resolveDexScopes } from '$lib/services/PokedexDexScopeService';
|
||||
import { getEnv } from '$lib/utils/env';
|
||||
|
||||
type ExportFailure = {
|
||||
integrationId: string;
|
||||
provider: ExportProvider;
|
||||
error: string;
|
||||
};
|
||||
|
||||
export type PokedexExportResult = {
|
||||
attempted: number;
|
||||
succeeded: number;
|
||||
failed: ExportFailure[];
|
||||
};
|
||||
|
||||
function csvEscape(value: unknown): string {
|
||||
if (value === null || value === undefined) return '';
|
||||
const str = String(value);
|
||||
if (/[",\n\r]/.test(str)) {
|
||||
return `"${str.replace(/"/g, '""')}"`;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function sanitizeFileName(name: string, fallback: string): string {
|
||||
const trimmed = name.trim();
|
||||
const safe = trimmed.replace(/[\\/:*?"<>|]+/g, '-');
|
||||
if (!safe) return fallback;
|
||||
return safe.endsWith('.csv') ? safe : `${safe}.csv`;
|
||||
}
|
||||
|
||||
function buildCsv(pokedex: Pokedex, combinedData: CombinedData[]): string {
|
||||
const headers = [
|
||||
'pokemonId',
|
||||
'pokedexNumber',
|
||||
'pokemon',
|
||||
'form',
|
||||
'caught',
|
||||
'haveToEvolve',
|
||||
'inHome',
|
||||
'personalNotes'
|
||||
];
|
||||
|
||||
const lines = [headers.map(csvEscape).join(',')];
|
||||
|
||||
for (const row of combinedData) {
|
||||
const entry = row.pokedexEntry;
|
||||
const catchRecord = row.catchRecord ?? {
|
||||
caught: false,
|
||||
haveToEvolve: false,
|
||||
inHome: false,
|
||||
hasGigantamaxed: false,
|
||||
personalNotes: ''
|
||||
};
|
||||
|
||||
const values = [
|
||||
entry._id,
|
||||
entry.pokedexNumber,
|
||||
entry.pokemon,
|
||||
entry.form || '',
|
||||
catchRecord.caught,
|
||||
catchRecord.haveToEvolve,
|
||||
catchRecord.inHome,
|
||||
catchRecord.personalNotes || ''
|
||||
];
|
||||
|
||||
lines.push(values.map(csvEscape).join(','));
|
||||
}
|
||||
|
||||
return lines.join('\r\n');
|
||||
}
|
||||
|
||||
function shouldRefreshToken(expiresAt: string | null): boolean {
|
||||
if (!expiresAt) return false;
|
||||
const expiry = new Date(expiresAt).getTime();
|
||||
if (!Number.isFinite(expiry)) return false;
|
||||
// Refresh if within 60 seconds of expiry.
|
||||
return expiry - Date.now() < 60_000;
|
||||
}
|
||||
|
||||
async function refreshGoogleToken(
|
||||
integration: PokedexExportIntegration,
|
||||
repo: PokedexExportIntegrationRepository
|
||||
): Promise<PokedexExportIntegration> {
|
||||
if (!integration.refreshToken) {
|
||||
throw new Error('Missing Google refresh token');
|
||||
}
|
||||
|
||||
const env = getEnv();
|
||||
const clientId = env.GOOGLE_OAUTH_CLIENT_ID;
|
||||
const clientSecret = env.GOOGLE_OAUTH_CLIENT_SECRET;
|
||||
if (!clientId || !clientSecret) {
|
||||
throw new Error('Missing Google OAuth client credentials');
|
||||
}
|
||||
|
||||
const params = new URLSearchParams({
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
refresh_token: integration.refreshToken,
|
||||
grant_type: 'refresh_token'
|
||||
});
|
||||
|
||||
const response = await fetch('https://oauth2.googleapis.com/token', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: params.toString()
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(`Google token refresh failed: ${response.status} ${text}`);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as {
|
||||
access_token: string;
|
||||
expires_in?: number;
|
||||
};
|
||||
|
||||
const expiresAt = data.expires_in
|
||||
? new Date(Date.now() + data.expires_in * 1000).toISOString()
|
||||
: null;
|
||||
|
||||
await repo.updateTokens(integration._id, {
|
||||
accessToken: data.access_token,
|
||||
accessTokenExpiresAt: expiresAt
|
||||
});
|
||||
|
||||
return {
|
||||
...integration,
|
||||
accessToken: data.access_token,
|
||||
accessTokenExpiresAt: expiresAt
|
||||
};
|
||||
}
|
||||
|
||||
async function refreshDropboxToken(
|
||||
integration: PokedexExportIntegration,
|
||||
repo: PokedexExportIntegrationRepository
|
||||
): Promise<PokedexExportIntegration> {
|
||||
if (!integration.refreshToken) {
|
||||
throw new Error('Missing Dropbox refresh token');
|
||||
}
|
||||
|
||||
const env = getEnv();
|
||||
const clientId = env.DROPBOX_OAUTH_CLIENT_ID;
|
||||
const clientSecret = env.DROPBOX_OAUTH_CLIENT_SECRET;
|
||||
if (!clientId || !clientSecret) {
|
||||
throw new Error('Missing Dropbox OAuth client credentials');
|
||||
}
|
||||
|
||||
const params = new URLSearchParams({
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
refresh_token: integration.refreshToken,
|
||||
grant_type: 'refresh_token'
|
||||
});
|
||||
|
||||
const response = await fetch('https://api.dropbox.com/oauth2/token', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: params.toString()
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(`Dropbox token refresh failed: ${response.status} ${text}`);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as {
|
||||
access_token: string;
|
||||
expires_in?: number;
|
||||
};
|
||||
|
||||
const expiresAt = data.expires_in
|
||||
? new Date(Date.now() + data.expires_in * 1000).toISOString()
|
||||
: null;
|
||||
|
||||
await repo.updateTokens(integration._id, {
|
||||
accessToken: data.access_token,
|
||||
accessTokenExpiresAt: expiresAt
|
||||
});
|
||||
|
||||
return {
|
||||
...integration,
|
||||
accessToken: data.access_token,
|
||||
accessTokenExpiresAt: expiresAt
|
||||
};
|
||||
}
|
||||
|
||||
async function ensureAccessToken(
|
||||
integration: PokedexExportIntegration,
|
||||
repo: PokedexExportIntegrationRepository
|
||||
): Promise<PokedexExportIntegration> {
|
||||
if (!shouldRefreshToken(integration.accessTokenExpiresAt)) {
|
||||
return integration;
|
||||
}
|
||||
|
||||
if (integration.provider === 'google_drive') {
|
||||
return await refreshGoogleToken(integration, repo);
|
||||
}
|
||||
|
||||
if (integration.provider === 'dropbox') {
|
||||
return await refreshDropboxToken(integration, repo);
|
||||
}
|
||||
|
||||
return integration;
|
||||
}
|
||||
|
||||
type GoogleDriveMetadata = {
|
||||
files?: Record<string, string>;
|
||||
};
|
||||
|
||||
function getGoogleFileId(metadata: Record<string, unknown> | null, pokedexId: string): string | null {
|
||||
const data = metadata as GoogleDriveMetadata | null;
|
||||
const fileId = data?.files?.[pokedexId];
|
||||
return typeof fileId === 'string' && fileId ? fileId : null;
|
||||
}
|
||||
|
||||
function withGoogleFileId(
|
||||
metadata: Record<string, unknown> | null,
|
||||
pokedexId: string,
|
||||
fileId: string
|
||||
): Record<string, unknown> {
|
||||
const data = (metadata as GoogleDriveMetadata | null) ?? {};
|
||||
const files = { ...(data.files ?? {}) };
|
||||
files[pokedexId] = fileId;
|
||||
return { ...data, files };
|
||||
}
|
||||
|
||||
function withoutGoogleFileId(
|
||||
metadata: Record<string, unknown> | null,
|
||||
pokedexId: string
|
||||
): Record<string, unknown> | null {
|
||||
const data = (metadata as GoogleDriveMetadata | null) ?? {};
|
||||
if (!data.files || !data.files[pokedexId]) return metadata;
|
||||
const files = { ...data.files };
|
||||
delete files[pokedexId];
|
||||
const next = { ...data, files };
|
||||
if (Object.keys(files).length === 0) {
|
||||
delete (next as GoogleDriveMetadata).files;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
async function uploadToGoogleDrive(
|
||||
integration: PokedexExportIntegration,
|
||||
repo: PokedexExportIntegrationRepository,
|
||||
pokedex: Pokedex,
|
||||
csv: string
|
||||
): Promise<void> {
|
||||
const refreshed = await ensureAccessToken(integration, repo);
|
||||
const fileName = sanitizeFileName(pokedex.name, 'pokedex.csv');
|
||||
|
||||
let folderId = refreshed.folderId?.trim() ?? '';
|
||||
if (!folderId) {
|
||||
try {
|
||||
const folderResponse = await fetch(
|
||||
'https://www.googleapis.com/drive/v3/files?' +
|
||||
new URLSearchParams({
|
||||
q: "name='Living Dex Tracker' and mimeType='application/vnd.google-apps.folder' and trashed=false",
|
||||
fields: 'files(id,name)',
|
||||
pageSize: '1'
|
||||
}).toString(),
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${refreshed.accessToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (folderResponse.ok) {
|
||||
const folderData = (await folderResponse.json()) as { files?: Array<{ id: string }> };
|
||||
folderId = folderData.files?.[0]?.id ?? '';
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to lookup Google Drive folder, using root:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!folderId) {
|
||||
try {
|
||||
const createResponse = await fetch('https://www.googleapis.com/drive/v3/files', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${refreshed.accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: 'Living Dex Tracker',
|
||||
mimeType: 'application/vnd.google-apps.folder'
|
||||
})
|
||||
});
|
||||
if (createResponse.ok) {
|
||||
const created = (await createResponse.json()) as { id?: string };
|
||||
folderId = created.id ?? '';
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to create Google Drive folder, using root:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const existingFileId = getGoogleFileId(refreshed.metadata, pokedex._id);
|
||||
let currentFileId = existingFileId;
|
||||
|
||||
for (let attempt = 0; attempt < 2; attempt++) {
|
||||
const metadata: Record<string, unknown> = {
|
||||
name: fileName,
|
||||
mimeType: 'text/csv'
|
||||
};
|
||||
if (folderId && !currentFileId) {
|
||||
metadata.parents = [folderId];
|
||||
}
|
||||
|
||||
const boundary = `boundary_${randomUUID()}`;
|
||||
const body = [
|
||||
`--${boundary}`,
|
||||
'Content-Type: application/json; charset=UTF-8',
|
||||
'',
|
||||
JSON.stringify(metadata),
|
||||
`--${boundary}`,
|
||||
'Content-Type: text/csv',
|
||||
'',
|
||||
csv,
|
||||
`--${boundary}--`
|
||||
].join('\r\n');
|
||||
|
||||
const url = currentFileId
|
||||
? `https://www.googleapis.com/upload/drive/v3/files/${currentFileId}?uploadType=multipart`
|
||||
: 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart';
|
||||
const method = currentFileId ? 'PATCH' : 'POST';
|
||||
const uploadUrl = currentFileId && folderId
|
||||
? `${url}&addParents=${encodeURIComponent(folderId)}`
|
||||
: url;
|
||||
|
||||
const response = await fetch(uploadUrl, {
|
||||
method,
|
||||
headers: {
|
||||
Authorization: `Bearer ${refreshed.accessToken}`,
|
||||
'Content-Type': `multipart/related; boundary=${boundary}`
|
||||
},
|
||||
body
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
if (currentFileId && response.status === 404 && attempt === 0) {
|
||||
const nextMetadata = withoutGoogleFileId(refreshed.metadata, pokedex._id);
|
||||
await repo.updateExportStatus(refreshed._id, { metadata: nextMetadata });
|
||||
currentFileId = null;
|
||||
continue;
|
||||
}
|
||||
throw new Error(`Google Drive upload failed: ${response.status} ${text}`);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as { id?: string };
|
||||
if (data.id && folderId) {
|
||||
await repo.updateExportStatus(refreshed._id, {
|
||||
folderId
|
||||
});
|
||||
}
|
||||
|
||||
if (!currentFileId && data.id) {
|
||||
const nextMetadata = withGoogleFileId(refreshed.metadata, pokedex._id, data.id);
|
||||
await repo.updateExportStatus(refreshed._id, { metadata: nextMetadata });
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadToDropbox(
|
||||
integration: PokedexExportIntegration,
|
||||
repo: PokedexExportIntegrationRepository,
|
||||
pokedex: Pokedex,
|
||||
csv: string
|
||||
): Promise<void> {
|
||||
const refreshed = await ensureAccessToken(integration, repo);
|
||||
const fileName = sanitizeFileName(pokedex.name, 'pokedex.csv');
|
||||
const trimmedPath = refreshed.path?.trim() ?? '';
|
||||
let targetPath = trimmedPath;
|
||||
if (!targetPath) {
|
||||
targetPath = `/${fileName}`;
|
||||
} else if (targetPath.endsWith('/')) {
|
||||
targetPath = `${targetPath}${fileName}`;
|
||||
} else if (!targetPath.toLowerCase().endsWith('.csv')) {
|
||||
targetPath = `${targetPath}/${fileName}`;
|
||||
}
|
||||
|
||||
const response = await fetch('https://content.dropboxapi.com/2/files/upload', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${refreshed.accessToken}`,
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Dropbox-API-Arg': JSON.stringify({
|
||||
path: targetPath,
|
||||
mode: 'overwrite',
|
||||
mute: true
|
||||
})
|
||||
},
|
||||
body: csv
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(`Dropbox upload failed: ${response.status} ${text}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function exportToIntegration(
|
||||
integration: PokedexExportIntegration,
|
||||
repo: PokedexExportIntegrationRepository,
|
||||
pokedex: Pokedex,
|
||||
csv: string
|
||||
): Promise<void> {
|
||||
if (integration.provider === 'google_drive') {
|
||||
await uploadToGoogleDrive(integration, repo, pokedex, csv);
|
||||
return;
|
||||
}
|
||||
if (integration.provider === 'dropbox') {
|
||||
await uploadToDropbox(integration, repo, pokedex, csv);
|
||||
}
|
||||
}
|
||||
|
||||
export async function exportPokedexIfConfigured(
|
||||
supabase: SupabaseClient,
|
||||
userId: string,
|
||||
pokedexId: string
|
||||
): Promise<PokedexExportResult> {
|
||||
const pokedexRepo = new PokedexRepository(supabase, userId);
|
||||
const pokedex = await pokedexRepo.findById(pokedexId);
|
||||
if (!pokedex) {
|
||||
return { attempted: 0, succeeded: 0, failed: [] };
|
||||
}
|
||||
|
||||
const integrationRepo = new PokedexExportIntegrationRepository(supabase, userId, pokedexId);
|
||||
const integrations = await integrationRepo.listEnabledForPokedexOrUser();
|
||||
if (integrations.length === 0) {
|
||||
return { attempted: 0, succeeded: 0, failed: [] };
|
||||
}
|
||||
|
||||
const dexScopes = await resolveDexScopes(supabase, pokedex);
|
||||
const combinedRepo = new CombinedDataRepository(supabase, userId, pokedexId);
|
||||
const combinedData = await combinedRepo.findAllCombinedData(
|
||||
userId,
|
||||
!!pokedex.isFormDex,
|
||||
'',
|
||||
pokedex.gameScope || '',
|
||||
dexScopes
|
||||
);
|
||||
const csv = buildCsv(pokedex, combinedData);
|
||||
|
||||
const failures: ExportFailure[] = [];
|
||||
let successes = 0;
|
||||
|
||||
for (const integration of integrations) {
|
||||
const scopedRepo = new PokedexExportIntegrationRepository(
|
||||
supabase,
|
||||
userId,
|
||||
integration.pokedexId ?? null
|
||||
);
|
||||
try {
|
||||
await exportToIntegration(integration, scopedRepo, pokedex, csv);
|
||||
await scopedRepo.updateExportStatus(integration._id, {
|
||||
lastExportedAt: new Date().toISOString(),
|
||||
lastError: null
|
||||
});
|
||||
successes++;
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
failures.push({
|
||||
integrationId: integration._id,
|
||||
provider: integration.provider,
|
||||
error: message
|
||||
});
|
||||
await scopedRepo.updateExportStatus(integration._id, {
|
||||
lastError: message
|
||||
});
|
||||
console.error('Failed to export pokedex:', integration.provider, message);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
attempted: integrations.length,
|
||||
succeeded: successes,
|
||||
failed: failures
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
import type { Pokedex } from '$lib/models/Pokedex';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
import { resolveDexScopes } from '$lib/services/PokedexDexScopeService';
|
||||
|
||||
/**
|
||||
* Calculate expected pokedex entries based on pokedex configuration
|
||||
* Applies the same filtering logic as CombinedDataRepository
|
||||
* @throws Error if the Supabase query fails
|
||||
*/
|
||||
export async function calculateExpectedEntries(
|
||||
supabase: SupabaseClient,
|
||||
pokedex: Pokedex
|
||||
): Promise<number[]> {
|
||||
const dexScopes = await resolveDexScopes(supabase, pokedex);
|
||||
|
||||
if (dexScopes.length > 0) {
|
||||
const { data: dexEntries, error: dexError } = await supabase
|
||||
.from('game_pokedex_entries')
|
||||
.select('pokemonId')
|
||||
.in('dexId', dexScopes);
|
||||
|
||||
if (dexError) {
|
||||
console.error('Error calculating dex-scoped entries:', dexError);
|
||||
throw new Error(`Failed to calculate dex-scoped entries: ${dexError.message}`);
|
||||
}
|
||||
|
||||
const uniqueIds = Array.from(new Set(dexEntries?.map((row) => row.pokemonId) || []));
|
||||
if (uniqueIds.length === 0) return [];
|
||||
|
||||
if (!pokedex.isFormDex) {
|
||||
const { data: entries, error: entryError } = await supabase
|
||||
.from('pokedex_entries')
|
||||
.select('id, pokemon, form')
|
||||
.in('id', uniqueIds);
|
||||
|
||||
if (entryError) {
|
||||
console.error('Error filtering base forms for dex scopes:', entryError);
|
||||
throw new Error(`Failed to filter base forms: ${entryError.message}`);
|
||||
}
|
||||
|
||||
return (
|
||||
entries
|
||||
?.filter(
|
||||
(entry) =>
|
||||
entry.form === null ||
|
||||
entry.form === 'male' ||
|
||||
(entry.pokemon === 'Unown' && entry.form === 'A')
|
||||
)
|
||||
.map((entry) => entry.id) || []
|
||||
);
|
||||
}
|
||||
|
||||
return uniqueIds;
|
||||
}
|
||||
|
||||
let query = supabase.from('pokedex_entries').select('id');
|
||||
|
||||
// Apply form filter: if isFormDex is false, only include base forms
|
||||
// Base forms have form IS NULL, except Unown which has no base form (use 'A')
|
||||
if (!pokedex.isFormDex) {
|
||||
query = query.or('form.is.null,form.eq.male,and(pokemon.eq.Unown,form.eq.A)');
|
||||
}
|
||||
|
||||
// Apply region filter: if gameScope is specified, filter by region
|
||||
if (pokedex.gameScope) {
|
||||
// Determine region from gameScope using games table.
|
||||
// We keep games.region as a denormalized convenience column.
|
||||
const { data: regionData, error: regionError } = await supabase
|
||||
.from('games')
|
||||
.select('region')
|
||||
.eq('displayName', pokedex.gameScope)
|
||||
.maybeSingle();
|
||||
|
||||
if (regionError) {
|
||||
console.error('Error looking up region for gameScope:', pokedex.gameScope, regionError);
|
||||
throw new Error(
|
||||
`Failed to lookup region for gameScope "${pokedex.gameScope}": ${regionError.message}`
|
||||
);
|
||||
}
|
||||
|
||||
if (regionData?.region) {
|
||||
query = query.eq('regionToCatchIn', regionData.region);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply game filter: if gameScope is specified, filter by gamesToCatchIn array
|
||||
if (pokedex.gameScope) {
|
||||
query = query.contains('gamesToCatchIn', [pokedex.gameScope]);
|
||||
}
|
||||
|
||||
const { data, error } = await query;
|
||||
|
||||
if (error) {
|
||||
console.error('Error calculating expected entries:', error);
|
||||
throw new Error(`Failed to calculate expected entries: ${error.message}`);
|
||||
}
|
||||
|
||||
return data?.map((entry) => entry.id) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate pokedex_entries_mapping table for a pokedex
|
||||
* Uses chunked upsert to avoid UNIQUE constraint violations and request size limits
|
||||
* @throws Error if the Supabase upsert fails
|
||||
*/
|
||||
export async function populatePokedexMappings(
|
||||
supabase: SupabaseClient,
|
||||
pokedexId: string,
|
||||
pokedex: Pokedex
|
||||
): Promise<void> {
|
||||
const expectedEntryIds = await calculateExpectedEntries(supabase, pokedex);
|
||||
|
||||
if (expectedEntryIds.length === 0) {
|
||||
console.warn(`No expected entries calculated for pokedex ${pokedexId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// New schema writes to pokedex_pokemon_mapping; column is pokemonId
|
||||
const mappings = expectedEntryIds.map((pokemonId) => ({
|
||||
pokedexId,
|
||||
pokemonId
|
||||
}));
|
||||
|
||||
// Process in chunks to avoid request size limits
|
||||
const CHUNK_SIZE = 500;
|
||||
for (let i = 0; i < mappings.length; i += CHUNK_SIZE) {
|
||||
const chunk = mappings.slice(i, i + CHUNK_SIZE);
|
||||
const { error } = await supabase.from('pokedex_pokemon_mapping').upsert(chunk, {
|
||||
onConflict: 'pokedexId,pokemonId',
|
||||
ignoreDuplicates: true
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error('Error populating pokedex mappings:', error);
|
||||
throw new Error(`Failed to populate pokedex mappings: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate pokedex_entries_mapping table for a pokedex (used on update)
|
||||
* Uses a single atomic RPC call to prevent orphaned pokedexes
|
||||
* @throws Error if the Supabase RPC call fails
|
||||
*/
|
||||
export async function recalculatePokedexMappings(
|
||||
supabase: SupabaseClient,
|
||||
pokedexId: string,
|
||||
pokedex: Pokedex
|
||||
): Promise<void> {
|
||||
const expectedEntryIds = await calculateExpectedEntries(supabase, pokedex);
|
||||
|
||||
if (expectedEntryIds.length === 0) {
|
||||
console.warn(`No expected entries calculated for pokedex ${pokedexId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the atomic RPC function to delete old mappings and insert new ones
|
||||
const { error } = await supabase.rpc('recalculate_pokedex_mappings', {
|
||||
p_pokedex_id: pokedexId,
|
||||
p_entry_ids: expectedEntryIds
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error('Error recalculating pokedex mappings:', error);
|
||||
throw new Error(`Failed to recalculate pokedex mappings: ${error.message}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
type Theme = 'pokeball' | 'dark';
|
||||
|
||||
const STORAGE_KEY = 'theme';
|
||||
|
||||
function isTheme(type: string): type is Theme {
|
||||
return type === 'pokeball' || type === 'dark';
|
||||
}
|
||||
|
||||
function createThemeStore() {
|
||||
// Get stored theme from localStorage or default to 'pokeball'
|
||||
let initialTheme: Theme = 'pokeball';
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
const storedTheme = localStorage.getItem(STORAGE_KEY);
|
||||
if (storedTheme && isTheme(storedTheme)) {
|
||||
initialTheme = storedTheme;
|
||||
}
|
||||
} catch {
|
||||
// ignore (privacy mode / disabled storage)
|
||||
}
|
||||
}
|
||||
|
||||
const { subscribe, set: writableSet, update } = writable<Theme>(initialTheme);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
set: (value: Theme) => {
|
||||
if (isTheme(value)) {
|
||||
writableSet(value);
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, value);
|
||||
} catch {
|
||||
// ignore (privacy mode / disabled storage)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
toggle: () => {
|
||||
update((theme) => {
|
||||
const newTheme = theme === 'pokeball' ? 'dark' : 'pokeball';
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, newTheme);
|
||||
} catch {
|
||||
// ignore (privacy mode / disabled storage)
|
||||
}
|
||||
}
|
||||
return newTheme;
|
||||
});
|
||||
},
|
||||
init: () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
if (stored && isTheme(stored)) {
|
||||
writableSet(stored);
|
||||
}
|
||||
} catch {
|
||||
// ignore (privacy mode / disabled storage)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const theme = createThemeStore();
|
||||
|
||||
// Helper function to apply theme to HTML element
|
||||
export function applyTheme(themeValue: Theme) {
|
||||
if (typeof document !== 'undefined') {
|
||||
document.documentElement.setAttribute('data-theme', themeValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { RequestEvent } from '@sveltejs/kit';
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
/**
|
||||
* Validates the user session and returns the authenticated user ID
|
||||
* Throws a 401 error if the user is not authenticated
|
||||
*/
|
||||
export async function requireAuth(event: RequestEvent): Promise<string> {
|
||||
const { session, user } = await event.locals.safeGetSession();
|
||||
|
||||
if (!session || !user) {
|
||||
throw error(401, 'Authentication required');
|
||||
}
|
||||
|
||||
return user.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally validates the user session and returns the user ID if authenticated
|
||||
* Returns null if not authenticated (no error thrown)
|
||||
*/
|
||||
export async function getOptionalUserId(event: RequestEvent): Promise<string | null> {
|
||||
try {
|
||||
const { session, user } = await event.locals.safeGetSession();
|
||||
return user?.id || null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Calculate box placement for Pokémon based on their position in a sorted list
|
||||
*
|
||||
* Box layout: 6 columns × 5 rows = 30 Pokémon per box
|
||||
*
|
||||
* @param index - Zero-based index in the sorted list
|
||||
* @returns Box placement with box number, row, and column (1-indexed)
|
||||
*/
|
||||
export function calculateBoxPlacement(index: number): {
|
||||
box: number;
|
||||
row: number;
|
||||
column: number;
|
||||
} {
|
||||
const POKEMON_PER_BOX = 30;
|
||||
const COLUMNS_PER_BOX = 6;
|
||||
const ROWS_PER_BOX = 5;
|
||||
|
||||
// Calculate which box this Pokémon belongs to (1-indexed)
|
||||
const box = Math.floor(index / POKEMON_PER_BOX) + 1;
|
||||
|
||||
// Calculate position within the box (0-indexed)
|
||||
const positionInBox = index % POKEMON_PER_BOX;
|
||||
|
||||
// Calculate row and column (1-indexed)
|
||||
const row = Math.floor(positionInBox / COLUMNS_PER_BOX) + 1;
|
||||
const column = (positionInBox % COLUMNS_PER_BOX) + 1;
|
||||
|
||||
return { box, row, column };
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate all unique box numbers needed for a list of Pokémon
|
||||
*
|
||||
* @param count - Total number of Pokémon
|
||||
* @returns Array of box numbers (1-indexed)
|
||||
*/
|
||||
export function calculateBoxNumbers(count: number): number[] {
|
||||
const POKEMON_PER_BOX = 30;
|
||||
const totalBoxes = Math.ceil(count / POKEMON_PER_BOX);
|
||||
return Array.from({ length: totalBoxes }, (_, i) => i + 1);
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
import { writable, type Readable } from 'svelte/store';
|
||||
import type { CatchRecord } from '$lib/models/CatchRecord';
|
||||
|
||||
export type CatchRecordWriteQueueStatus = {
|
||||
pending: number;
|
||||
inFlight: number;
|
||||
lastError: string | null;
|
||||
lastFlushAttemptAt: number | null;
|
||||
lastSuccessfulFlushAt: number | null;
|
||||
};
|
||||
|
||||
type QueueItem = {
|
||||
record: CatchRecord;
|
||||
attempts: number;
|
||||
notBefore: number; // unix ms
|
||||
debounceTimer: ReturnType<typeof setTimeout> | null;
|
||||
version: number;
|
||||
};
|
||||
|
||||
export type CreateCatchRecordWriteQueueOptions = {
|
||||
/**
|
||||
* URL to the pokédex-scoped catch-records endpoint.
|
||||
* Example: `/api/pokedexes/${pokedexId}/catch-records`
|
||||
*/
|
||||
endpointUrl: string;
|
||||
/**
|
||||
* Fetch implementation to use (usually the `fetch` provided by SvelteKit load).
|
||||
*/
|
||||
fetchFn: typeof fetch;
|
||||
/** Max number of records sent per request. */
|
||||
batchSize?: number;
|
||||
/** Max number of concurrent in-flight requests. */
|
||||
concurrency?: number;
|
||||
};
|
||||
|
||||
export type EnqueueCatchRecordWriteOptions = {
|
||||
/** Debounce before the record becomes eligible for flushing (ms). */
|
||||
debounceMs?: number;
|
||||
/** If true, schedule an immediate flush attempt after enqueue. */
|
||||
flushSoon?: boolean;
|
||||
};
|
||||
|
||||
export type FlushOptions = {
|
||||
/**
|
||||
* Use `keepalive` to improve best-effort delivery during `pagehide`.
|
||||
* Note: browsers impose body-size limits on keepalive requests.
|
||||
*/
|
||||
keepalive?: boolean;
|
||||
/**
|
||||
* Limit number of items flushed in this attempt.
|
||||
* Useful for keepalive flushes on tab close.
|
||||
*/
|
||||
limit?: number;
|
||||
};
|
||||
|
||||
function keyFor(record: CatchRecord): string {
|
||||
return `${record.userId}:${record.pokedexId}:${record.pokemonId}`;
|
||||
}
|
||||
|
||||
function backoffMs(attempts: number): number {
|
||||
// Exponential backoff with jitter: 250ms, 500ms, 1s, 2s, 4s... capped.
|
||||
const base = 250 * Math.pow(2, Math.max(0, attempts - 1));
|
||||
const capped = Math.min(base, 10_000);
|
||||
const jitter = Math.floor(Math.random() * 200);
|
||||
return capped + jitter;
|
||||
}
|
||||
|
||||
export function createCatchRecordWriteQueue(options: CreateCatchRecordWriteQueueOptions): {
|
||||
enqueue: (record: CatchRecord, opts?: EnqueueCatchRecordWriteOptions) => void;
|
||||
flushNow: (opts?: FlushOptions) => Promise<void>;
|
||||
getStatus: Readable<CatchRecordWriteQueueStatus>;
|
||||
getPendingCount: () => number;
|
||||
clearError: () => void;
|
||||
} {
|
||||
const { endpointUrl, fetchFn, batchSize = 100, concurrency = 1 } = options;
|
||||
|
||||
const items = new Map<string, QueueItem>();
|
||||
let scheduled: ReturnType<typeof setTimeout> | null = null;
|
||||
let inFlight = 0;
|
||||
|
||||
const statusStore = writable<CatchRecordWriteQueueStatus>({
|
||||
pending: 0,
|
||||
inFlight: 0,
|
||||
lastError: null,
|
||||
lastFlushAttemptAt: null,
|
||||
lastSuccessfulFlushAt: null
|
||||
});
|
||||
|
||||
function updateStatus(patch: Partial<CatchRecordWriteQueueStatus>) {
|
||||
statusStore.update((s) => ({
|
||||
...s,
|
||||
pending: items.size,
|
||||
inFlight,
|
||||
...patch
|
||||
}));
|
||||
}
|
||||
|
||||
function computeNextWakeup(): number | null {
|
||||
let next: number | null = null;
|
||||
const now = Date.now();
|
||||
for (const [, item] of items) {
|
||||
if (item.debounceTimer) continue;
|
||||
if (item.notBefore <= now) {
|
||||
return now;
|
||||
}
|
||||
next = next === null ? item.notBefore : Math.min(next, item.notBefore);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
function scheduleFlush() {
|
||||
if (scheduled) return;
|
||||
const next = computeNextWakeup();
|
||||
if (next === null) return;
|
||||
const delay = Math.max(0, next - Date.now());
|
||||
scheduled = setTimeout(async () => {
|
||||
scheduled = null;
|
||||
await flushNow();
|
||||
}, delay);
|
||||
}
|
||||
|
||||
async function flushBatch(opts?: FlushOptions): Promise<void> {
|
||||
if (typeof navigator !== 'undefined' && navigator.onLine === false) {
|
||||
// Stay queued; caller can retry when online.
|
||||
return;
|
||||
}
|
||||
if (inFlight >= concurrency) return;
|
||||
|
||||
const now = Date.now();
|
||||
const eligible: Array<[string, QueueItem]> = [];
|
||||
for (const entry of items.entries()) {
|
||||
const [k, item] = entry;
|
||||
if (item.debounceTimer) continue;
|
||||
if (item.notBefore > now) continue;
|
||||
eligible.push([k, item]);
|
||||
if (eligible.length >= (opts?.limit ?? batchSize)) break;
|
||||
}
|
||||
if (eligible.length === 0) return;
|
||||
|
||||
inFlight++;
|
||||
updateStatus({ lastFlushAttemptAt: now });
|
||||
try {
|
||||
const payload = eligible.map(([, item]) => item.record);
|
||||
const response = await fetchFn(endpointUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
// keepalive improves odds during `pagehide`.
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
keepalive: !!opts?.keepalive,
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(`Failed to flush catch records: ${response.status} ${text}`);
|
||||
}
|
||||
|
||||
// Success: drop the flushed keys.
|
||||
for (const [k, sentItem] of eligible) {
|
||||
const current = items.get(k);
|
||||
if (!current) {
|
||||
items.delete(k);
|
||||
continue;
|
||||
}
|
||||
// Only clear if nothing newer was enqueued after this batch started.
|
||||
if (current.version === sentItem.version) {
|
||||
items.delete(k);
|
||||
}
|
||||
}
|
||||
updateStatus({ lastError: null, lastSuccessfulFlushAt: Date.now() });
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : String(e);
|
||||
// Backoff all eligible items and keep them.
|
||||
for (const [k, item] of eligible) {
|
||||
const current = items.get(k);
|
||||
if (!current) continue;
|
||||
if (current.version !== item.version) continue;
|
||||
const nextAttempts = item.attempts + 1;
|
||||
items.set(k, {
|
||||
...item,
|
||||
attempts: nextAttempts,
|
||||
notBefore: Date.now() + backoffMs(nextAttempts)
|
||||
});
|
||||
}
|
||||
updateStatus({ lastError: message });
|
||||
} finally {
|
||||
inFlight--;
|
||||
updateStatus({});
|
||||
}
|
||||
}
|
||||
|
||||
async function flushNow(opts?: FlushOptions): Promise<void> {
|
||||
updateStatus({});
|
||||
// Drain in waves while eligible work exists and we have capacity.
|
||||
// We intentionally do not block indefinitely; this is a “best-effort background flush”.
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (items.size === 0) break;
|
||||
await flushBatch(opts);
|
||||
// If nothing is eligible yet, schedule the next wakeup and exit.
|
||||
const next = computeNextWakeup();
|
||||
if (next !== null && next > Date.now()) break;
|
||||
if (inFlight >= concurrency) break;
|
||||
}
|
||||
scheduleFlush();
|
||||
}
|
||||
|
||||
function enqueue(record: CatchRecord, opts?: EnqueueCatchRecordWriteOptions) {
|
||||
const k = keyFor(record);
|
||||
const now = Date.now();
|
||||
const existing = items.get(k);
|
||||
const debounceMs = opts?.debounceMs ?? 0;
|
||||
const nextVersion = (existing?.version ?? 0) + 1;
|
||||
|
||||
// Clear any pending debounce timer: latest state always wins.
|
||||
if (existing?.debounceTimer) {
|
||||
clearTimeout(existing.debounceTimer);
|
||||
}
|
||||
|
||||
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
let notBefore = now;
|
||||
if (debounceMs > 0) {
|
||||
notBefore = now + debounceMs;
|
||||
debounceTimer = setTimeout(() => {
|
||||
const item = items.get(k);
|
||||
if (!item) return;
|
||||
items.set(k, { ...item, debounceTimer: null, notBefore: Date.now() });
|
||||
updateStatus({});
|
||||
scheduleFlush();
|
||||
}, debounceMs);
|
||||
}
|
||||
|
||||
items.set(k, {
|
||||
record,
|
||||
attempts: existing?.attempts ?? 0,
|
||||
notBefore,
|
||||
debounceTimer,
|
||||
version: nextVersion
|
||||
});
|
||||
updateStatus({});
|
||||
if (opts?.flushSoon !== false) scheduleFlush();
|
||||
}
|
||||
|
||||
function getPendingCount(): number {
|
||||
return items.size;
|
||||
}
|
||||
|
||||
function clearError() {
|
||||
updateStatus({ lastError: null });
|
||||
}
|
||||
|
||||
return {
|
||||
enqueue,
|
||||
flushNow,
|
||||
getStatus: { subscribe: statusStore.subscribe },
|
||||
getPendingCount,
|
||||
clearError
|
||||
};
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { getEnv } from '$lib/utils/env';
|
||||
const env = getEnv();
|
||||
|
||||
/*
|
||||
0 - disconnected
|
||||
1 - connected
|
||||
2 - connecting
|
||||
3 - disconnecting
|
||||
4 - uninitialized
|
||||
*/
|
||||
let mongoConnectionState = 0;
|
||||
|
||||
export const dbConnect = async () => {
|
||||
if (mongoConnectionState === 1) {
|
||||
console.log('Connection already established');
|
||||
return;
|
||||
}
|
||||
|
||||
if (mongoose.connections.length > 0) {
|
||||
mongoConnectionState = mongoose.connections[0].readyState;
|
||||
if (mongoConnectionState === 1) {
|
||||
console.log('Using existing connection');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await mongoose.connect(env.MONGO_URL, {
|
||||
serverApi: { version: '1', strict: true, deprecationErrors: true }
|
||||
});
|
||||
await mongoose.connection.db.admin().command({ ping: 1 });
|
||||
console.log('Pinged your deployment. You successfully connected to MongoDB!');
|
||||
mongoConnectionState = 1;
|
||||
} catch (error) {
|
||||
console.error('Error connecting to MongoDB:', error);
|
||||
mongoConnectionState = 0;
|
||||
}
|
||||
};
|
||||
|
||||
export const dbDisconnect = async () => {
|
||||
if (process.env.NODE_ENV === 'development') return;
|
||||
if (mongoConnectionState === 0) return;
|
||||
|
||||
await mongoose.disconnect();
|
||||
mongoConnectionState = 0;
|
||||
console.log('disconnected from mongodb');
|
||||
};
|
||||
@@ -1,7 +1,5 @@
|
||||
import { env } from '$env/dynamic/private';
|
||||
|
||||
export function getEnv() {
|
||||
return process.env.hasOwnProperty('MONGO_URL')
|
||||
? process.env
|
||||
: {
|
||||
MONGO_URL: import.meta.env.VITE_MONGO_URL
|
||||
};
|
||||
return env;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import type { RequestEvent } from '@sveltejs/kit';
|
||||
|
||||
export type OAuthStatePayload = {
|
||||
state: string;
|
||||
userId: string;
|
||||
pokedexId?: string | null;
|
||||
provider: string;
|
||||
fileName?: string | null;
|
||||
folderId?: string | null;
|
||||
path?: string | null;
|
||||
returnTo?: string | null;
|
||||
};
|
||||
|
||||
const STATE_MAX_AGE = 10 * 60; // 10 minutes
|
||||
|
||||
export function createOAuthState(): string {
|
||||
return randomUUID();
|
||||
}
|
||||
|
||||
function cookieName(provider: string): string {
|
||||
return `oauth_state_${provider}`;
|
||||
}
|
||||
|
||||
export function setOAuthStateCookie(
|
||||
event: RequestEvent,
|
||||
provider: string,
|
||||
payload: OAuthStatePayload
|
||||
) {
|
||||
event.cookies.set(cookieName(provider), JSON.stringify(payload), {
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
sameSite: 'lax',
|
||||
secure: event.url.protocol === 'https:',
|
||||
maxAge: STATE_MAX_AGE
|
||||
});
|
||||
}
|
||||
|
||||
export function readOAuthStateCookie(
|
||||
event: RequestEvent,
|
||||
provider: string
|
||||
): OAuthStatePayload | null {
|
||||
const raw = event.cookies.get(cookieName(provider));
|
||||
if (!raw) return null;
|
||||
try {
|
||||
const parsed = JSON.parse(raw) as OAuthStatePayload;
|
||||
if (!parsed?.state || !parsed?.userId) return null;
|
||||
return parsed;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function clearOAuthStateCookie(event: RequestEvent, provider: string) {
|
||||
event.cookies.delete(cookieName(provider), { path: '/' });
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Maps game names to their corresponding regional Pokédex identifier.
|
||||
* This mapping is used to determine which regional dex number to use when
|
||||
* filtering and ordering Pokémon for a specific game.
|
||||
*/
|
||||
|
||||
type RegionalDexKey =
|
||||
| 'kanto'
|
||||
| 'johto'
|
||||
| 'hoenn'
|
||||
| 'sinnoh'
|
||||
| 'unova_bw'
|
||||
| 'unova_b2w2'
|
||||
| 'kalos_central'
|
||||
| 'kalos_coastal'
|
||||
| 'kalos_mountain'
|
||||
| 'alola_sm'
|
||||
| 'alola_usum'
|
||||
| 'galar'
|
||||
| 'galar_isle_of_armor'
|
||||
| 'galar_crown_tundra'
|
||||
| 'hisui'
|
||||
| 'paldea';
|
||||
|
||||
const gameToRegionalDexMap: Record<string, RegionalDexKey> = {
|
||||
// Kanto region
|
||||
'Red': 'kanto',
|
||||
'Blue': 'kanto',
|
||||
'Yellow': 'kanto',
|
||||
'FireRed': 'kanto',
|
||||
'LeafGreen': 'kanto',
|
||||
'LG: Pikachu': 'kanto',
|
||||
'LG: Eevee': 'kanto',
|
||||
|
||||
// Johto region
|
||||
'Gold': 'johto',
|
||||
'Silver': 'johto',
|
||||
'Crystal': 'johto',
|
||||
'HeartGold': 'johto',
|
||||
'SoulSilver': 'johto',
|
||||
|
||||
// Hoenn region
|
||||
'Ruby': 'hoenn',
|
||||
'Sapphire': 'hoenn',
|
||||
'Emerald': 'hoenn',
|
||||
'OmegaRuby': 'hoenn',
|
||||
'AlphaSapphire': 'hoenn',
|
||||
|
||||
// Sinnoh region
|
||||
'Diamond': 'sinnoh',
|
||||
'Pearl': 'sinnoh',
|
||||
'Platinum': 'sinnoh',
|
||||
'BrilliantDiamond': 'sinnoh',
|
||||
'ShiningPearl': 'sinnoh',
|
||||
|
||||
// Unova region
|
||||
'Black': 'unova_bw',
|
||||
'White': 'unova_bw',
|
||||
'Black2': 'unova_b2w2',
|
||||
'White2': 'unova_b2w2',
|
||||
|
||||
// Kalos region - Note: All XY use all three sub-dexes
|
||||
// We default to Central for simplicity
|
||||
'X': 'kalos_central',
|
||||
'Y': 'kalos_central',
|
||||
|
||||
// Alola region
|
||||
'Sun': 'alola_sm',
|
||||
'Moon': 'alola_sm',
|
||||
'UltraSun': 'alola_usum',
|
||||
'UltraMoon': 'alola_usum',
|
||||
|
||||
// Galar region
|
||||
'Sword': 'galar',
|
||||
'Shield': 'galar',
|
||||
|
||||
// Hisui region
|
||||
'LegendsArceus': 'hisui',
|
||||
|
||||
// Paldea region
|
||||
'Scarlet': 'paldea',
|
||||
'Violet': 'paldea'
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the regional dex key for a given game name.
|
||||
* Returns undefined if the game doesn't have a regional dex mapping.
|
||||
*/
|
||||
export function getRegionalDexKey(gameName: string): RegionalDexKey | undefined {
|
||||
return gameToRegionalDexMap[gameName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a game has a regional dex mapping.
|
||||
*/
|
||||
export function hasRegionalDex(gameName: string): boolean {
|
||||
return gameName in gameToRegionalDexMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database column name for a game's regional dex.
|
||||
* Maps game name → database column name (e.g., 'Scarlet' → 'paldea_dex_number').
|
||||
* Returns undefined if the game doesn't have a regional dex mapping.
|
||||
*/
|
||||
export function getRegionalDexColumnName(gameName: string): string | undefined {
|
||||
const regionalKey = getRegionalDexKey(gameName);
|
||||
if (!regionalKey) return undefined;
|
||||
return `${regionalKey}_dex_number`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the frontend field name for a game's regional dex.
|
||||
* Maps game name → PokedexEntry field name (e.g., 'Scarlet' → 'paldeaDexNumber').
|
||||
* Returns undefined if the game doesn't have a regional dex mapping.
|
||||
*/
|
||||
export function getRegionalDexFieldName(gameName: string): string | undefined {
|
||||
const regionalKey = getRegionalDexKey(gameName);
|
||||
if (!regionalKey) return undefined;
|
||||
|
||||
// Map regional key to actual PokedexEntry field name (camelCase)
|
||||
const fieldMap: Record<string, string> = {
|
||||
'kanto': 'kantoDexNumber',
|
||||
'johto': 'johtoDexNumber',
|
||||
'hoenn': 'hoennDexNumber',
|
||||
'sinnoh': 'sinnohDexNumber',
|
||||
'unova_bw': 'unovaBwDexNumber',
|
||||
'unova_b2w2': 'unovaB2w2DexNumber',
|
||||
'kalos_central': 'kalosCentralDexNumber',
|
||||
'kalos_coastal': 'kalosCoastalDexNumber',
|
||||
'kalos_mountain': 'kalosMountainDexNumber',
|
||||
'alola_sm': 'alolaSmDexNumber',
|
||||
'alola_usum': 'alolaUsumDexNumber',
|
||||
'galar': 'galarDexNumber',
|
||||
'galar_isle_of_armor': 'galarIsleOfArmorDexNumber',
|
||||
'galar_crown_tundra': 'galarCrownTundraDexNumber',
|
||||
'hisui': 'hisuiDexNumber',
|
||||
'paldea': 'paldeaDexNumber'
|
||||
};
|
||||
|
||||
return fieldMap[regionalKey];
|
||||
}
|
||||
+24
-2
@@ -8,7 +8,10 @@ import {
|
||||
precacheAndRoute,
|
||||
precache
|
||||
} from 'workbox-precaching';
|
||||
// import { NavigationRoute, registerRoute } from 'workbox-routing';
|
||||
import { registerRoute } from 'workbox-routing';
|
||||
import { CacheFirst } from 'workbox-strategies';
|
||||
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
|
||||
import { ExpirationPlugin } from 'workbox-expiration';
|
||||
|
||||
declare let self: ServiceWorkerGlobalScope;
|
||||
|
||||
@@ -20,11 +23,30 @@ self.addEventListener('message', (event) => {
|
||||
precache([{ url: '/', revision: null }]);
|
||||
|
||||
// self.__WB_MANIFEST is default injection point
|
||||
precacheAndRoute(self.__WB_MANIFEST);
|
||||
// Handle the case where __WB_MANIFEST might be undefined in development
|
||||
const manifest = self.__WB_MANIFEST || [];
|
||||
if (Array.isArray(manifest)) {
|
||||
precacheAndRoute(manifest);
|
||||
}
|
||||
|
||||
// clean old assets
|
||||
cleanupOutdatedCaches();
|
||||
|
||||
registerRoute(
|
||||
({ request }) => request.destination === 'image',
|
||||
new CacheFirst({
|
||||
cacheName: 'image-cache',
|
||||
plugins: [
|
||||
new CacheableResponsePlugin({ statuses: [0, 200] }),
|
||||
new ExpirationPlugin({
|
||||
maxEntries: 3000,
|
||||
maxAgeSeconds: 60 * 60 * 24 * 30,
|
||||
purgeOnQuotaError: true
|
||||
})
|
||||
]
|
||||
})
|
||||
);
|
||||
|
||||
// let allowlist: undefined | RegExp[];
|
||||
// if (import.meta.env.DEV) allowlist = [/^\/$/];
|
||||
|
||||
|
||||
+47
-40
@@ -5,11 +5,13 @@
|
||||
import { type User } from '@supabase/auth-js';
|
||||
import SignIn from '$lib/components/SignIn.svelte';
|
||||
import SignOut from '$lib/components/SignOut.svelte';
|
||||
import ThemeToggle from '$lib/components/ThemeToggle.svelte';
|
||||
|
||||
import { pwaInfo } from 'virtual:pwa-info';
|
||||
import { pwaAssetsHead } from 'virtual:pwa-assets/head';
|
||||
|
||||
$: webManifestLink = pwaInfo ? pwaInfo.webManifest.linkTag : '';
|
||||
const pwaDescription = (pwaAssetsHead as { description?: { content: string } }).description;
|
||||
|
||||
export let data;
|
||||
let { supabase } = data;
|
||||
@@ -21,26 +23,47 @@
|
||||
});
|
||||
onDestroy(unsubscribe);
|
||||
|
||||
onMount(async () => {
|
||||
await getUser();
|
||||
let authSubscription: { unsubscribe: () => void } | null = null;
|
||||
|
||||
onMount(() => {
|
||||
void getUser();
|
||||
|
||||
// Listen for auth state changes to keep the user store in sync
|
||||
const {
|
||||
data: { subscription }
|
||||
} = supabase.auth.onAuthStateChange((event, session) => {
|
||||
if (session) {
|
||||
localUser = session.user;
|
||||
} else {
|
||||
localUser = null;
|
||||
}
|
||||
user.set(localUser);
|
||||
});
|
||||
authSubscription = subscription;
|
||||
|
||||
if (pwaInfo) {
|
||||
const { registerSW } = await import('virtual:pwa-register');
|
||||
registerSW({
|
||||
immediate: true,
|
||||
onRegistered(r) {
|
||||
// uncomment following code if you want check for updates
|
||||
// r && setInterval(() => {
|
||||
// console.log('Checking for sw update')
|
||||
// r.update()
|
||||
// }, 20000 /* 20s for testing purposes */)
|
||||
console.log(`SW Registered: ${r}`);
|
||||
},
|
||||
onRegisterError(error) {
|
||||
console.log('SW registration error', error);
|
||||
}
|
||||
});
|
||||
void (async () => {
|
||||
const { registerSW } = await import('virtual:pwa-register');
|
||||
registerSW({
|
||||
immediate: true,
|
||||
onRegistered(r) {
|
||||
// uncomment following code if you want check for updates
|
||||
// r && setInterval(() => {
|
||||
// console.log('Checking for sw update')
|
||||
// r.update()
|
||||
// }, 20000 /* 20s for testing purposes */)
|
||||
console.log(`SW Registered: ${r}`);
|
||||
},
|
||||
onRegisterError(error) {
|
||||
console.log('SW registration error', error);
|
||||
}
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
return () => {
|
||||
authSubscription?.unsubscribe();
|
||||
};
|
||||
});
|
||||
|
||||
async function getUser() {
|
||||
@@ -63,8 +86,8 @@
|
||||
{#if pwaAssetsHead.themeColor}
|
||||
<meta name="theme-color" content={pwaAssetsHead.themeColor.content} />
|
||||
{/if}
|
||||
{#if pwaAssetsHead.description}
|
||||
<meta name="description" content={pwaAssetsHead.description.content} />
|
||||
{#if pwaDescription}
|
||||
<meta name="description" content={pwaDescription.content} />
|
||||
{/if}
|
||||
{#each pwaAssetsHead.links as link}
|
||||
<link {...link} />
|
||||
@@ -91,7 +114,7 @@
|
||||
<header>
|
||||
<div class="navbar bg-primary text-primary-content">
|
||||
<div class="navbar-start">
|
||||
<div class="dropdown">
|
||||
<!-- <div class="dropdown">
|
||||
<div tabindex="0" role="button" class="btn btn-ghost btn-circle">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -110,32 +133,17 @@
|
||||
<ul
|
||||
class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-primary text-primary-content rounded-box w-52"
|
||||
>
|
||||
<li><a href="/about">About</a></li>
|
||||
<li>
|
||||
<a href="https://github.com/jcreek/LivingDexTracker" target="_blank">Contribute</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="navbar-center">
|
||||
<a class="btn btn-ghost text-xl" href="/">Living Dex Tracker</a>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<button class="btn btn-ghost btn-circle">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/></svg
|
||||
>
|
||||
</button>
|
||||
<ThemeToggle />
|
||||
<div class="dropdown dropdown-end">
|
||||
{#if localUser}
|
||||
<div tabindex="0" role="button" class="btn btn-ghost btn-circle avatar">
|
||||
@@ -149,12 +157,11 @@
|
||||
>
|
||||
{#if localUser}
|
||||
<li>
|
||||
<a href="/mydex"> My Dex </a>
|
||||
<a href="/my-pokedexes"> My Pokédexes </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/profile"> Profile </a>
|
||||
<a href="/backup-settings"> Backup Settings </a>
|
||||
</li>
|
||||
<li><a href="/settings">Settings</a></li>
|
||||
<li><SignOut {supabase} on:signedOut={getUser} /></li>
|
||||
{:else}
|
||||
<li><SignIn {supabase} on:signedIn={getUser} /></li>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
/**
|
||||
* Server-side load function for the homepage
|
||||
*
|
||||
* Fetches public statistics from the database and passes them to the page component.
|
||||
* Stats are cached for 24 hours to improve performance.
|
||||
*/
|
||||
export const load: PageServerLoad = async ({ fetch }) => {
|
||||
// Fetch stats from database
|
||||
const statsResponse = await fetch('/api/stats');
|
||||
const statsData = await statsResponse.json();
|
||||
|
||||
return {
|
||||
stats: statsData.error ? null : statsData
|
||||
};
|
||||
};
|
||||
+369
-118
@@ -1,141 +1,392 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy } from 'svelte';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { user } from '$lib/stores/user.js';
|
||||
import { type User } from '@supabase/auth-js';
|
||||
import SignUp from '$lib/components/SignUp.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
export let data;
|
||||
let { supabase } = data;
|
||||
$: ({ supabase } = data);
|
||||
let { supabase, stats } = data;
|
||||
$: ({ supabase, stats } = data);
|
||||
|
||||
let localUser: User | null;
|
||||
const unsubscribe = user.subscribe((value) => {
|
||||
localUser = value;
|
||||
});
|
||||
onDestroy(unsubscribe);
|
||||
|
||||
let isCheckingSession = true;
|
||||
|
||||
onMount(() => {
|
||||
checkSessionAndRedirect();
|
||||
});
|
||||
|
||||
async function checkSessionAndRedirect() {
|
||||
try {
|
||||
const {
|
||||
data: { session }
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
if (session) {
|
||||
await goto('/my-pokedexes');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking session:', error);
|
||||
} finally {
|
||||
isCheckingSession = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSignedUp() {
|
||||
await goto('/welcome');
|
||||
}
|
||||
|
||||
// Format large numbers (e.g., 1000 -> 1K, 1000000 -> 1M)
|
||||
function formatNumber(num: number): string {
|
||||
if (num >= 1000000) {
|
||||
return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
|
||||
}
|
||||
if (num >= 1000) {
|
||||
return (num / 1000).toFixed(0) + 'K';
|
||||
}
|
||||
return num.toString();
|
||||
}
|
||||
|
||||
// Get formatted stats or fallback to 0
|
||||
let pokemonCaught = '0';
|
||||
let users = '0';
|
||||
let livingDexesCompleted = '0';
|
||||
$: {
|
||||
pokemonCaught = formatNumber(stats?.pokemonCaught ?? 0);
|
||||
users = formatNumber(stats?.users ?? 0);
|
||||
livingDexesCompleted = formatNumber(stats?.livingDexesCompleted ?? 0);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="hero bg-base-100 my-36">
|
||||
<div class="hero-content flex-col lg:flex-row-reverse">
|
||||
<div class="text-center lg:text-left">
|
||||
<h1 class="text-5xl font-bold">Start Your Pokédex Journey!</h1>
|
||||
</div>
|
||||
<div class="card shrink-0 w-full max-w-sm shadow-2xl bg-neutral">
|
||||
<SignUp {supabase} />
|
||||
<svelte:head>
|
||||
<title>Living Dex Tracker - Track Your Pokédex Journey</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="A free, open source tool to track your Living Pokédex progress. Join thousands of trainers worldwide in completing their collection."
|
||||
/>
|
||||
</svelte:head>
|
||||
|
||||
{#if isCheckingSession}
|
||||
<!-- Loading placeholder while checking session -->
|
||||
<div class="hero bg-base-100 my-36">
|
||||
<div class="hero-content flex-col">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="md:container md:mx-auto justify-self-center flex justify-center items-center h-full flex-col mb-10"
|
||||
>
|
||||
<div class="stats stats-vertical lg:stats-horizontal shadow bg-neutral text-center">
|
||||
<div class="stat">
|
||||
<div class="stat-title">Pokémon caught</div>
|
||||
<div class="stat-value">310K</div>
|
||||
<div class="stat-desc">Since January 2024</div>
|
||||
</div>
|
||||
|
||||
<div class="stat">
|
||||
<div class="stat-title">New Users</div>
|
||||
<div class="stat-value">4,200</div>
|
||||
<div class="stat-desc">↗︎ 400 (22%)</div>
|
||||
</div>
|
||||
|
||||
<div class="stat">
|
||||
<div class="stat-title">Living Dexes Completed</div>
|
||||
<div class="stat-value">1,200</div>
|
||||
<div class="stat-desc">↘︎ 90 (14%)</div>
|
||||
{:else}
|
||||
<!-- Hero Section -->
|
||||
<div class="hero bg-base-100 my-36">
|
||||
<div class="hero-content flex-col lg:flex-row-reverse">
|
||||
<div class="text-center lg:text-left">
|
||||
<div class="flex flex-wrap gap-2 mb-4">
|
||||
<div class="badge badge-primary badge-lg gap-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
Free
|
||||
</div>
|
||||
<div class="badge badge-secondary badge-lg gap-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"
|
||||
/>
|
||||
</svg>
|
||||
Open Source
|
||||
</div>
|
||||
<div class="badge badge-accent badge-lg gap-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
Offline-friendly
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="text-5xl font-bold mb-6">Start Your Pokédex Journey!</h1>
|
||||
<p class="text-xl mb-6 text-base-content/80">
|
||||
Track your progress towards a complete Living Pokédex — one of every Pokémon, actively
|
||||
maintained across your boxes. Join thousands of trainers worldwide.
|
||||
</p>
|
||||
<div class="flex flex-wrap gap-3 justify-center lg:justify-start">
|
||||
<a
|
||||
href="https://discord.gg/2ytj4pkUPY"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn btn-primary btn-lg"
|
||||
aria-label="Join the Living Dex Tracker Discord community"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"
|
||||
/>
|
||||
</svg>
|
||||
Join Discord
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/jcreek/LivingDexTracker"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn btn-outline btn-lg"
|
||||
aria-label="View the Living Dex Tracker project on GitHub"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
|
||||
/>
|
||||
</svg>
|
||||
Contribute on GitHub
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shrink-0 w-full max-w-sm shadow-2xl bg-neutral">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-2xl mb-4">Get Started Free</h2>
|
||||
<SignUp {supabase} on:signedUp={handleSignedUp} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="features mt-8">
|
||||
<h1 class="flex justify-center text-4xl font-bold mb-5">Features</h1>
|
||||
|
||||
<ul class="space-y-6">
|
||||
<li class="p-6 rounded-lg shadow-md bg-neutral">
|
||||
<div class="flex items-start space-x-4">
|
||||
<svg
|
||||
class="w-8 h-8 text-green-500 flex-shrink-0"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"
|
||||
></path>
|
||||
</svg>
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">Social</h2>
|
||||
<p>
|
||||
Easily share your Pokédex journey with friends, or find theirs. If you'd rather go it
|
||||
alone, that's okay too!
|
||||
</p>
|
||||
</div>
|
||||
<!-- Stats Section -->
|
||||
<div class="bg-base-200 py-16">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="stats stats-vertical lg:stats-horizontal shadow bg-neutral text-center w-full">
|
||||
<div class="stat">
|
||||
<div class="stat-title">Pokémon caught</div>
|
||||
<div class="stat-value text-primary">{pokemonCaught}</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="p-6 rounded-lg shadow-md bg-neutral">
|
||||
<div class="flex items-start space-x-4">
|
||||
<svg
|
||||
class="w-8 h-8 text-green-500 flex-shrink-0"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"
|
||||
></path>
|
||||
</svg>
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">Free & Open Source</h2>
|
||||
<p>
|
||||
Completely open source and free to use, enabling the community to contribute updates
|
||||
as soon as new Pokémon are released.
|
||||
</p>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-title">Users</div>
|
||||
<div class="stat-value text-primary">{users}</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="p-6 rounded-lg shadow-md bg-neutral">
|
||||
<div class="flex items-start space-x-4">
|
||||
<svg
|
||||
class="w-8 h-8 text-green-500 flex-shrink-0"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"
|
||||
></path>
|
||||
</svg>
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">Easy to use with advanced filtering</h2>
|
||||
<p>
|
||||
If you just want to track your progress completing your Pokédex, you can do that. But
|
||||
if you are attempting a harder variant, like a Living Origin Forme Dex, you might find
|
||||
our advanced filtering options helpful for tracking target Pokémon for specific
|
||||
catching sessions.
|
||||
</p>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-title">Living Dexes Completed</div>
|
||||
<div class="stat-value text-primary">{livingDexesCompleted}</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="p-6 rounded-lg shadow-md bg-neutral">
|
||||
<div class="flex items-start space-x-4">
|
||||
<svg
|
||||
class="w-8 h-8 text-green-500 flex-shrink-0"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"
|
||||
></path>
|
||||
</svg>
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">100% free</h2>
|
||||
<p>Did we mention it's completely free to use? Oh, we did? Good. Because it is.</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- What is a Living Dex Section -->
|
||||
<div class="py-16 bg-base-100">
|
||||
<div class="container mx-auto px-4 max-w-4xl">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-3xl mb-4">What is a Living Dex?</h2>
|
||||
<p class="text-lg text-base-content/80">
|
||||
A Living Dex is a complete Pokédex where you keep one of every Pokémon in your boxes
|
||||
(often including forms/variants). Living Dex Tracker helps you build and maintain that
|
||||
collection with filters, notes, and progress tracking.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Features Section -->
|
||||
<div class="py-16 bg-base-200">
|
||||
<div class="container mx-auto px-4 max-w-6xl">
|
||||
<h2 class="text-4xl font-bold mb-12 text-center">Why Choose Living Dex Tracker?</h2>
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-6">
|
||||
<div class="card bg-neutral shadow-xl">
|
||||
<div class="card-body">
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="flex-shrink-0">
|
||||
<svg
|
||||
class="w-10 h-10 text-green-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="card-title text-xl mb-2">Social & Shareable</h2>
|
||||
<p class="text-base-content/80">
|
||||
Easily share your Pokédex journey with friends, or find theirs. If you'd rather go
|
||||
it alone, that's okay too!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-neutral shadow-xl">
|
||||
<div class="card-body">
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="flex-shrink-0">
|
||||
<svg
|
||||
class="w-10 h-10 text-green-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="card-title text-xl mb-2">Free & Open Source</h2>
|
||||
<p class="text-base-content/80">
|
||||
Completely open source and free to use, enabling the community to contribute
|
||||
updates as soon as new Pokémon are released.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-neutral shadow-xl">
|
||||
<div class="card-body">
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="flex-shrink-0">
|
||||
<svg
|
||||
class="w-10 h-10 text-green-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="card-title text-xl mb-2">Advanced Filtering</h2>
|
||||
<p class="text-base-content/80">
|
||||
Track simple progress or tackle harder variants like a Living Origin Form Dex with
|
||||
our powerful filtering options for targeted catching sessions.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-neutral shadow-xl">
|
||||
<div class="card-body">
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="flex-shrink-0">
|
||||
<svg
|
||||
class="w-10 h-10 text-green-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="card-title text-xl mb-2">100% free</h2>
|
||||
<p class="text-base-content/80">
|
||||
Did we mention it's completely free to use? Oh, we did? Good. Because it is.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CTA Section -->
|
||||
<div class="py-16 bg-base-100">
|
||||
<div class="container mx-auto px-4 text-center">
|
||||
<h2 class="text-4xl font-bold mb-6">Ready to Start Your Journey?</h2>
|
||||
<p class="text-xl mb-8 text-base-content/80 max-w-2xl mx-auto">
|
||||
Get started today with tracking your Living Pokédex progress. It's free, open source, and
|
||||
built with love for the Pokémon community.
|
||||
</p>
|
||||
<div class="flex flex-wrap gap-4 justify-center">
|
||||
<div class="card shrink-0 w-full max-w-sm shadow-2xl bg-neutral">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-xl mb-4">Sign Up Now</h3>
|
||||
<SignUp {supabase} on:signedUp={handleSignedUp} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Legal Section -->
|
||||
<div class="py-8 bg-base-200">
|
||||
<div class="container mx-auto px-4 max-w-4xl">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-lg mb-2">Legal Disclaimer</h2>
|
||||
<p class="text-sm text-base-content/70">
|
||||
Living Dex Tracker is a fan-made project. We do not claim ownership of any Pokémon
|
||||
characters, images, or other content featured on this website. This project is not
|
||||
affiliated with, endorsed, sponsored, or specifically approved by Nintendo, Game Freak,
|
||||
or The Pokémon Company.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,327 +0,0 @@
|
||||
<svelte:head>
|
||||
<title>About Us</title>
|
||||
<meta name="description" content="About this app" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&family=Staatliches&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</svelte:head>
|
||||
|
||||
<div class="content h-full bg-base inline-block">
|
||||
<div id="grad">
|
||||
<div id="banner-content">
|
||||
<p class=" text-xs opacity-70 tracking-wide">Learn</p>
|
||||
<h2 class=" mt-0 pt-0 text-5xl tracking-widest text-center font-bold p-24">
|
||||
About<br /> Us
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="introduction">
|
||||
<p class="font-semibold text-xl mb-5 ml-5">
|
||||
Introducing <span class="typewriter-text underline decoration-accent">Living Dex Tracker</span
|
||||
>
|
||||
</p>
|
||||
<p class="text-base mt-10 mb-5 ml-5 mr-5">
|
||||
<img src="/placeholder-bulb.png" alt="bulb" class="float-right w-28" />
|
||||
Living Dex Tracker is dolor sit amet, consectetur adipiscing elit. Proin dignissim risus eu quam
|
||||
feugiat malesuada. Vivamus arcu sapien, feugiat sed lacus ut, malesuada congue nibh. In lacinia
|
||||
lacus quis bibendum pulvinar. Aliquam in suscipit risus. Aliquam ut justo dolor.
|
||||
</p>
|
||||
|
||||
<p class="font-semibold text-xl mt-20 mb-5 ml-5">Features</p>
|
||||
|
||||
<!-- TODO (#41) - Make this a card carousel -->
|
||||
<div class="card md:card-side bg-base-00 shadow-m">
|
||||
<figure>
|
||||
<img src="/OIG3.jpeg" alt="Album" />
|
||||
</figure>
|
||||
<div class="card-body">
|
||||
<p class="card-title">Player Dex Search</p>
|
||||
<p>Find and explore your friends' Pokémon collections effortlessly.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-neutral pb-20">
|
||||
<p class="font-semibold text-white text-xl mt-0 mb-5 ml-5">Meet The Team</p>
|
||||
<div class="avatar flex items-center justify-end mb-20">
|
||||
<p class="text-m mb-5 ml-5 mr-5">Team Member 1</p>
|
||||
<div class="w-24 rounded-full flex justify-end">
|
||||
<img src="/OIG5.jpg" alt="profile" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="avatar">
|
||||
<div class="w-24 rounded-full">
|
||||
<img src="/OIG5.jpg" alt="profile " />
|
||||
</div>
|
||||
|
||||
<p class="text-m mb-5 ml-5 mr-5">Team Member 2</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="project-details">
|
||||
<p class="font-semibold text-xl mt-10 mb-5 ml-5">The Developement</p>
|
||||
<p class="text-sm mb-5 ml-5 mr-5">
|
||||
Share insights into the development process, challenges faced, and any interesting anecdotes
|
||||
or milestones achieved during the project's journey.
|
||||
</p>
|
||||
|
||||
<ul class="timeline timeline-vertical">
|
||||
<li>
|
||||
<div class="timeline-start timeline-box">Example</div>
|
||||
<div class="timeline-middle">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-5 h-5 text-primary"
|
||||
><path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<hr class="bg-primary" />
|
||||
</li>
|
||||
<li>
|
||||
<hr class="bg-primary" />
|
||||
<div class="timeline-middle">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-5 h-5 text-primary"
|
||||
><path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<div class="timeline-end timeline-box">Example</div>
|
||||
<hr class="bg-primary" />
|
||||
</li>
|
||||
<li>
|
||||
<hr class="bg-primary" />
|
||||
<div class="timeline-start timeline-box">Example</div>
|
||||
<div class="timeline-middle">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-5 h-5 text-primary"
|
||||
><path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<hr />
|
||||
</li>
|
||||
<li>
|
||||
<hr />
|
||||
<div class="timeline-middle">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-5 h-5"
|
||||
><path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<div class="timeline-end timeline-box">Example</div>
|
||||
<hr />
|
||||
</li>
|
||||
<li>
|
||||
<hr />
|
||||
<div class="timeline-start timeline-box">Example</div>
|
||||
<div class="timeline-middle">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-5 h-5"
|
||||
><path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p class="font-semibold text-xl mt-10 mb-5 ml-5">Join Us On Discord!</p>
|
||||
|
||||
<div id="contact-information ">
|
||||
<a href="https://discord.gg/2ytj4pkUPY">
|
||||
<button
|
||||
class="relative inline-flex items-center justify-center w-16 p-0.5 ml-5 mb-20 me-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-gradient-to-br from-cyan-500 to-blue-500 group-hover:from-cyan-500 group-hover:to-blue-500 hover:text-white dark:text-white focus:ring-4 focus:outline-none focus:ring-cyan-200 dark:focus:ring-cyan-800"
|
||||
>
|
||||
<img src="/discord1.svg" class="w-12" /></button
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="contact-form">
|
||||
<p class="font-semibold text-xl mt-0 mb-5 text-white pt-10">Contact Form</p>
|
||||
<input type="text" name="first" placeholder="First Name" autocomplete="off" required />
|
||||
<input type="text" name="last" placeholder="Last Name" autocomplete="off" required />
|
||||
<input type="email" name="Email" placeholder="Email Address" autocomplete="off" required />
|
||||
<textarea
|
||||
rows="5"
|
||||
cols="50"
|
||||
name="message"
|
||||
placeholder="Enter text"
|
||||
autocomplete="off"
|
||||
required
|
||||
/>
|
||||
<button type="submit" id="submit-button">Send Message</button>
|
||||
</div>
|
||||
|
||||
<div id="legal-information">
|
||||
<p class="font-semibold text-xl mt-0 mb-5 ml-5 text-white pt-10">Legal</p>
|
||||
|
||||
<p class="text-sm mb-5 ml-5 mr-5">
|
||||
Living Dex Tracker is a fan-made website dedicated to providing information about Pokemon
|
||||
creatures. We do not claim ownership of any Pokemon characters, images, or other content
|
||||
featured on this website.
|
||||
</p>
|
||||
<p class="text-sm mb-5 ml-5 mr-5">
|
||||
We do not generate revenue from the use of Pokemon content. Any advertisements or sponsored
|
||||
content on this website are unrelated to Pokemon and are used solely to support the
|
||||
maintenance and operation of the website.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="Acknowledgments">
|
||||
<p class="font-semibold text-xl mt-0 mb-5 ml-5 text-white pt-10">Acknowledgments</p>
|
||||
<p class="text-sm mb-5 ml-5 mr-5">
|
||||
Express gratitude to any individuals or organisations that have contributed to the project's
|
||||
success, including sponsors, supporters, or open-source contributors.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#banner-content {
|
||||
padding-top: 170px;
|
||||
}
|
||||
#grad {
|
||||
font-family: 'Pixelify Sans', sans-serif;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
|
||||
width: 100%;
|
||||
height: 422px;
|
||||
margin: 0 auto;
|
||||
background: linear-gradient(45deg, #d2001a, #7462ff, #f48e21, #23d5ab);
|
||||
color: #fff;
|
||||
background-size: 300% 300%;
|
||||
animation: color 12s ease-in-out infinite;
|
||||
text-align: center;
|
||||
}
|
||||
@keyframes color {
|
||||
0% {
|
||||
background-position: 0 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0 50%;
|
||||
}
|
||||
}
|
||||
|
||||
#introduction .font-semibold {
|
||||
font-family: 'Staatliches', sans-serif;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-size: 25px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.contact-form {
|
||||
background-color: rgb(216, 224, 178);
|
||||
width: 380px;
|
||||
height: 590px;
|
||||
border-radius: 20px;
|
||||
margin-bottom: 40px;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.contact-form > p {
|
||||
margin-left: 9px;
|
||||
}
|
||||
input {
|
||||
background-color: rgb(156, 186, 139);
|
||||
width: 70%;
|
||||
margin-left: 12%;
|
||||
padding: 16px 16px;
|
||||
border-radius: 10px;
|
||||
border-color: rgb(131, 167, 124);
|
||||
border-width: 2px;
|
||||
margin-bottom: 20px;
|
||||
font-family: 'Staatliches', sans-serif;
|
||||
}
|
||||
|
||||
textarea {
|
||||
background-color: rgb(156, 186, 139);
|
||||
width: 70%;
|
||||
margin-left: 12%;
|
||||
padding: 16px 16px;
|
||||
border-radius: 10px;
|
||||
border-color: rgb(83, 145, 50);
|
||||
margin-bottom: 25px;
|
||||
font-family: 'Staatliches', sans-serif;
|
||||
}
|
||||
|
||||
input:focus-within {
|
||||
outline: none;
|
||||
border-color: rgb(169, 227, 157);
|
||||
border-width: 3px;
|
||||
font-family: 'Staatliches', sans-serif;
|
||||
}
|
||||
textarea:focus-within {
|
||||
outline: none;
|
||||
border-color: rgb(169, 227, 157);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
#submit-button {
|
||||
background-color: rgb(185, 201, 135);
|
||||
border-radius: 20px;
|
||||
border-color: #fff;
|
||||
padding: 10px 18px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
margin: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
opacity: 80%;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -1,9 +0,0 @@
|
||||
import { dev } from '$app/environment';
|
||||
|
||||
// we don't need any JS on this page, though we'll load
|
||||
// it in dev so that we get hot module replacement...
|
||||
export const csr = dev;
|
||||
|
||||
// since there's no dynamic data here, we can prerender
|
||||
// it so that it gets served as a static asset in prod
|
||||
export const prerender = true;
|
||||
@@ -1,58 +0,0 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { dbConnect, dbDisconnect } from '$lib/utils/db';
|
||||
import { type CatchRecord } from '$lib/models/CatchRecord';
|
||||
import CatchRecordRepository from '$lib/repositories/CatchRecordRepository';
|
||||
|
||||
export const GET = async () => {
|
||||
let catchData = null as CatchRecord[] | null;
|
||||
|
||||
try {
|
||||
await dbConnect();
|
||||
const repo = new CatchRecordRepository();
|
||||
catchData = await repo.findAll();
|
||||
// order by pokedexEntryId property, ascending
|
||||
catchData = catchData.sort((a, b) => a.pokedexEntryId - b.pokedexEntryId);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
dbDisconnect();
|
||||
}
|
||||
|
||||
return json(catchData);
|
||||
};
|
||||
|
||||
export const PUT = async ({ request }) => {
|
||||
try {
|
||||
const data: Partial<CatchRecord> = await request.json();
|
||||
await dbConnect();
|
||||
const repo = new CatchRecordRepository();
|
||||
const upsertedRecord = await repo.upsert(data);
|
||||
return json(upsertedRecord);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw error(500, 'Internal Server Error');
|
||||
} finally {
|
||||
await dbDisconnect();
|
||||
}
|
||||
};
|
||||
|
||||
export const POST = async ({ request }) => {
|
||||
try {
|
||||
const records: Partial<CatchRecord>[] = await request.json();
|
||||
await dbConnect();
|
||||
const repo = new CatchRecordRepository();
|
||||
|
||||
const insertedRecords = [];
|
||||
for (const record of records) {
|
||||
const upsertedRecord = await repo.upsert(record);
|
||||
insertedRecords.push(upsertedRecord);
|
||||
}
|
||||
|
||||
return json(insertedRecords);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw error(500, 'Internal Server Error');
|
||||
} finally {
|
||||
await dbDisconnect();
|
||||
}
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { dbConnect, dbDisconnect } from '$lib/utils/db';
|
||||
import CombinedDataRepository from '$lib/repositories/CombinedDataRepository';
|
||||
|
||||
export const GET = async ({ url }) => {
|
||||
const page = parseInt(url.searchParams.get('page') || '1', 10);
|
||||
const limit = parseInt(url.searchParams.get('limit') || '20', 10);
|
||||
const enableForms = url.searchParams.get('enableForms') === 'true';
|
||||
const region = url.searchParams.get('region');
|
||||
const game = url.searchParams.get('game');
|
||||
|
||||
try {
|
||||
await dbConnect();
|
||||
const repo = new CombinedDataRepository();
|
||||
const combinedData = await repo.findCombinedData(page, limit, enableForms, region, game);
|
||||
|
||||
if (combinedData.length === 0) {
|
||||
return json({ error: 'No combined data found' }, { status: 404 });
|
||||
}
|
||||
const totalCount = await repo.countCombinedData(enableForms, region, game);
|
||||
const totalPages = Math.ceil(totalCount / limit);
|
||||
|
||||
return json({ combinedData, totalPages });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
} finally {
|
||||
dbDisconnect();
|
||||
}
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { dbConnect, dbDisconnect } from '$lib/utils/db';
|
||||
import CombinedDataRepository from '$lib/repositories/CombinedDataRepository';
|
||||
|
||||
export const GET = async ({ url }) => {
|
||||
const enableForms = url.searchParams.get('enableForms') === 'true';
|
||||
const region = url.searchParams.get('region');
|
||||
const game = url.searchParams.get('game');
|
||||
|
||||
try {
|
||||
await dbConnect();
|
||||
const repo = new CombinedDataRepository();
|
||||
const combinedData = await repo.findAllCombinedData(enableForms, region, game);
|
||||
|
||||
if (combinedData.length === 0) {
|
||||
return json({ error: 'No combined data found' }, { status: 404 });
|
||||
}
|
||||
return json(combinedData);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
} finally {
|
||||
dbDisconnect();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestEvent } from '@sveltejs/kit';
|
||||
import PokedexExportIntegrationRepository from '$lib/repositories/PokedexExportIntegrationRepository';
|
||||
import { requireAuth } from '$lib/utils/auth';
|
||||
|
||||
export const GET = async (event: RequestEvent) => {
|
||||
try {
|
||||
const userId = await requireAuth(event);
|
||||
|
||||
const { session } = await event.locals.safeGetSession();
|
||||
if (session) {
|
||||
await event.locals.supabase.auth.setSession(session);
|
||||
}
|
||||
|
||||
const repo = new PokedexExportIntegrationRepository(event.locals.supabase, userId, null);
|
||||
const integrations = await repo.listAll();
|
||||
|
||||
const safe = integrations.map((integration) => ({
|
||||
id: integration._id,
|
||||
provider: integration.provider,
|
||||
enabled: integration.enabled,
|
||||
fileName: integration.fileName,
|
||||
folderId: integration.folderId,
|
||||
path: integration.path,
|
||||
metadata: integration.metadata,
|
||||
lastExportedAt: integration.lastExportedAt,
|
||||
lastError: integration.lastError
|
||||
}));
|
||||
|
||||
return json(safe);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (err && typeof err === 'object' && 'status' in err) {
|
||||
throw err;
|
||||
}
|
||||
return json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestEvent } from '@sveltejs/kit';
|
||||
import { requireAuth } from '$lib/utils/auth';
|
||||
|
||||
const ALLOWED_PROVIDERS = new Set(['google_drive', 'dropbox']);
|
||||
|
||||
export const PUT = async (event: RequestEvent) => {
|
||||
try {
|
||||
const userId = await requireAuth(event);
|
||||
const { provider } = event.params;
|
||||
|
||||
if (!provider || !ALLOWED_PROVIDERS.has(provider)) {
|
||||
return json({ error: 'Invalid provider' }, { status: 400 });
|
||||
}
|
||||
|
||||
const { session } = await event.locals.safeGetSession();
|
||||
if (session) {
|
||||
await event.locals.supabase.auth.setSession(session);
|
||||
}
|
||||
|
||||
let body: {
|
||||
folderId?: string | null;
|
||||
path?: string | null;
|
||||
};
|
||||
try {
|
||||
body = (await event.request.json()) as {
|
||||
folderId?: string | null;
|
||||
path?: string | null;
|
||||
};
|
||||
} catch (err) {
|
||||
if (err instanceof SyntaxError) {
|
||||
return new Response('Malformed JSON', { status: 400 });
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
const patch: Record<string, unknown> = {};
|
||||
if (body.folderId !== undefined) patch.folderId = body.folderId;
|
||||
if (body.path !== undefined) patch.path = body.path;
|
||||
if (Object.keys(patch).length === 0) {
|
||||
return json({ error: 'No fields to update' }, { status: 400 });
|
||||
}
|
||||
|
||||
const { data, error } = await event.locals.supabase
|
||||
.from('pokedex_export_integrations')
|
||||
.update(patch)
|
||||
.eq('userId', userId)
|
||||
.is('pokedexId', null)
|
||||
.eq('provider', provider)
|
||||
.select('id, provider, enabled, fileName, folderId, path, metadata, lastExportedAt, lastError')
|
||||
.maybeSingle();
|
||||
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
}
|
||||
|
||||
if (data === null) {
|
||||
return json({ error: 'Integration not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
return json(data);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (err && typeof err === 'object' && 'status' in err) {
|
||||
throw err;
|
||||
}
|
||||
return json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { listGameDexes } from '$lib/services/PokedexDexScopeService';
|
||||
|
||||
/**
|
||||
* GET /api/game-dexes
|
||||
* Returns game dexes grouped by game display name.
|
||||
*/
|
||||
export const GET: RequestHandler = async ({ locals }) => {
|
||||
try {
|
||||
const { gameDexes, gameOrder, games } = await listGameDexes(locals.supabase);
|
||||
return json({ gameDexes, gameOrder, games });
|
||||
} catch (err) {
|
||||
console.error('Unexpected error fetching game dexes:', err);
|
||||
return json({ error: 'Internal server error' }, { status: 500 });
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
/**
|
||||
* GET /api/games
|
||||
* Returns all games from the games table, sorted by release year descending (newest first)
|
||||
*/
|
||||
export const GET: RequestHandler = async ({ locals }) => {
|
||||
const { supabase } = locals;
|
||||
|
||||
try {
|
||||
// Query games table for all games, sorted by release year descending
|
||||
const { data, error } = await supabase
|
||||
.from('games')
|
||||
.select('displayName, releaseYear')
|
||||
.order('releaseYear', { ascending: false })
|
||||
.order('displayName', { ascending: true }); // Secondary sort by name for same year
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching games:', error);
|
||||
return json({ error: 'Failed to fetch games' }, { status: 500 });
|
||||
}
|
||||
|
||||
// Extract just the display names
|
||||
const gameNames = data.map((row) => row.displayName);
|
||||
|
||||
return json({ games: gameNames });
|
||||
} catch (err) {
|
||||
console.error('Unexpected error fetching games:', err);
|
||||
return json({ error: 'Internal server error' }, { status: 500 });
|
||||
}
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user