@jjlmoya/utils-home 1.30.0 → 1.32.0
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.
- package/package.json +2 -1
- package/src/entries.ts +7 -1
- package/src/index.ts +1 -0
- package/src/tests/locale_completeness.test.ts +2 -2
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tool/lightingCalculator/bibliography.astro +36 -0
- package/src/tool/lightingCalculator/bibliography.ts +10 -0
- package/src/tool/lightingCalculator/component.astro +308 -0
- package/src/tool/lightingCalculator/draw.ts +247 -0
- package/src/tool/lightingCalculator/entry.ts +29 -0
- package/src/tool/lightingCalculator/how-many-lights-per-room.css +493 -0
- package/src/tool/lightingCalculator/i18n/de.ts +213 -0
- package/src/tool/lightingCalculator/i18n/en.ts +213 -0
- package/src/tool/lightingCalculator/i18n/es.ts +213 -0
- package/src/tool/lightingCalculator/i18n/fr.ts +213 -0
- package/src/tool/lightingCalculator/i18n/id.ts +213 -0
- package/src/tool/lightingCalculator/i18n/it.ts +213 -0
- package/src/tool/lightingCalculator/i18n/ja.ts +213 -0
- package/src/tool/lightingCalculator/i18n/ko.ts +213 -0
- package/src/tool/lightingCalculator/i18n/nl.ts +213 -0
- package/src/tool/lightingCalculator/i18n/pl.ts +213 -0
- package/src/tool/lightingCalculator/i18n/pt.ts +213 -0
- package/src/tool/lightingCalculator/i18n/ru.ts +213 -0
- package/src/tool/lightingCalculator/i18n/sv.ts +213 -0
- package/src/tool/lightingCalculator/i18n/tr.ts +213 -0
- package/src/tool/lightingCalculator/i18n/zh.ts +213 -0
- package/src/tool/lightingCalculator/index.ts +9 -0
- package/src/tool/lightingCalculator/logic.ts +119 -0
- package/src/tool/lightingCalculator/seo.astro +15 -0
- package/src/tool/lightingCalculator/state.ts +113 -0
- package/src/tool/lightingCalculator/ui.ts +48 -0
- package/src/tool/tileLayoutCalculator/bibliography.astro +14 -0
- package/src/tool/tileLayoutCalculator/bibliography.ts +10 -0
- package/src/tool/tileLayoutCalculator/component.astro +415 -0
- package/src/tool/tileLayoutCalculator/entry.ts +29 -0
- package/src/tool/tileLayoutCalculator/i18n/de.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/en.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/es.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/fr.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/id.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/it.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/ja.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/ko.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/nl.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/pl.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/pt.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/ru.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/sv.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/tr.ts +208 -0
- package/src/tool/tileLayoutCalculator/i18n/zh.ts +208 -0
- package/src/tool/tileLayoutCalculator/index.ts +9 -0
- package/src/tool/tileLayoutCalculator/logic.ts +55 -0
- package/src/tool/tileLayoutCalculator/seo.astro +15 -0
- package/src/tool/tileLayoutCalculator/tile-layout-calculator.css +404 -0
- package/src/tool/tileLayoutCalculator/ui.ts +37 -0
- package/src/tools.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jjlmoya/utils-home",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"@jjlmoya/utils-shared": "1.2.0",
|
|
45
45
|
"astro": "^6.1.2",
|
|
46
46
|
"astro-icon": "^1.1.0",
|
|
47
|
+
"jspdf": "^4.2.1",
|
|
47
48
|
"qrcode": "^1.5.4"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
package/src/entries.ts
CHANGED
|
@@ -24,6 +24,10 @@ export { deskErgonomics } from './tool/deskErgonomics/entry';
|
|
|
24
24
|
export type { DeskErgonomicsLocaleContent } from './tool/deskErgonomics/entry';
|
|
25
25
|
export { applianceCostCalculator } from './tool/applianceCostCalculator/entry';
|
|
26
26
|
export type { ApplianceCostCalculatorLocaleContent } from './tool/applianceCostCalculator/entry';
|
|
27
|
+
export { tileLayoutCalculator } from './tool/tileLayoutCalculator/entry';
|
|
28
|
+
export type { TileLayoutCalculatorLocaleContent } from './tool/tileLayoutCalculator/entry';
|
|
29
|
+
export { lightingCalculator } from './tool/lightingCalculator/entry';
|
|
30
|
+
export type { LightingCalculatorLocaleContent } from './tool/lightingCalculator/entry';
|
|
27
31
|
export { homeCategory } from './category';
|
|
28
32
|
import { dewPointCalculator } from './tool/dewPointCalculator/entry';
|
|
29
33
|
import { heatingComparator } from './tool/heatingComparator/entry';
|
|
@@ -38,4 +42,6 @@ import { wallPaintingCalculator } from './tool/wallPaintingCalculator/entry';
|
|
|
38
42
|
import { vampireDrawSimulator } from './tool/vampireDrawSimulator/entry';
|
|
39
43
|
import { deskErgonomics } from './tool/deskErgonomics/entry';
|
|
40
44
|
import { applianceCostCalculator } from './tool/applianceCostCalculator/entry';
|
|
41
|
-
|
|
45
|
+
import { tileLayoutCalculator } from './tool/tileLayoutCalculator/entry';
|
|
46
|
+
import { lightingCalculator } from './tool/lightingCalculator/entry';
|
|
47
|
+
export const ALL_ENTRIES = [dewPointCalculator, heatingComparator, ledSavingCalculator, projectorCalculator, qrGenerator, solarCalculator, tariffComparator, wifiRangeSimulator, acTonnageCalculator, wallPaintingCalculator, vampireDrawSimulator, deskErgonomics, applianceCostCalculator, tileLayoutCalculator, lightingCalculator];
|
package/src/index.ts
CHANGED
|
@@ -28,4 +28,5 @@ export { WALL_PAINTING_CALCULATOR_TOOL } from './tool/wallPaintingCalculator';
|
|
|
28
28
|
export { VAMPIRE_DRAW_SIMULATOR_TOOL } from './tool/vampireDrawSimulator';
|
|
29
29
|
export { DESK_ERGONOMICS_TOOL } from './tool/deskErgonomics';
|
|
30
30
|
export { APPLIANCE_COST_CALCULATOR_TOOL } from './tool/applianceCostCalculator';
|
|
31
|
+
export { TILE_LAYOUT_CALCULATOR_TOOL } from './tool/tileLayoutCalculator';
|
|
31
32
|
|
|
@@ -17,8 +17,8 @@ describe('Locale Completeness Validation', () => {
|
|
|
17
17
|
});
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
it('should have
|
|
21
|
-
expect(ALL_TOOLS.length).toBe(
|
|
20
|
+
it('should have 15 tools registered', () => {
|
|
21
|
+
expect(ALL_TOOLS.length).toBe(15);
|
|
22
22
|
});
|
|
23
23
|
});
|
|
24
24
|
|
|
@@ -4,8 +4,8 @@ import { homeCategory } from '../data';
|
|
|
4
4
|
|
|
5
5
|
describe('Tool Validation Suite', () => {
|
|
6
6
|
describe('Library Registration', () => {
|
|
7
|
-
it('should have
|
|
8
|
-
expect(ALL_TOOLS.length).toBe(
|
|
7
|
+
it('should have 15 tools in ALL_TOOLS', () => {
|
|
8
|
+
expect(ALL_TOOLS.length).toBe(15);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
it('homeCategory should be defined', () => {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { BibliographyEntry } from '../../types';
|
|
3
|
+
import { bibliography } from './bibliography';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
title?: string;
|
|
7
|
+
links?: BibliographyEntry[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { links = bibliography } = Astro.props;
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<ul class="lighting-bibliography">
|
|
14
|
+
{links.map((link) => (
|
|
15
|
+
<li>
|
|
16
|
+
<a href={link.url} target="_blank" rel="noopener noreferrer">
|
|
17
|
+
{link.name}
|
|
18
|
+
</a>
|
|
19
|
+
</li>
|
|
20
|
+
))}
|
|
21
|
+
</ul>
|
|
22
|
+
|
|
23
|
+
<style>
|
|
24
|
+
.lighting-bibliography {
|
|
25
|
+
list-style: none;
|
|
26
|
+
padding: 0;
|
|
27
|
+
margin: 0;
|
|
28
|
+
}
|
|
29
|
+
.lighting-bibliography li {
|
|
30
|
+
margin-bottom: 0.5rem;
|
|
31
|
+
}
|
|
32
|
+
.lighting-bibliography a {
|
|
33
|
+
color: var(--text-primary);
|
|
34
|
+
text-decoration: underline;
|
|
35
|
+
}
|
|
36
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const bibliography = [
|
|
2
|
+
{
|
|
3
|
+
name: 'IES Lighting Handbook 10th Edition',
|
|
4
|
+
url: 'https://www.ies.org/publications/ies-lighting-handbook/',
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
name: 'EN 12464-1:2021 Light and Lighting - Indoor Work Places',
|
|
8
|
+
url: 'https://standards.cencenelec.eu/',
|
|
9
|
+
},
|
|
10
|
+
];
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { LightingCalculatorUI } from './ui';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
ui?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { ui = {} } = Astro.props;
|
|
9
|
+
const lUI = ui as LightingCalculatorUI;
|
|
10
|
+
|
|
11
|
+
const INIT_R_W = 4, INIT_R_L = 5, INIT_H = 2.7, INIT_W = 9, INIT_F = 6;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<div class="lc-wrap">
|
|
15
|
+
<div class="lc-card">
|
|
16
|
+
<div class="lc-head">
|
|
17
|
+
<span class="lc-title">{lUI.sectionTitle}</span>
|
|
18
|
+
<div class="lc-unit-toggle">
|
|
19
|
+
<button class="lc-unit-btn lc-unit-active" data-unit="metric">{lUI.btnMetric}</button>
|
|
20
|
+
<button class="lc-unit-btn" data-unit="imperial">{lUI.btnImperial}</button>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="lc-row">
|
|
24
|
+
<div class="lc-input-group">
|
|
25
|
+
<label class="lc-input-label" for="lc-w">{lUI.labelRoomWidth}</label>
|
|
26
|
+
<div class="lc-input-wrap">
|
|
27
|
+
<input id="lc-w" type="number" value={INIT_R_W} min="0.1" max="50" step="0.1" class="lc-input" />
|
|
28
|
+
<span class="lc-input-unit" id="lc-w-u">{lUI.unitMetricRoom}</span>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="lc-input-group">
|
|
32
|
+
<label class="lc-input-label" for="lc-l">{lUI.labelRoomLength}</label>
|
|
33
|
+
<div class="lc-input-wrap">
|
|
34
|
+
<input id="lc-l" type="number" value={INIT_R_L} min="0.1" max="50" step="0.1" class="lc-input" />
|
|
35
|
+
<span class="lc-input-unit" id="lc-l-u">{lUI.unitMetricRoom}</span>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="lc-input-group">
|
|
39
|
+
<label class="lc-input-label" for="lc-h">{lUI.labelHeight}</label>
|
|
40
|
+
<div class="lc-input-wrap">
|
|
41
|
+
<input id="lc-h" type="number" value={INIT_H} min="1.5" max="10" step="0.1" class="lc-input" />
|
|
42
|
+
<span class="lc-input-unit" id="lc-h-u">{lUI.unitHeight}</span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
<div class="lc-row">
|
|
47
|
+
<div class="lc-chips">
|
|
48
|
+
<button class="lc-chip lc-chip-active" data-room="living">
|
|
49
|
+
<svg class="lc-chip-icon" viewBox="0 0 24 24"><path d="M7 6h10v3h-2V7H9v2H7V6zm-2 5h14v8h-2v-6H9v6H7v-8z"/></svg>
|
|
50
|
+
<span>{lUI.btnLiving}</span>
|
|
51
|
+
</button>
|
|
52
|
+
<button class="lc-chip" data-room="kitchen">
|
|
53
|
+
<svg class="lc-chip-icon" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>
|
|
54
|
+
<span>{lUI.btnKitchen}</span>
|
|
55
|
+
</button>
|
|
56
|
+
<button class="lc-chip" data-room="bedroom">
|
|
57
|
+
<svg class="lc-chip-icon" viewBox="0 0 24 24"><path d="M7 14c1.66 0 3-1.34 3-3S8.66 8 7 8s-3 1.34-3 3 1.34 3 3 3zm12-3c0 1.66 1.34 3 3 3s3-1.34 3-3-1.34-3-3-3-3 1.34-3 3zm-3 4H7c-2.21 0-4 1.79-4 4v2h16v-2c0-2.21-1.79-4-4-4z"/></svg>
|
|
58
|
+
<span>{lUI.btnBedroom}</span>
|
|
59
|
+
</button>
|
|
60
|
+
<button class="lc-chip" data-room="bathroom">
|
|
61
|
+
<svg class="lc-chip-icon" viewBox="0 0 24 24"><path d="M7 7c0-2.21 1.79-4 4-4s4 1.79 4 4v3H7V7zm12 4H5v8c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-8z"/></svg>
|
|
62
|
+
<span>{lUI.btnBathroom}</span>
|
|
63
|
+
</button>
|
|
64
|
+
<button class="lc-chip" data-room="office">
|
|
65
|
+
<svg class="lc-chip-icon" viewBox="0 0 24 24"><path d="M20 18c1.1 0 1.99-.9 1.99-2L22 5c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v11c0 1.1.9 2 2 2H0c0 1.1.9 2 2 2h20c1.1 0 2-.9 2-2h-4zM4 5h16v11H4V5z"/></svg>
|
|
66
|
+
<span>{lUI.btnOffice}</span>
|
|
67
|
+
</button>
|
|
68
|
+
<button class="lc-chip" data-room="hallway">
|
|
69
|
+
<svg class="lc-chip-icon" viewBox="0 0 24 24"><path d="M19 19V5c0-1.1-.9-2-2-2H7c-1.1 0-2 .9-2 2v14H3v2h18v-2h-2zm-2 0H7V5h10v14z"/></svg>
|
|
70
|
+
<span>{lUI.btnHallway}</span>
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="lc-row">
|
|
75
|
+
<div class="lc-input-group">
|
|
76
|
+
<label class="lc-input-label">{lUI.labelAmbient}</label>
|
|
77
|
+
<div class="lc-bulb-bar">
|
|
78
|
+
<button class="lc-ambient-btn" data-ambient="0.7">{lUI.btnAmbientCozy}</button>
|
|
79
|
+
<button class="lc-ambient-btn lc-ambient-active" data-ambient="1">{lUI.btnAmbientNormal}</button>
|
|
80
|
+
<button class="lc-ambient-btn" data-ambient="1.3">{lUI.btnAmbientBright}</button>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="lc-input-group lc-grow">
|
|
84
|
+
<label class="lc-input-label">{lUI.labelBulbType}</label>
|
|
85
|
+
<div class="lc-bulb-bar">
|
|
86
|
+
<button class="lc-bulb lc-bulb-active" data-bulb="led">
|
|
87
|
+
<span class="lc-bulb-dot" style="background:#22c55e;box-shadow:0 0 8px #22c55e"></span>
|
|
88
|
+
<span>{lUI.btnBulbLED}</span>
|
|
89
|
+
</button>
|
|
90
|
+
<button class="lc-bulb" data-bulb="cfl">
|
|
91
|
+
<span class="lc-bulb-dot" style="background:#f59e0b;box-shadow:0 0 8px #f59e0b"></span>
|
|
92
|
+
<span>{lUI.btnBulbCFL}</span>
|
|
93
|
+
</button>
|
|
94
|
+
<button class="lc-bulb" data-bulb="halogen">
|
|
95
|
+
<span class="lc-bulb-dot" style="background:#f97316;box-shadow:0 0 8px #f97316"></span>
|
|
96
|
+
<span>{lUI.btnBulbHalogen}</span>
|
|
97
|
+
</button>
|
|
98
|
+
<button class="lc-bulb" data-bulb="incandescent">
|
|
99
|
+
<span class="lc-bulb-dot" style="background:#ef4444;box-shadow:0 0 8px #ef4444"></span>
|
|
100
|
+
<span>{lUI.btnBulbIncandescent}</span>
|
|
101
|
+
</button>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
<div class="lc-plan-wrap" id="lc-plan-wrap">
|
|
106
|
+
<svg class="lc-plan" viewBox="0 0 300 200" id="lc-plan"></svg>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="lc-dial-row">
|
|
109
|
+
<div class="lc-dial-wrap">
|
|
110
|
+
<svg class="lc-dial" viewBox="0 0 120 70" id="lc-dial-lux"></svg>
|
|
111
|
+
<span class="lc-dial-label">{lUI.labelCurrentLux}</span>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
<div class="lc-status" id="lc-status">
|
|
115
|
+
<span class="lc-status-dot" id="lc-status-dot"></span>
|
|
116
|
+
<div class="lc-status-body">
|
|
117
|
+
<span class="lc-status-text" id="lc-status-text">{lUI.statusOptimal}</span>
|
|
118
|
+
<span class="lc-status-desc" id="lc-status-desc"></span>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
<div class="lc-victory" id="lc-victory">
|
|
122
|
+
<div class="lc-victory-title">{lUI.labelSummary}</div>
|
|
123
|
+
<div class="lc-victory-row">
|
|
124
|
+
<span class="lc-victory-label">{lUI.labelTotalLumens}</span>
|
|
125
|
+
<span class="lc-victory-value" id="lc-v-lumens">0</span>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="lc-victory-row">
|
|
128
|
+
<span class="lc-victory-label">{lUI.labelSuggestedSetup}</span>
|
|
129
|
+
<span class="lc-victory-value" id="lc-v-setup">-</span>
|
|
130
|
+
</div>
|
|
131
|
+
<button class="lc-export-btn" id="lc-export">{lUI.btnExport}</button>
|
|
132
|
+
</div>
|
|
133
|
+
<div class="lc-manual-toggle" id="lc-manual-toggle">
|
|
134
|
+
<svg viewBox="0 0 24 24"><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></svg>
|
|
135
|
+
{lUI.labelManualAdjust}
|
|
136
|
+
</div>
|
|
137
|
+
<div class="lc-manual" id="lc-manual">
|
|
138
|
+
<div class="lc-row">
|
|
139
|
+
<div class="lc-input-group">
|
|
140
|
+
<label class="lc-input-label" for="lc-bw">{lUI.labelBulbWatt}</label>
|
|
141
|
+
<div class="lc-input-wrap">
|
|
142
|
+
<input id="lc-bw" type="number" value={INIT_W} min="1" max="200" step="1" class="lc-input" />
|
|
143
|
+
<span class="lc-input-unit">{lUI.unitWatt}</span>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
<div class="lc-input-group">
|
|
147
|
+
<label class="lc-input-label" for="lc-f">{lUI.labelFixtures}</label>
|
|
148
|
+
<div class="lc-input-wrap">
|
|
149
|
+
<input id="lc-f" type="number" value={INIT_F} min="1" max="50" step="1" class="lc-input" />
|
|
150
|
+
<span class="lc-input-unit">{lUI.unitBulbs}</span>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<script>
|
|
159
|
+
import { loadState, saveState, restoreInputs, runCalc, updateUnitLabels, convertValue } from './state';
|
|
160
|
+
import { drawPlan, drawDial, generatePDF } from './draw';
|
|
161
|
+
import type { State } from './state';
|
|
162
|
+
import type { LightingResult } from './logic';
|
|
163
|
+
|
|
164
|
+
const st: State = loadState();
|
|
165
|
+
|
|
166
|
+
function el(id: string) { return document.getElementById(id); }
|
|
167
|
+
function setTxt(id: string, v: string) { const e = el(id); if (e) e.textContent = v; }
|
|
168
|
+
function getNum(id: string): number { const e = el(id) as HTMLInputElement | null; return e ? parseFloat(e.value) || 0 : 0; }
|
|
169
|
+
function setVal(id: string, v: string) { const e = el(id) as HTMLInputElement | null; if (e) e.value = v; }
|
|
170
|
+
|
|
171
|
+
function updateStatus(r: LightingResult) {
|
|
172
|
+
const statusEl = el('lc-status');
|
|
173
|
+
const stText = el('lc-status-text');
|
|
174
|
+
const stDesc = el('lc-status-desc');
|
|
175
|
+
const planWrap = el('lc-plan-wrap');
|
|
176
|
+
if (statusEl) statusEl.className = 'lc-status ' + r.status;
|
|
177
|
+
if (planWrap) planWrap.className = 'lc-plan-wrap ' + r.status;
|
|
178
|
+
if (stText) {
|
|
179
|
+
if (r.status === 'optimal') stText.textContent = 'Perfect';
|
|
180
|
+
else if (r.status === 'insufficient') stText.textContent = 'Too Dim';
|
|
181
|
+
else stText.textContent = 'Too Bright';
|
|
182
|
+
}
|
|
183
|
+
if (stDesc) stDesc.textContent = r.sensoryContext;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function updateVictory(r: LightingResult) {
|
|
187
|
+
setTxt('lc-v-lumens', String(r.requiredLumens));
|
|
188
|
+
setTxt('lc-v-setup', r.suggestedProducts);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function render() {
|
|
192
|
+
const r = runCalc(st, getNum);
|
|
193
|
+
const f = st.unitSys === 'metric' ? 1 : 0.3048;
|
|
194
|
+
const w = getNum('lc-w') * f;
|
|
195
|
+
const l = getNum('lc-l') * f;
|
|
196
|
+
const plan = el('lc-plan') as SVGSVGElement | null;
|
|
197
|
+
if (plan) drawPlan(plan, { widthM: w, lengthM: l, optimalBulbs: r.optimalBulbs, luxRatio: r.luxRatio, ambiance: st.luxMultiplier, status: r.status });
|
|
198
|
+
const maxDial = Math.max(r.targetLux, r.currentLux) * 1.2;
|
|
199
|
+
const dialLux = el('lc-dial-lux') as SVGSVGElement | null;
|
|
200
|
+
if (dialLux) drawDial(dialLux, { value: r.currentLux, target: r.targetLux, max: maxDial, label: 'LUX' });
|
|
201
|
+
updateStatus(r);
|
|
202
|
+
updateVictory(r);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function persist() { saveState(st, getNum); }
|
|
206
|
+
|
|
207
|
+
function applyUnit(s: 'metric' | 'imperial') {
|
|
208
|
+
st.unitSys = s;
|
|
209
|
+
persist();
|
|
210
|
+
document.querySelectorAll('.lc-unit-btn').forEach((b) => b.classList.toggle('lc-unit-active', (b as HTMLElement).dataset.unit === s));
|
|
211
|
+
const toMetric = s === 'metric';
|
|
212
|
+
convertValue('lc-w', getNum, setVal, toMetric);
|
|
213
|
+
convertValue('lc-l', getNum, setVal, toMetric);
|
|
214
|
+
convertValue('lc-h', getNum, setVal, toMetric);
|
|
215
|
+
updateUnitLabels(st.unitSys, setTxt);
|
|
216
|
+
render();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function setRoom(type: string) {
|
|
220
|
+
st.roomType = type;
|
|
221
|
+
persist();
|
|
222
|
+
document.querySelectorAll('.lc-chip').forEach((b) => b.classList.toggle('lc-chip-active', (b as HTMLElement).dataset.room === type));
|
|
223
|
+
render();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function setBulb(type: string) {
|
|
227
|
+
st.bulbType = type;
|
|
228
|
+
persist();
|
|
229
|
+
document.querySelectorAll('.lc-bulb').forEach((b) => b.classList.toggle('lc-bulb-active', (b as HTMLElement).dataset.bulb === type));
|
|
230
|
+
render();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function setAmbient(m: string) {
|
|
234
|
+
st.luxMultiplier = parseFloat(m);
|
|
235
|
+
persist();
|
|
236
|
+
document.querySelectorAll('.lc-ambient-btn').forEach((b) => b.classList.toggle('lc-ambient-active', (b as HTMLElement).dataset.ambient === m));
|
|
237
|
+
render();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function init() {
|
|
241
|
+
restoreInputs(getNum, setVal);
|
|
242
|
+
updateUnitLabels(st.unitSys, setTxt);
|
|
243
|
+
document.querySelectorAll('.lc-unit-btn').forEach((b) => b.classList.toggle('lc-unit-active', (b as HTMLElement).dataset.unit === st.unitSys));
|
|
244
|
+
document.querySelectorAll('.lc-chip').forEach((b) => b.classList.toggle('lc-chip-active', (b as HTMLElement).dataset.room === st.roomType));
|
|
245
|
+
document.querySelectorAll('.lc-bulb').forEach((b) => b.classList.toggle('lc-bulb-active', (b as HTMLElement).dataset.bulb === st.bulbType));
|
|
246
|
+
document.querySelectorAll('.lc-ambient-btn').forEach((b) => b.classList.toggle('lc-ambient-active', (b as HTMLElement).dataset.ambient === String(st.luxMultiplier)));
|
|
247
|
+
const fInput = el('lc-f') as HTMLInputElement | null;
|
|
248
|
+
if (fInput && !fInput.value) {
|
|
249
|
+
const calc = runCalc(st, getNum);
|
|
250
|
+
setVal('lc-f', String(calc.optimalBulbs));
|
|
251
|
+
}
|
|
252
|
+
document.querySelectorAll('.lc-unit-btn').forEach((btn) => {
|
|
253
|
+
btn.addEventListener('click', () => {
|
|
254
|
+
const u = (btn as HTMLElement).dataset.unit as 'metric' | 'imperial';
|
|
255
|
+
if (u) applyUnit(u);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
document.querySelectorAll('.lc-chip').forEach((btn) => {
|
|
259
|
+
btn.addEventListener('click', () => {
|
|
260
|
+
const t = (btn as HTMLElement).dataset.room || 'living';
|
|
261
|
+
setRoom(t);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
document.querySelectorAll('.lc-bulb').forEach((btn) => {
|
|
265
|
+
btn.addEventListener('click', () => {
|
|
266
|
+
const t = (btn as HTMLElement).dataset.bulb || 'led';
|
|
267
|
+
setBulb(t);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
document.querySelectorAll('.lc-ambient-btn').forEach((btn) => {
|
|
271
|
+
btn.addEventListener('click', () => {
|
|
272
|
+
const m = (btn as HTMLElement).dataset.ambient || '1';
|
|
273
|
+
setAmbient(m);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
['lc-w', 'lc-l', 'lc-h', 'lc-bw', 'lc-f'].forEach((id) => {
|
|
277
|
+
const e = el(id);
|
|
278
|
+
if (e) e.addEventListener('input', () => { persist(); render(); });
|
|
279
|
+
});
|
|
280
|
+
const manualToggle = el('lc-manual-toggle');
|
|
281
|
+
const manual = el('lc-manual');
|
|
282
|
+
if (manualToggle && manual) {
|
|
283
|
+
manualToggle.addEventListener('click', () => {
|
|
284
|
+
manual.classList.toggle('lc-manual-open');
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
const exportBtn = el('lc-export');
|
|
288
|
+
if (exportBtn) {
|
|
289
|
+
exportBtn.addEventListener('click', () => {
|
|
290
|
+
const r = runCalc(st, getNum);
|
|
291
|
+
const unitLabel = st.unitSys === 'metric' ? 'm' : 'ft';
|
|
292
|
+
generatePDF({
|
|
293
|
+
roomType: st.roomType,
|
|
294
|
+
width: getNum('lc-w'),
|
|
295
|
+
length: getNum('lc-l'),
|
|
296
|
+
height: getNum('lc-h'),
|
|
297
|
+
r,
|
|
298
|
+
unitSys: st.unitSys,
|
|
299
|
+
unitLabel,
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
render();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
document.addEventListener('astro:page-load', init);
|
|
307
|
+
init();
|
|
308
|
+
</script>
|