Skip to content

Commit

Permalink
Add mobile brand picker
Browse files Browse the repository at this point in the history
Add mobile brand picker
  • Loading branch information
pkong-ds authored May 28, 2024
2 parents 895a971 + cd68037 commit f35a9e9
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 98 deletions.
3 changes: 3 additions & 0 deletions public/Images/chevron.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions public/scripts/device.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,18 @@ function handleClickBrandLabelBtn(e, viewModel) {
const brand = e.target.dataset.brandName;
viewModel.selectedBrand = brand;
}
function handleSelectBrandOption(selectParent, viewModel) {
const brand = selectParent.value;
viewModel.selectedBrand = brand;
}

function main() {
const deviceGrids = document.querySelectorAll(".device-grid");
const brands = document.querySelectorAll(".device-brand-list__item-button");
const brandSelect = document.querySelector("#device-brand-select");
const brandSelectOptions = document.querySelectorAll(
".device-brand-select__option",
);

const viewModel = new RootViewModel(
window.deviceList,
Expand Down Expand Up @@ -136,6 +144,7 @@ function main() {
),
];
targetBrandSections.forEach((n) => n.classList.remove("d-none"));
brandSelect.value = selectedBrand;
},
);

Expand All @@ -149,4 +158,8 @@ function main() {
handleClickBrandLabelBtn(e, viewModel),
);
});

brandSelect.addEventListener("change", () =>
handleSelectBrandOption(brandSelect, viewModel),
);
}
53 changes: 36 additions & 17 deletions src/pages/type/[type].astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import BaseLayout from "../../layouts/BaseLayout.astro";
import "/src/styles/device.css";
import { DEVICE_MANAGER } from "../../scripts/deviceManager";
import type { ModelThumbnail } from "../../scripts/model";
import type { BrandValue, ModelThumbnail } from "../../scripts/model";
import { BrandEnum, DeviceTypeEnum } from "../../scripts/parse";
export async function getStaticPaths() {
Expand All @@ -23,14 +23,16 @@ const thumbnailList: ModelThumbnail[] =
DEVICE_MANAGER.getModelThumbnailListByType(deviceType);
const brandThumbnailList: Partial<Record<BrandEnum, ModelThumbnail[]>> =
DEVICE_MANAGER.getBrandModelThumbnailList(deviceType);
const brandValues: Partial<Record<BrandEnum, BrandValue>> =
DEVICE_MANAGER.getBrandValues();
const nonEmptyBrands: BrandEnum[] = Object.keys(brandThumbnailList)
.filter((b) => {
const brand = BrandEnum.parse(b);
const thumbnails: ModelThumbnail[] | undefined = brandThumbnailList[brand];
return thumbnails != null && thumbnails.length > 0;
})
.map((b) => BrandEnum.parse(b));
const brandList: string[] = ["all", ...nonEmptyBrands];
const brandList: Array<BrandEnum | "all"> = ["all", ...nonEmptyBrands];
---

<BaseLayout>
Expand Down Expand Up @@ -134,23 +136,40 @@ const brandList: string[] = ["all", ...nonEmptyBrands];
</a>
</li>
</ul>
<ul class="device-brand-list">
{
brandList.map((b: string) => (
<li class="device-brand-list__item">
<button
class={`device-brand-list__item-button ${
b === "all" ? "device-brand-list__item-button--selected" : ""
}`}
id={`device-brand-list__item-button__${b}`}
<div class="device-brand-list-container">
<ul class="device-brand-list">
{
brandList.map((b: BrandEnum | "all") => (
<li class="device-brand-list__item">
<button
class={`device-brand-list__item-button ${
b === "all" ? "device-brand-list__item-button--selected" : ""
}`}
id={`device-brand-list__item-button__${b}`}
data-brand-name={b}
>
{b === "all" ? "All Brands" : brandValues[b]?.name ?? b}
</button>
</li>
))
}
</ul>
</div>
<div class="device-brand-select-container">
<select name="device-brand-select" id="device-brand-select">
{
brandList.map((b: BrandEnum | "all") => (
<option
class="device-brand-select__option"
value={b}
data-brand-name={b}
>
{b === "all" ? "All Brand" : b}
</button>
</li>
))
}
</ul>
{b === "all" ? "All Brands" : brandValues[b]?.name ?? b}
</option>
))
}
</select>
</div>
</section>
<section class="select-device">
<ul class="device-section-list">
Expand Down
140 changes: 86 additions & 54 deletions src/scripts/brand.json
Original file line number Diff line number Diff line change
@@ -1,56 +1,88 @@
{
"apple": [
"iphone-14",
"iphone-14-plus",
"iphone-14-pro",
"iphone-14-pro-max",
"iphone-13",
"iphone-13-mini",
"iphone-13-pro",
"iphone-13-pro-max",
"ipad-pro-11-inch",
"ipad-pro-13-inch",
"ipad-air-5",
"ipad",
"ipad-mini",
"apple-watch-ultra",
"apple-watch-series-8-41mm",
"apple-watch-series-8-45mm",
"macbook-12-inch",
"macbook-pro-14-inch",
"macbook-pro-16-inch",
"macbook-air-13-inch",
"imac-2013",
"imac-2015",
"imac-2015-retina"
],
"google": [
"google-pixel-1",
"google-pixel-4",
"google-pixel-4-xl",
"google-pixel-5"
],
"motorola": ["moto-e", "moto-g"],
"samsung": [
"galaxy-s21-plus",
"galaxy-s21-ultra",
"galaxy-s21",
"galaxy-s20-plus",
"galaxy-s20",
"galaxy-s20-ultra",
"galaxy-s-duos",
"galaxy-s4",
"galaxy-note-5",
"galaxy-y",
"samsung-tv-d8000",
"samsung-tv-es8000"
],
"dell": ["dell-xps-13", "dell-xps-15"],
"lg": ["lg-55lw5600", "lg-tm2792"],
"microsoft": [
"microsoft-surface-book",
"microsoft-surface-pro-4",
"microsoft-surface-pro-3"
],
"oneplus": ["oneplus-8-pro"]
"apple": {
"id": "apple",
"name": "Apple",
"modelIds": [
"iphone-14",
"iphone-14-plus",
"iphone-14-pro",
"iphone-14-pro-max",
"iphone-13",
"iphone-13-mini",
"iphone-13-pro",
"iphone-13-pro-max",
"ipad-pro-11-inch",
"ipad-pro-13-inch",
"ipad-air-5",
"ipad",
"ipad-mini",
"apple-watch-ultra",
"apple-watch-series-8-41mm",
"apple-watch-series-8-45mm",
"macbook-12-inch",
"macbook-pro-14-inch",
"macbook-pro-16-inch",
"macbook-air-13-inch",
"imac-2013",
"imac-2015",
"imac-2015-retina"
]
},
"google": {
"id": "google",
"name": "Google",
"modelIds": [
"google-pixel-1",
"google-pixel-4",
"google-pixel-4-xl",
"google-pixel-5"
]
},
"motorola": {
"id": "motorola",
"name": "Motorola",
"modelIds": ["moto-e", "moto-g"]
},
"samsung": {
"id": "samsung",
"name": "Samsung",
"modelIds": [
"galaxy-s21-plus",
"galaxy-s21-ultra",
"galaxy-s21",
"galaxy-s20-plus",
"galaxy-s20",
"galaxy-s20-ultra",
"galaxy-s-duos",
"galaxy-s4",
"galaxy-note-5",
"galaxy-y",
"samsung-tv-d8000",
"samsung-tv-es8000"
]
},
"dell": {
"id": "dell",
"name": "Dell",
"modelIds": ["dell-xps-13", "dell-xps-15"]
},
"lg": {
"id": "lg",
"name": "LG",
"modelIds": ["lg-55lw5600", "lg-tm2792"]
},
"microsoft": {
"id": "microsoft",
"name": "Microsoft",
"modelIds": [
"microsoft-surface-book",
"microsoft-surface-pro-4",
"microsoft-surface-pro-3"
]
},
"oneplus": {
"id": "oneplus",
"name": "OnePlus",
"modelIds": ["oneplus-8-pro"]
}
}
25 changes: 20 additions & 5 deletions src/scripts/deviceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ export class DeviceManager {

public getModelThumbnailListByBrand(
brand: BrandEnum,
): model.ModelThumbnail[] {
): model.BrandValue | undefined {
const targetBrand = this.allBrands[brand];
return targetBrand ?? [];
return targetBrand;
}

public getModelThumbnailList(
Expand All @@ -120,13 +120,16 @@ export class DeviceManager {
return [];
}

const targetBrand: model.ModelThumbnail[] = this.allBrands[brand] ?? [];
const targetBrand: model.BrandValue | undefined = this.allBrands[brand];
const targetType: model.ModelThumbnail[] =
deviceType === "all"
? this.allModelThumbnails
: this.allDeviceTypes[deviceType] ?? [];
return targetType.filter((value) =>
targetBrand.map((value) => value.modelId).includes(value.modelId),
return targetType.filter(
(value) =>
targetBrand?.thumbnails
.map((value) => value.modelId)
.includes(value.modelId),
); // ref https://stackoverflow.com/a/1885569/19287186
}

Expand All @@ -140,6 +143,18 @@ export class DeviceManager {
});
return result;
}

public getBrandValues(): Partial<Record<BrandEnum, model.BrandValue>> {
let result: Partial<Record<BrandEnum, model.BrandValue>> = {};
BrandEnum.options.forEach((b: BrandEnum) => {
const brandValue = this.allBrands[b];
if (brandValue == null) {
return;
}
result[b] = brandValue;
});
return result;
}
}

function makeDeviceManager(
Expand Down
23 changes: 19 additions & 4 deletions src/scripts/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ export interface ModelThumbnail {
device: Device;
}

export interface BrandValue {
id: schema.BrandEnum;
name: string;
thumbnails: ModelThumbnail[];
}

export interface ModelValue {
id: schema.ModelEnum;
name: string;
Expand All @@ -36,7 +42,7 @@ export interface ModelValue {
export type DeviceType = Partial<
Record<schema.DeviceTypeEnum, ModelThumbnail[]>
>;
export type Brand = Partial<Record<schema.BrandEnum, ModelThumbnail[]>>;
export type Brand = Partial<Record<schema.BrandEnum, BrandValue>>;
export type Model = Partial<Record<schema.ModelEnum, ModelValue>>;

export function getModelValue(
Expand Down Expand Up @@ -123,16 +129,25 @@ export function parseAllDeviceTypes(url: string, allModels: Model): DeviceType {
return mapDeviceType(rawDeviceTypes, allModels);
}

function mapBrandValue(bv: schema.RawBrandValue, allModels: Model): BrandValue {
return {
...bv,
thumbnails: mapModelThumbnails(bv.modelIds, allModels),
};
}
function mapBrand(data: schema.RawBrand, allModels: Model): Brand {
let result: Brand = {};
Object.keys(data).forEach((brandKey: string) => {
const brand = schema.BrandEnum.parse(brandKey);

const models: schema.ModelEnum[] = data[brand] ?? [];
const rawBrandValue: schema.RawBrandValue | undefined = data[brand];

const modelThumbnails = mapModelThumbnails(models, allModels);
if (rawBrandValue == null) {
return;
}
const brandValue: BrandValue = mapBrandValue(rawBrandValue, allModels);

result[brand] = modelThumbnails;
result[brand] = brandValue;
});
return result;
}
Expand Down
9 changes: 8 additions & 1 deletion src/scripts/parse/parseBrand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ export const BrandEnum = z.enum([
]);

export type BrandEnum = z.infer<typeof BrandEnum>;
const RawBrand = z.record(BrandEnum, z.array(ModelEnum));
export const RawBrandValue = z.object({
id: BrandEnum,
name: z.string(),
modelIds: z.array(ModelEnum),
});
export type RawBrandValue = z.infer<typeof RawBrandValue>;
const RawBrand = z.record(BrandEnum, RawBrandValue);

export type RawBrand = z.infer<typeof RawBrand>;

export function parseRawBrandFile(url: string): RawBrand {
Expand Down
Loading

0 comments on commit f35a9e9

Please sign in to comment.