Add dedicated Faktiska map production workflow
This commit is contained in:
@@ -10,11 +10,11 @@ import { CityData, drawOnMap } from "./canvasDraw";
|
||||
import { IconInputs } from "../weatherIcons/IconInputs";
|
||||
import { download } from '../../helpers/download'
|
||||
|
||||
export const MapView: Component<{ type: MapResolution, data: () => ResultKeyVal[] }> = ({ type, data }) => {
|
||||
export const MapView: Component<{ type: MapResolution, data: () => ResultKeyVal[], mode?: "temperature" | "faktiska" }> = ({ type, data, mode = "temperature" }) => {
|
||||
const [getCanvas, setCanvas] = createSignal<HTMLCanvasElement>();
|
||||
const [getImg, setImg] = createSignal(new Image());
|
||||
const weatherIconsSingal = createSignal<{[key: string]: string;}>({});
|
||||
const [getWeatherIcons] = weatherIconsSingal;
|
||||
const weatherIconsSignal = createSignal<{[key: string]: string;}>({});
|
||||
const [getWeatherIcons] = weatherIconsSignal;
|
||||
const [getTitle, setTitle] = createSignal("");
|
||||
const [getSource, setSource] = createSignal("");
|
||||
|
||||
@@ -90,15 +90,16 @@ export const MapView: Component<{ type: MapResolution, data: () => ResultKeyVal[
|
||||
return (
|
||||
<div class="mapWorkspace">
|
||||
<div class="mapToolbar"><div><strong>Map preview</strong><span>{props.width} × {props.height} px export</span></div><button class="primary" onClick={downloadPng}>Download PNG</button></div>
|
||||
<details class="broadcastControls">
|
||||
<details class="broadcastControls" open>
|
||||
<summary><span><strong>Broadcast overlay controls</strong><small>Optional manual wind and weather-symbol overrides</small></span></summary>
|
||||
<p class="controlHelp">These settings do not change the queried city values. Use them only when preparing a finished broadcast graphic.</p>
|
||||
<div class="overlayFields">
|
||||
<label><span>Title</span><input type="text" placeholder="19. APRĪĻA GAISA TEMPERATŪRAS REKORDI" value={getTitle()} onInput={e => setTitle(e.target.value)} /></label>
|
||||
<label><span>Source</span><input type="text" placeholder="LVĢMC" value={getSource()} onInput={e => setSource(e.target.value)} /></label>
|
||||
</div>
|
||||
<div class="grid-1-2">
|
||||
<div>
|
||||
<div class="mapControlSections">
|
||||
<section class="valueControls">
|
||||
<strong>Value and wind settings</strong>
|
||||
<div>
|
||||
<label>
|
||||
<input
|
||||
@@ -110,8 +111,8 @@ export const MapView: Component<{ type: MapResolution, data: () => ResultKeyVal[
|
||||
</label>
|
||||
</div>
|
||||
{ props.showWind && <WindInputs signals={windSignals} /> }
|
||||
</div>
|
||||
<div><IconInputs weatherIconsSingal={weatherIconsSingal} /></div>
|
||||
</section>
|
||||
{mode === "faktiska" && <IconInputs cities={data().map(([city]) => city)} weatherIconsSignal={weatherIconsSignal} />}
|
||||
</div>
|
||||
</details>
|
||||
<div class="canvasFrame">
|
||||
|
||||
@@ -1,48 +1,17 @@
|
||||
import { Component, Signal } from "solid-js";
|
||||
import { weatherIconCities, weatherIcons } from "./iconConsts";
|
||||
|
||||
import { Component, createSignal, For, Show, Signal } from "solid-js";
|
||||
import { weatherIcons } from "./iconConsts";
|
||||
import "../../css/weatherIcons.css";
|
||||
|
||||
export const IconInputs: Component<{ weatherIconsSingal: Signal<{[key: string]: string;}>; }> = ({
|
||||
weatherIconsSingal: [getWeatherIcons, setWeatherIcons]
|
||||
}) => {
|
||||
export const IconInputs: Component<{cities: string[]; weatherIconsSignal: Signal<Record<string, string>>}> = (props) => {
|
||||
const [icons, setIcons] = props.weatherIconsSignal;
|
||||
const [selected, setSelected] = createSignal(weatherIcons[0]);
|
||||
const assign = (city: string) => setIcons({...icons(), [city]: selected()});
|
||||
const clear = (city: string) => { const next = {...icons()}; delete next[city]; setIcons(next); };
|
||||
const applyAll = () => setIcons(Object.fromEntries(props.cities.map(city => [city, selected()])));
|
||||
|
||||
function onIconChange(city: string, icon: string) {
|
||||
const weatherIcons = { ...getWeatherIcons() };
|
||||
weatherIcons[city] = icon;
|
||||
if (icon === "") delete weatherIcons[city];
|
||||
|
||||
setWeatherIcons(weatherIcons);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<strong>Weather symbols</strong><p class="fieldHint">Click a symbol to copy it, then paste it into a city field below.</p>
|
||||
{ weatherIcons.map(icon =>
|
||||
<span class="weatherIconButton" onClick={() => copyToClipboard(icon)}>{ icon }</span>)
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
{ weatherIconCities.map(city =>
|
||||
<div style="float: left;">
|
||||
{city}:
|
||||
|
||||
<input
|
||||
type="text"
|
||||
class="weatherIconInput"
|
||||
size="1"
|
||||
maxlength="1"
|
||||
onInput={e => onIconChange(city, e.target.value)}
|
||||
/>
|
||||
|
||||
</div>)
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function copyToClipboard(icon: string) {
|
||||
navigator.clipboard.writeText(icon);
|
||||
}
|
||||
return <section class="symbolEditor">
|
||||
<div class="symbolEditorHeading"><div><strong>Weather symbols</strong><p class="fieldHint">Select a font symbol, apply it to all cities, then change the exceptions.</p></div><button type="button" onClick={applyAll}>Apply selected to all</button></div>
|
||||
<div class="symbolPalette" role="listbox" aria-label="Weather symbols"><For each={weatherIcons}>{icon => <button type="button" class="weatherIconButton" classList={{selected: selected() === icon}} onClick={() => setSelected(icon)}>{icon}</button>}</For></div>
|
||||
<div class="citySymbols"><For each={props.cities}>{city => <div class="citySymbolRow"><span>{city}</span><button type="button" class="assignedSymbol" onClick={() => assign(city)} title="Assign selected symbol"><Show when={icons()[city]} fallback="Assign">{icons()[city]}</Show></button><button type="button" class="clearSymbol" disabled={!icons()[city]} onClick={() => clear(city)}>Clear</button></div>}</For></div>
|
||||
</section>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user