Skip to content

Commit f2a71f6

Browse files
committed
Add demo project
1 parent 3a428c1 commit f2a71f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+12960
-2621
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,12 @@ jobs:
1717
run: npm ci
1818
- name: Build
1919
run: npm run build
20-
- name: Build github pages
21-
run: |
22-
mkdir -p /tmp/github-pages/dist
23-
cp -r packages/tyria/dev/* /tmp/github-pages
24-
cp -r packages/tyria/dist/* /tmp/github-pages/dist
2520
- name: Upload github pages artifact
2621
uses: actions/upload-pages-artifact@v3
2722
with:
28-
path: /tmp/github-pages/
23+
path: apps/demo/dist/
2924

3025
deploy-gh-pages:
31-
if: github.event_name == 'push'
3226
needs: build
3327
permissions:
3428
pages: write
@@ -38,6 +32,6 @@ jobs:
3832
url: ${{ steps.deployment.outputs.page_url }}
3933
runs-on: ubuntu-latest
4034
steps:
41-
- name: Deploy to GitHub Pages
42-
id: deployment
43-
uses: actions/deploy-pages@v4
35+
- name: Deploy to GitHub Pages
36+
id: deployment
37+
uses: actions/deploy-pages@v4

apps/demo/.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

apps/demo/README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# React + TypeScript + Vite
2+
3+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4+
5+
Currently, two official plugins are available:
6+
7+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
8+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9+
10+
## Expanding the ESLint configuration
11+
12+
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
13+
14+
```js
15+
export default tseslint.config({
16+
extends: [
17+
// Remove ...tseslint.configs.recommended and replace with this
18+
...tseslint.configs.recommendedTypeChecked,
19+
// Alternatively, use this for stricter rules
20+
...tseslint.configs.strictTypeChecked,
21+
// Optionally, add this for stylistic rules
22+
...tseslint.configs.stylisticTypeChecked,
23+
],
24+
languageOptions: {
25+
// other options...
26+
parserOptions: {
27+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
28+
tsconfigRootDir: import.meta.dirname,
29+
},
30+
},
31+
})
32+
```
33+
34+
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
35+
36+
```js
37+
// eslint.config.js
38+
import reactX from 'eslint-plugin-react-x'
39+
import reactDom from 'eslint-plugin-react-dom'
40+
41+
export default tseslint.config({
42+
plugins: {
43+
// Add the react-x and react-dom plugins
44+
'react-x': reactX,
45+
'react-dom': reactDom,
46+
},
47+
rules: {
48+
// other rules...
49+
// Enable its recommended typescript rules
50+
...reactX.configs['recommended-typescript'].rules,
51+
...reactDom.configs.recommended.rules,
52+
},
53+
})
54+
```

apps/demo/eslint.config.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import js from '@eslint/js'
2+
import globals from 'globals'
3+
import reactHooks from 'eslint-plugin-react-hooks'
4+
import reactRefresh from 'eslint-plugin-react-refresh'
5+
import tseslint from 'typescript-eslint'
6+
7+
export default tseslint.config(
8+
{ ignores: ['dist'] },
9+
{
10+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
11+
files: ['**/*.{ts,tsx}'],
12+
languageOptions: {
13+
ecmaVersion: 2020,
14+
globals: globals.browser,
15+
},
16+
plugins: {
17+
'react-hooks': reactHooks,
18+
'react-refresh': reactRefresh,
19+
},
20+
rules: {
21+
...reactHooks.configs.recommended.rules,
22+
'react-refresh/only-export-components': [
23+
'warn',
24+
{ allowConstantExport: true },
25+
],
26+
},
27+
},
28+
)

apps/demo/index.html

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Tyria</title>
7+
<style>
8+
html, body {
9+
margin: 0;
10+
padding: 0;
11+
overflow: hidden;
12+
background-color: #051626;
13+
}
14+
#map {
15+
position: absolute;
16+
inset: 0;
17+
animation: fadeIn 2s ease-out;
18+
}
19+
@keyframes fadeIn {
20+
from { opacity: 0; }
21+
}
22+
.controls {
23+
position: absolute;
24+
top: calc(50% - 48px);
25+
right: 16px;
26+
display: flex;
27+
flex-direction: column;
28+
background-color: #fff;
29+
border-radius: 2px;
30+
box-shadow: 0 0 4px rgb(0 0 0 / .5);
31+
overflow: hidden;
32+
}
33+
.controls > button {
34+
width: 48px;
35+
height: 48px;
36+
background: transparent;
37+
border: none;
38+
font-size: 24px;
39+
cursor: pointer;
40+
}
41+
.controls > button + button {
42+
border-top: 1px solid #eee;
43+
}
44+
.controls > button:hover {
45+
background-color: #eee;
46+
}
47+
.toolbar {
48+
position: absolute;
49+
bottom: 16px;
50+
background: #fff;
51+
margin-left: 50%;
52+
margin-right: -50%;
53+
transform: translateX(-50%);
54+
padding: 16px;
55+
border-radius: 2px;
56+
box-shadow: 0 0 4px rgb(0 0 0 / .5);
57+
display: flex;
58+
gap: 16px;
59+
}
60+
#over {
61+
position: absolute;
62+
top: 16px;
63+
background: #fff;
64+
margin-left: 50%;
65+
margin-right: -50%;
66+
transform: translateX(-50%);
67+
padding: 16px;
68+
border-radius: 2px;
69+
box-shadow: 0 0 4px rgb(0 0 0 / .5);
70+
display: flex;
71+
gap: 16px;
72+
}
73+
#over:empty {
74+
display: none;
75+
}
76+
</style>
77+
</head>
78+
<body>
79+
<div id="map">
80+
<div class="controls">
81+
<button onclick="map.easeTo({ zoom: map.view.zoom + .5 }, { duration: 300 })">+</button>
82+
<button onclick="map.easeTo({ zoom: map.view.zoom - .5 }, { duration: 300 })">-</button>
83+
</div>
84+
</div>
85+
<div class="toolbar">
86+
<label>
87+
<input type="checkbox" id="debug"/>
88+
debug overlays
89+
</label>
90+
<button id="lionsarch">Lion's Arch</button>
91+
<button id="ascalon">Ascalon</button>
92+
<button id="horn">Horn of Maguuma</button>
93+
<button id="cantha">Cantha</button>
94+
</div>
95+
<div id="over"></div>
96+
<script type="module" src="/src/index.ts"></script>
97+
</body>
98+
</html>

apps/demo/package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "demo",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc -b && vite build",
9+
"lint": "eslint .",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"react": "^19.0.0",
14+
"react-dom": "^19.0.0",
15+
"tyria": "*"
16+
},
17+
"devDependencies": {
18+
"@eslint/js": "^9.22.0",
19+
"@types/node": "^22.14.1",
20+
"@types/react": "^19.0.10",
21+
"@types/react-dom": "^19.0.4",
22+
"@vitejs/plugin-react-swc": "^3.8.0",
23+
"eslint": "^9.22.0",
24+
"eslint-plugin-react-hooks": "^5.2.0",
25+
"eslint-plugin-react-refresh": "^0.4.19",
26+
"globals": "^16.0.0",
27+
"typescript": "~5.7.2",
28+
"typescript-eslint": "^8.26.1",
29+
"vite": "^6.3.1"
30+
}
31+
}

apps/demo/src/index.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Tyria, TileLayer, MarkerLayer } from 'tyria';
2+
3+
const map = new Tyria(document.getElementById('map')!, {
4+
backgroundColor: '#051626',
5+
maxZoom: 7,
6+
minZoom: 1,
7+
zoomSnap: .5,
8+
padding: 80,
9+
bounds: [[0, 0], [81920, 114688]],
10+
// padding: { top: 16, bottom: 80, left: 16, right: 80 },
11+
});
12+
13+
map.addLayer(new TileLayer({
14+
source: (x, y, z) => `https://tiles.gw2.io/1/1/${z}/${x}/${y}.jpg`,
15+
bounds: [[0, 0], [81920, 114688]],
16+
}));
17+
18+
const markers = new MarkerLayer({
19+
icon: 'https://render.guildwars2.com/file/32633AF8ADEA696A1EF56D3AE32D617B10D3AC57/157353.png',
20+
iconSize: [32, 32],
21+
minZoom: 3,
22+
});
23+
map.addLayer(markers)
24+
25+
const waypoints = new Map();
26+
27+
fetch('https://api.guildwars2.com/v2/continents/1/floors/1').then((r) => r.json()).then((data) => {
28+
// @ts-expect-error test
29+
const wps = Object.values(data.regions ?? []).flatMap((region) => Object.values(region.maps ?? {}).flatMap((map) => Object.values(map.points_of_interest ?? {}).filter((poi) => poi.type === 'waypoint').map((poi) => ({ ...poi, map }))));
30+
wps.forEach((wp) => waypoints.set(wp.id, wp));
31+
markers.add(...wps.map((wp) => ({
32+
id: wp.id,
33+
position: wp.coord,
34+
})))
35+
});
36+
37+
map.jumpTo({ center: [49432, 31440], zoom: 2.5 });
38+
map.easeTo({ zoom: 3 }, { duration: 2000, easing: (x) => 1 - Math.pow(1 - x, 3) });
39+
40+
map.addEventListener('marker.over', (e) => document.getElementById('over')!.innerText = waypoints.get(e.markerId).name);
41+
map.addEventListener('marker.leave', () => document.getElementById('over')!.innerText = '');
42+
map.addEventListener('marker.click', (e) => {
43+
const wp = waypoints.get(e.markerId);
44+
console.log(wp);
45+
map.easeTo({ contain: wp.map.continent_rect })
46+
});
47+
48+
// @ts-expect-error test
49+
document.getElementById('debug')!.addEventListener('change', (e) => map.setDebug(e.target.checked));
50+
51+
document.getElementById('lionsarch')!.addEventListener('click', () => map.easeTo({ contain: [[48130, 30720], [50430, 32250]] }))
52+
document.getElementById('ascalon')!.addEventListener('click', () => map.easeTo({ contain: [[56682, 24700], [64500, 35800]], zoom: 3 }))
53+
document.getElementById('horn')!.addEventListener('click', () => map.easeTo({ contain: [[19328, 19048], [27296, 24800]] }))
54+
document.getElementById('cantha')!.addEventListener('click', () => map.easeTo({ contain: [[20576, 97840], [39056, 106256]] }))
55+
56+
// @ts-expect-error debug
57+
window.map = map;

apps/demo/src/vite-env.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="vite/client" />

apps/demo/src/wvw/App.module.css

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
.layout {
2+
display: flex;
3+
gap: 16px;
4+
padding: 16px;
5+
flex: 1;
6+
}
7+
8+
.map {
9+
flex: 1;
10+
position: relative;
11+
}
12+
13+
.map > canvas {
14+
border-radius: 6px;
15+
position: absolute;
16+
inset: 0;
17+
}
18+
19+
.sidebar {
20+
width: 400px;
21+
}
22+
23+
24+
.controls {
25+
position: absolute;
26+
top: 16px;
27+
left: 16px;
28+
display: flex;
29+
flex-direction: column;
30+
background-color: #fff;
31+
border-radius: 4px;
32+
box-shadow: 0 0 4px rgb(0 0 0 / .5);
33+
overflow: hidden;
34+
}
35+
.controls > button {
36+
width: 48px;
37+
height: 48px;
38+
background: transparent;
39+
border: none;
40+
font-size: 24px;
41+
cursor: pointer;
42+
}
43+
.controls > button + button {
44+
border-top: 1px solid #eee;
45+
}
46+
.controls > button:hover {
47+
background-color: #eee;
48+
}

0 commit comments

Comments
 (0)