diff --git a/index.html b/index.html index ba14117..b172a0e 100644 --- a/index.html +++ b/index.html @@ -45,12 +45,21 @@

Showcase your journey

+
@@ -79,6 +88,19 @@

Showcase your journey

+ diff --git a/src/images/ImageGenerator.ts b/src/images/ImageGenerator.ts index b0e07a4..6fe9d4e 100644 --- a/src/images/ImageGenerator.ts +++ b/src/images/ImageGenerator.ts @@ -11,6 +11,11 @@ const FLAG_HEIGHT = 30 * DPI; const FLAG_WIDTH = 40 * DPI; const FLAG_GAP = 8 * DPI; +export type RenderParams = { + flags: HTMLImageElement[]; + background: string; +} + export class ImageGenerator { constructor( private canvas: CanvasManager, @@ -41,10 +46,10 @@ export class ImageGenerator { this.image.classList.add(READY_CLASS_NAME); } - async render(flags: HTMLImageElement[]) { + async render({ flags, background }: RenderParams) { this.canvas .setSize(INITIAL_WIDTH, INITIAL_HEIGHT) - .fill(INITIAL_COLOR); + .fill(background); const centerX = this.canvas.width / 2; const centerY = this.canvas.height / 2; diff --git a/src/main.ts b/src/main.ts index 5310357..e340c50 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,11 +1,13 @@ import { countries, getFlagSrc } from "./flags"; import { CanvasManager, ImageGenerator } from "./images"; import { Landing } from "./landing"; -import { CountrySelector, Settings } from "./settings"; +import { ColorSelector, CountrySelector, Settings } from "./settings"; import { getFullfiled, loadImage, querySelectorSafe } from "./shared/utils"; import { Sidebar } from "./sidebar"; import { StateManager } from "./state"; +import type { SettingsData } from "./settings"; + import "./style.css"; const state = new StateManager(); @@ -25,30 +27,36 @@ const countrySelector = new CountrySelector( querySelectorSafe("#country"), ); +const colorSelector = new ColorSelector( + querySelectorSafe(".colors-list"), + querySelectorSafe("#color"), +); + const settings = new Settings(querySelectorSafe("form")); const manager = new CanvasManager(querySelectorSafe(".canvas")); const generator = new ImageGenerator(manager, querySelectorSafe(".device-screen")); -async function draw(codes: string[]) { +async function draw({ countries, background }: SettingsData) { const flags = await getFullfiled( - codes.map(code => loadImage(getFlagSrc(code))) + countries.map(code => loadImage(getFlagSrc(code))) ); - generator.render(flags); + generator.render({ flags, background }); } function main() { const codes = state.getCodes(); countrySelector.initialize(countries); + colorSelector.initialize(); settings.initialize({ countries: codes }); generator.initialize(); - draw(codes); + draw(settings.getData()); - settings.onChange(({ countries }) => { - state.writeCodes(countries); + settings.onChange(data => { + state.writeCodes(data.countries); - return draw(countries); + return draw(data); }); sidebar.initialize(); diff --git a/src/settings/ColorSelector.css b/src/settings/ColorSelector.css new file mode 100644 index 0000000..87605f9 --- /dev/null +++ b/src/settings/ColorSelector.css @@ -0,0 +1,38 @@ +.colors-list { + margin: 0; + padding: 0; + list-style-type: none; +} + +.color-radio { + display: none; +} + +.color-item { + margin: 0 0 4px; +} + +.color-label { + display: flex; + padding: 6px 8px; + border-radius: 6px; + display: flex; + line-height: 20px; +} + +.color-flag { + display: inline-block; + width: 24px; + height: 18px; + margin-block-start: 1px; + margin-inline-end: 12px; + outline: 1px solid rgba(255,255,255,0.5); +} + +input:checked + .color-label { + background-color: #94a3b8; +} + +input:checked + .color-label .color-flag { + outline: none; +} diff --git a/src/settings/ColorSelector.ts b/src/settings/ColorSelector.ts new file mode 100644 index 0000000..f2be672 --- /dev/null +++ b/src/settings/ColorSelector.ts @@ -0,0 +1,53 @@ +import { querySelectorSafe } from "../shared/utils"; + +import "./ColorSelector.css"; + +type Color = { + name: string; + code: string; +} + +const colors: Color[] = [ + { + name: "Olive", + code: "#5f6a5e", + }, + { + name: "Stone", + code: "#a8a29e", + }, + { + name: "Silver", + code: "#f1f5f9", + }, + { + name: "Sand", + code: "#eed9c4", + }, + { + name: "Rose", + code: "#ecc5c0", + }, +]; + +export class ColorSelector { + constructor( + private container: HTMLElement, + private template: HTMLTemplateElement, + ) { } + + initialize() { + colors.forEach(color => { + const clone = this.template.content.cloneNode(true) as HTMLLIElement; + const id = color.code.replace("#", ""); + + querySelectorSafe("input", clone).value = color.code; + querySelectorSafe("input", clone).id = id; + querySelectorSafe("label", clone).setAttribute("for", id); + querySelectorSafe(".color-name", clone).innerText = color.name; + querySelectorSafe(".color-flag", clone).style.backgroundColor = color.code; + + this.container.appendChild(clone); + }); + } +} diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index a96b913..30becf0 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -1,7 +1,8 @@ -import { isCheckable, toArrayOfStrings } from "../shared/utils"; +import { isCheckable, toArrayOfStrings, toString } from "../shared/utils"; -type SettingsData = { +export type SettingsData = { countries: string[]; + background: string; } type SettingsListener = (data: SettingsData) => void; @@ -23,6 +24,12 @@ export class Settings { } } } + + const firstBackgroundColor = this.form.querySelector("input[name=background]"); + + if (firstBackgroundColor && isCheckable(firstBackgroundColor)) { + firstBackgroundColor.checked = true; + } } onChange(callback: SettingsListener) { @@ -34,9 +41,11 @@ export class Settings { getData(): SettingsData { const data = new FormData(this.form); const countries = toArrayOfStrings(data.getAll("country")); + const background = toString(data.get("background")); return { - countries: countries, + countries, + background, }; } } diff --git a/src/settings/index.ts b/src/settings/index.ts index 03bc68b..9972125 100644 --- a/src/settings/index.ts +++ b/src/settings/index.ts @@ -1,2 +1,3 @@ +export { ColorSelector } from "./ColorSelector"; export { CountrySelector } from "./CountrySelector"; -export { Settings } from "./Settings"; +export { Settings, type SettingsData } from "./Settings"; diff --git a/src/shared/utils.ts b/src/shared/utils.ts index 0d62175..0b21826 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -8,6 +8,14 @@ export function querySelectorSafe(selector: string, return element; } +export function toString(data: FormDataEntryValue | null): string { + if (typeof data !== "string") { + return ""; + } + + return data; +} + export function toArrayOfStrings(data: FormDataEntryValue[]): string[] { if (!data) { return [];