@coturnix_fr/grain 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
Binary file
@@ -19,7 +19,10 @@
19
19
  "moduleResolution": "bundler",
20
20
  "module": "esnext",
21
21
  "noEmit": true,
22
- "target": "esnext"
22
+ "target": "esnext",
23
+ "types": [
24
+ "node"
25
+ ]
23
26
  },
24
27
  "include": [
25
28
  "ambient.d.ts",
@@ -30,6 +33,9 @@
30
33
  "../src/**/*.js",
31
34
  "../src/**/*.ts",
32
35
  "../src/**/*.svelte",
36
+ "../test/**/*.js",
37
+ "../test/**/*.ts",
38
+ "../test/**/*.svelte",
33
39
  "../tests/**/*.js",
34
40
  "../tests/**/*.ts",
35
41
  "../tests/**/*.svelte"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coturnix_fr/grain",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "prettier": {
5
5
  "trailingComma": "es5",
6
6
  "tabWidth": 4,
@@ -9,47 +9,46 @@
9
9
  "bracketSameLine": true
10
10
  },
11
11
  "devDependencies": {
12
- "@eslint/compat": "^1.4.1",
13
- "@eslint/js": "^9.38.0",
12
+ "@eslint/compat": "^2.1.0",
13
+ "@eslint/js": "^10.0.1",
14
14
  "@popperjs/core": "^2.11.7",
15
- "@sveltejs/adapter-node": "^5.3.2",
16
- "@sveltejs/kit": "^2.41.0",
15
+ "@sveltejs/adapter-node": "^5.5.4",
16
+ "@sveltejs/kit": "^2.61.1",
17
17
  "@types/d3": "^7.4.3",
18
- "@types/leaflet": "^1.9.20",
19
- "@types/leaflet.fullscreen": "^3.0.3",
20
- "@types/node": "^22",
21
- "@types/plotly.js": "^3.0.6",
22
- "@typescript-eslint/eslint-plugin": "^8.44.0",
23
- "@typescript-eslint/parser": "^8.44.0",
24
- "daisyui": "^5.5.18",
25
- "eslint": "^9.38.0",
18
+ "@types/leaflet": "^1.9.21",
19
+ "@types/node": "^25.9.1",
20
+ "@types/plotly.js": "^3.0.10",
21
+ "@typescript-eslint/eslint-plugin": "^8.60.0",
22
+ "@typescript-eslint/parser": "^8.60.0",
23
+ "daisyui": "^5.5.20",
24
+ "eslint": "^10.4.0",
26
25
  "eslint-config-prettier": "^10.1.8",
27
- "eslint-plugin-svelte": "^3.12.4",
28
- "globals": "^16.4.0",
29
- "prettier": "^3.6.2",
30
- "prettier-plugin-svelte": "^3.4.0",
31
- "sass": "=1.77.6",
32
- "sv": "^0.9.11",
33
- "svelte": "^5.38.10",
34
- "svelte-preprocess": "^6.0.3",
35
- "tailwindcss": "^4.1.18",
26
+ "eslint-plugin-svelte": "^3.17.1",
27
+ "globals": "^17.6.0",
28
+ "prettier": "^3.8.3",
29
+ "prettier-plugin-svelte": "^4.0.1",
30
+ "sv": "^0.15.3",
31
+ "svelte": "^5.55.9",
32
+ "svelte-preprocess": "^6.0.5",
33
+ "tailwindcss": "^4.3.0",
36
34
  "tslib": "^2.8.1",
37
- "typescript": "^5.9.2",
38
- "typescript-eslint": "^8.46.1",
39
- "typescript-language-server": "^5.0.0",
40
- "vite": "^7.1.5"
35
+ "typescript": "^6.0.3",
36
+ "typescript-eslint": "^8.60.0",
37
+ "typescript-language-server": "^5.3.0",
38
+ "vite": "^8.0.14"
41
39
  },
42
40
  "type": "module",
43
41
  "dependencies": {
44
42
  "@popperjs/core": "^2.11.8",
45
- "@sveltejs/vite-plugin-svelte": "^6.2.0",
46
- "@tailwindcss/vite": "^4.1.18",
43
+ "@sveltejs/vite-plugin-svelte": "^7.1.2",
44
+ "@tailwindcss/vite": "^4.3.0",
47
45
  "d3": "^7.9.0",
48
46
  "financial": "^0.2.4",
49
47
  "leaflet": "^1.9.4",
50
48
  "leaflet-gesture-handling": "^1.2.2",
51
- "leaflet.fullscreen": "^4.0.0",
52
- "plotly.js-dist": "^3.1.0",
49
+ "leaflet.fullscreen": "^5.3.1",
50
+ "plotly.js-dist": "^3.5.1",
51
+ "plotly.js-dist-min": "^3.5.1",
53
52
  "screenfull": "^6.0.2"
54
53
  },
55
54
  "scripts": {
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import '../../app.scss'
2
+ import '../../app.css'
3
3
  import { resolve } from '$app/paths'
4
4
  import Grain from './Grain.svelte'
5
5
  import { page } from '$app/state'
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import '../../app.scss'
2
+ import '../../app.css'
3
3
  let { logo = false } = $props()
4
4
  </script>
5
5
 
@@ -16,18 +16,15 @@
16
16
  </span>
17
17
  {/if}
18
18
 
19
- <style lang="scss">
20
- $primary: #b81413;
21
- $gp-2: #d71c19;
22
- $gp-3: #de601e;
23
- .co {
24
- color: $primary;
19
+ <style>
20
+ .co {
21
+ color: #b81413;
25
22
  }
26
23
  .g {
27
- color: $gp-3;
24
+ color: #de601e;
28
25
  }
29
26
  .ra {
30
- color: $gp-2;
27
+ color: #d71c19;
31
28
  }
32
29
  img {
33
30
  margin-left: 8px;
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import '../../app.scss'
2
+ import '../../app.css'
3
3
  let { logo = false } = $props()
4
4
  </script>
5
5
 
@@ -18,18 +18,15 @@
18
18
  ></span>
19
19
  {/if}
20
20
 
21
- <style lang="scss">
22
- $primary: #b81413;
23
- $gp-2: #d71c19;
24
- $gp-3: #de601e;
25
- .co {
26
- color: $primary;
21
+ <style>
22
+ .co {
23
+ color: #b81413;
27
24
  }
28
25
  .g {
29
- color: $gp-3;
26
+ color: #de601e;
30
27
  }
31
28
  .ra {
32
- color: $gp-2;
29
+ color: #d71c19;
33
30
  }
34
31
  img {
35
32
  margin-left: 8px;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { asset, resolve } from '$app/paths'
3
3
  import { getContext, onMount } from 'svelte'
4
- import '../../app.scss'
4
+ import '../../app.css'
5
5
  import Coturnix from './Coturnix.svelte'
6
6
  import Grain from './Grain.svelte'
7
7
  import Donnees from './Donnees.svelte'
@@ -150,7 +150,7 @@
150
150
  </div>
151
151
  </div>
152
152
 
153
- <style lang="scss">
153
+ <style>
154
154
  .sub {
155
155
  font-size: 1.4rem;
156
156
  font-weight: bold;
@@ -31,59 +31,61 @@
31
31
  email?: string
32
32
  }
33
33
 
34
- let data: Data = $state(props.data)
35
- let simulation = new Derived(data.simulation)
34
+ let data: Data = $derived(props.data)
35
+ let simulation = $derived(new Derived(data.simulation))
36
36
  let profils_modified = writable(false)
37
37
  let prms_modified = writable(false)
38
- let expert = writable(data.expert)
39
- let needsSaving = derived(
40
- [simulation.modified, profils_modified, prms_modified],
41
- ([$mod, $profils, $prms]) => {
42
- console.log('derived', $mod)
43
- return $mod || $profils || $prms
44
- }
38
+ let expert = $derived(writable(data.expert))
39
+ let needsSaving = $derived(
40
+ derived(
41
+ [simulation.modified, profils_modified, prms_modified],
42
+ ([$mod, $profils, $prms]) => {
43
+ console.log('derived', $mod)
44
+ return $mod || $profils || $prms
45
+ }
46
+ )
45
47
  )
46
-
47
- setContext('simulation', simulation)
48
- setContext('profils', writable(data.profils || []))
49
- setContext('prms', writable(data.prms || []))
50
- setContext('profils_modified', profils_modified)
51
- setContext('prms_modified', writable(data.prms || []))
52
- let communaute = writable(data.communaute)
53
- setContext('communaute', communaute)
54
- setContext('expert', expert)
55
- setContext('pvgis', writable({ pvgis: null, loading: false }))
56
- setContext(
57
- 'soleil',
58
- writable({
59
- hourly: {
60
- x: <string[]>[],
61
- y: <number[]>[],
62
- },
63
- daily: {
64
- x: <string[]>[],
65
- y: <number[]>[],
66
- },
67
- weekly: {
48
+ let communaute = $derived(writable(data.communaute))
49
+ $effect(() => {
50
+ setContext('simulation', simulation)
51
+ setContext('profils', writable(data.profils || []))
52
+ setContext('prms', writable(data.prms || []))
53
+ setContext('profils_modified', profils_modified)
54
+ setContext('prms_modified', writable(data.prms || []))
55
+ setContext('communaute', communaute)
56
+ setContext('expert', expert)
57
+ setContext('pvgis', writable({ pvgis: null, loading: false }))
58
+ setContext(
59
+ 'soleil',
60
+ writable({
61
+ hourly: {
62
+ x: <string[]>[],
63
+ y: <number[]>[],
64
+ },
65
+ daily: {
66
+ x: <string[]>[],
67
+ y: <number[]>[],
68
+ },
69
+ weekly: {
70
+ x: <string[]>[],
71
+ y: <number[]>[],
72
+ },
68
73
  x: <string[]>[],
69
74
  y: <number[]>[],
70
- },
71
- x: <string[]>[],
72
- y: <number[]>[],
73
- type: 'bar',
74
- line: {
75
- color: '#ffbf00',
76
- width: 1,
77
- },
78
- marker: {
79
- color: '#ffbf00',
80
- width: 1,
81
- },
82
- name: 'Production solaire',
83
- bucket: 1,
84
- })
85
- )
86
-
75
+ type: 'bar',
76
+ line: {
77
+ color: '#ffbf00',
78
+ width: 1,
79
+ },
80
+ marker: {
81
+ color: '#ffbf00',
82
+ width: 1,
83
+ },
84
+ name: 'Production solaire',
85
+ bucket: 1,
86
+ })
87
+ )
88
+ })
87
89
  const compteActive = $derived(page.route.id?.endsWith('/finances') ?? false)
88
90
  const descriptionActive = $derived(
89
91
  page.route.id?.endsWith('/description') ?? false
@@ -101,7 +103,7 @@
101
103
  let menuElt: null | HTMLElement = null
102
104
 
103
105
  const surface_kwc = 4.5
104
- let surface = $state(surface_kwc * data.simulation.puissance)
106
+ let surface = $derived(surface_kwc * data.simulation.puissance)
105
107
 
106
108
  function onTauxChange(ev: Event) {
107
109
  let t = ev.target as HTMLInputElement
@@ -133,15 +135,15 @@
133
135
  surface = $puissance * surface_kwc
134
136
  }
135
137
  }
136
- const puissance = simulation?.p.puissance
137
- const autoconso = simulation?.p.autoconso
138
- const autoprod = simulation?.p.autoprod
139
- const cout = simulation?.p.cout_elec
140
- const prix = simulation.p.prix
141
- const apport = simulation.p.apport
142
- const interet = simulation.p.interet
143
- const echeances = simulation.p.echeances
144
- const N = simulation.N
138
+ const puissance = $derived(simulation?.p.puissance)
139
+ const autoconso = $derived(simulation?.p.autoconso)
140
+ const autoprod = $derived(simulation?.p.autoprod)
141
+ const cout = $derived(simulation?.p.cout_elec)
142
+ const prix = $derived(simulation.p.prix)
143
+ const apport = $derived(simulation.p.apport)
144
+ const interet = $derived(simulation.p.interet)
145
+ const echeances = $derived(simulation.p.echeances)
146
+ const N = $derived(simulation.N)
145
147
 
146
148
  async function save_() {
147
149
  let resp = await fetch(`/grain/projet/${props.params.id}?/save`, {
@@ -196,12 +198,16 @@
196
198
  </div>
197
199
 
198
200
  <input
201
+ id="text-nom"
202
+ data-testid="text-nom"
199
203
  type="text"
200
204
  class="input input-lg"
201
205
  bind:value={data.nom}
202
206
  placeholder="Nouveau projet" />
203
207
  <form onsubmit={save}>
204
208
  <button
209
+ id="sauvegarder"
210
+ data-testid="sauvegarder"
205
211
  class="my-2 btn btn-sm btn-primary"
206
212
  disabled={!$needsSaving}>Sauvegarder</button>
207
213
  </form>
@@ -212,6 +218,7 @@
212
218
  type="checkbox"
213
219
  role="switch"
214
220
  id="expertsw"
221
+ data-testid="expertsw"
215
222
  bind:checked={$expert} />
216
223
  <label class="label ms" for="expertsw"
217
224
  >Niveau expert</label>
@@ -385,6 +392,7 @@
385
392
  class="tab"
386
393
  class:tab-active={syntheseActive}
387
394
  id="synthese-tab"
395
+ data-testid="synthese-tab"
388
396
  type="button"
389
397
  role="tab">Synthèse</a>
390
398
  <a
@@ -393,7 +401,8 @@
393
401
  })}
394
402
  class="tab"
395
403
  class:tab-active={compteActive}
396
- id="profile-tab"
404
+ id="finances-tab"
405
+ data-testid="finances-tab"
397
406
  type="button"
398
407
  role="tab">Détails financiers</a>
399
408
  <a
@@ -403,6 +412,7 @@
403
412
  class="tab"
404
413
  class:tab-active={descriptionActive}
405
414
  id="profile-tab"
415
+ data-testid="profile-tab"
406
416
  type="button"
407
417
  role="tab">Description</a>
408
418
 
@@ -413,6 +423,7 @@
413
423
  class="tab"
414
424
  class:tab-active={banqueActive}
415
425
  id="banque-tab"
426
+ data-testid="banque-tab"
416
427
  type="button"
417
428
  role="tab">Emprunt</a>
418
429
 
@@ -424,6 +435,7 @@
424
435
  class="tab"
425
436
  class:tab-active={expertActive}
426
437
  id="expert-tab"
438
+ data-testid="expert-tab"
427
439
  type="button"
428
440
  role="tab">Mode expert</a>
429
441
  {/if}
@@ -435,6 +447,7 @@
435
447
  class="tab"
436
448
  class:tab-active={simuActive}
437
449
  id="prm-tab"
450
+ data-testid="prm-tab"
438
451
  type="button"
439
452
  role="tab">Simulation</a>
440
453
  </div>
@@ -473,64 +473,29 @@
473
473
  </div>
474
474
  </div>
475
475
 
476
- <style lang="scss">
477
- $gp-1: #b71515;
478
- $gp-2: #d71c19;
479
- $gp-3: #de601e;
480
- $gs-1: #cf3e39;
481
-
476
+ <style>
482
477
  .loading {
483
478
  color: #ffbf00;
484
479
  }
485
480
 
486
- h5 {
487
- font-size: 1.5rem;
488
- font-weight: bold;
489
- }
490
-
491
- #syntheseTabContent h5 {
492
- border-bottom: 3px solid;
493
- font-size: 1.75rem;
494
- padding-bottom: 5px;
495
- }
496
-
497
481
  .donnee {
498
482
  font-size: 2rem;
499
483
  font-weight: bold;
500
484
  }
501
485
 
502
486
  .total .donnee {
503
- color: $gp-1;
504
- }
505
-
506
- .total h5 {
507
- color: $gp-1;
508
- border-color: $gp-1;
487
+ color: #b71515;
509
488
  }
510
489
 
511
490
  .dix .donnee {
512
- color: $gp-2;
513
- }
514
-
515
- .dix h5 {
516
- color: $gp-2;
517
- border-color: $gp-2;
491
+ color: #d71c19;
518
492
  }
519
493
 
520
494
  .cinq .donnee {
521
- color: $gp-3;
495
+ color: #de601e;
522
496
  }
523
497
 
524
- .cinq h5 {
525
- color: $gp-3;
526
- border-color: $gp-3;
527
- }
528
498
  .moyenne .donnee {
529
- color: $gs-1;
530
- }
531
-
532
- .moyenne h5 {
533
- color: $gs-1;
534
- border-color: $gs-1;
499
+ color: #cf3e39;
535
500
  }
536
501
  </style>
@@ -79,8 +79,40 @@
79
79
  puissance: number
80
80
  point?: L.CircleMarker
81
81
  }[] = $state([])
82
+ let pompiers: {
83
+ lat: number
84
+ lng: number
85
+ nom: string
86
+ telephone: string
87
+ }[] = $state([])
88
+ let pompierMarkers: L.Marker[] = []
82
89
  let total = $state(0)
83
90
 
91
+ function firebrigadeIcon() {
92
+ return leaflet!.divIcon({
93
+ html: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 75" width="40" height="50">
94
+ <path d="M30 73 C18 57 6 50 6 36 A24 24 0 1 1 54 36 C54 50 42 57 30 73Z" fill="#C53030"/>
95
+ <circle cx="30" cy="36" r="21" fill="white"/>
96
+ <rect x="18" y="27" width="26" height="2" rx="1" fill="#9B2C2C"/>
97
+ <line x1="24" y1="27" x2="24" y2="29" stroke="#9B2C2C" stroke-width="1.5"/>
98
+ <line x1="31" y1="27" x2="31" y2="29" stroke="#9B2C2C" stroke-width="1.5"/>
99
+ <line x1="38" y1="27" x2="38" y2="29" stroke="#9B2C2C" stroke-width="1.5"/>
100
+ <rect x="18" y="29" width="26" height="13" rx="2" fill="#C53030"/>
101
+ <rect x="11" y="31" width="10" height="11" rx="2" fill="#C53030"/>
102
+ <rect x="13" y="33" width="6" height="6" rx="1" fill="white" opacity="0.85"/>
103
+ <circle cx="18" cy="42" r="4" fill="#444"/>
104
+ <circle cx="18" cy="42" r="2" fill="white" opacity="0.6"/>
105
+ <circle cx="40" cy="42" r="4" fill="#444"/>
106
+ <circle cx="40" cy="42" r="2" fill="white" opacity="0.6"/>
107
+ <rect x="13" y="27" width="5" height="2.5" rx="1" fill="#FC8181"/>
108
+ </svg>`,
109
+ className: '',
110
+ iconSize: [40, 50],
111
+ iconAnchor: [20, 50],
112
+ popupAnchor: [0, -52],
113
+ })
114
+ }
115
+
84
116
  async function checkRayon(latlng: Grain.LatLng | null, rayon: number) {
85
117
  if (latlng) {
86
118
  console.log('checkRayon')
@@ -124,6 +156,46 @@
124
156
  }
125
157
  }
126
158
  })(),
159
+ (async () => {
160
+ console.log('Pompier')
161
+ for (let marker of pompierMarkers) {
162
+ if (marker && map) {
163
+ marker.removeFrom(map)
164
+ }
165
+ }
166
+ pompierMarkers = []
167
+ pompiers = []
168
+
169
+ let resp = await fetch(
170
+ `${srv}/api/grain/pompiers?lat=${latlng.lat}&lng=${latlng.lng}&rayon=10000`,
171
+ {
172
+ credentials: 'include',
173
+ }
174
+ )
175
+ console.log('Pompier', resp.status)
176
+ if (resp.status == 200) {
177
+ pompiers = await resp.json()
178
+ if (leaflet && map) {
179
+ for (let p of pompiers) {
180
+ let marker = leaflet.marker(p, {
181
+ icon: firebrigadeIcon(),
182
+ })
183
+ marker
184
+ .addTo(map)
185
+ .bindPopup(
186
+ `<b>${p.nom}</b>${p.telephone ? `<br/>Tél: ${p.telephone}` : ''}`
187
+ )
188
+ .on('mouseover', function () {
189
+ marker.openPopup()
190
+ })
191
+ .on('mouseout', function () {
192
+ marker.closePopup()
193
+ })
194
+ pompierMarkers.push(marker)
195
+ }
196
+ }
197
+ }
198
+ })(),
127
199
  ])
128
200
  }
129
201
  }
@@ -297,7 +297,7 @@
297
297
  </div>
298
298
  </div>
299
299
 
300
- <style lang="scss">
300
+ <style>
301
301
  .tcellt {
302
302
  border-bottom: 1px solid var(--color-primary);
303
303
  display: flex;
@@ -1,8 +1,7 @@
1
1
  <script lang="ts">
2
2
  import Simulation from './Simulation.svelte'
3
3
  const props = $props()
4
- let data = $state(props.data)
5
- // data.active = true
4
+ let data = $derived(props.data)
6
5
  </script>
7
6
 
8
7
  <Simulation bind:data />
package/vite.config.js CHANGED
@@ -4,16 +4,6 @@ import tailwindcss from '@tailwindcss/vite'
4
4
  /** @type {import('vite').UserConfig} */
5
5
  const config = {
6
6
  plugins: [tailwindcss(), sveltekit()],
7
- css: {
8
- preprocessorOptions: {
9
- scss: {
10
- additionalData(source, fp) {
11
- if (fp.endsWith('app.scss')) return source
12
- return '@import "/src/app.scss";' + source
13
- },
14
- },
15
- },
16
- },
17
7
  server: {
18
8
  host: true,
19
9
  allowedHosts: ['localhost', 'coturnix.fr'],
File without changes