Skip to content

Commit

Permalink
MPR Refactor duplicate search code in homejs and devicejs
Browse files Browse the repository at this point in the history
Refactor duplicate search code in homejs and devicejs
  • Loading branch information
YayunHuang authored Sep 2, 2024
2 parents e4706ee + 10c955f commit facbe31
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 297 deletions.
29 changes: 29 additions & 0 deletions src/components/DeviceSearch/DeviceSearch.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
import "./search.css";
import { DEVICE_MANAGER } from "../../scripts/deviceManager";
import { getModelItems, getBrandItems } from "../../scripts/algolia/generate";
const modelItems = getModelItems(DEVICE_MANAGER);
const brandItems = getBrandItems(DEVICE_MANAGER);
interface Props {
id: string;
}
const { id } = Astro.props;
---

<script define:vars={{ modelItems, brandItems, containerId: id }}>
window.modelItems = modelItems;
window.brandItems = brandItems;
if (window.containerIds != null) {
window.containerIds.push(containerId);
} else {
window.containerIds = [containerId];
}
</script>

<>
<div id={id}></div>
<script src="./search.js"></script>
</>
43 changes: 40 additions & 3 deletions src/styles/search.css → src/components/DeviceSearch/search.css
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,47 @@
height: 100%;
}

/* .aa-InputWrapperPrefix > .aa-DetachedCancelButton {
height: 100%;
} */
.aa-InputWrapperSuffix {
width: 48px;
}
}

/* header variant styles */

#device-list__header__autocomplete {
max-width: 38%; /* 543 / 1440 */
flex: 1 1 0%;
margin: 0;
height: 56px;
background: var(--white);
}

@media (width >= 992px) {
#device-list__header__autocomplete {
margin: 0 0 0 144px; /* to prevent search bar overlapping with mockuphone logo */
}
}

@media (width >= 1300px) {
#device-list__header__autocomplete {
margin: 0;
}
}

.search-device {
display: flex;
padding: 40px 20px 0;
}

@media (width >= 992px) {
.search-device {
display: none;
}
}

#device-list__page__autocomplete {
flex: 1 1 0%;
margin: 0;
height: 56px;
background: var(--white);
}
59 changes: 26 additions & 33 deletions src/pages/_home.js → src/components/DeviceSearch/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,22 @@ import * as autocompletePluginRecentSearchesPkg from "@algolia/autocomplete-plug
const { createLocalStorageRecentSearchesPlugin } =
autocompletePluginRecentSearchesPkg;
import * as autocompleteJsPkg from "@algolia/autocomplete-js";
const { autocomplete } = autocompleteJsPkg;

const NUM_DEFAULT_MODEL_ITEMS_TO_DISPLAY = 0;
const NUM_DEFAULT_BRAND_ITEMS_TO_DISPLAY = 0;
const MAX_SEARCH_HISTORY_ITEM = 5;
const ALGOLIA_SEARCH_HISTORY_KEY = "brandModelSearch";
const LOCAL_STORAGE_KEY = `AUTOCOMPLETE_RECENT_SEARCHES:${ALGOLIA_SEARCH_HISTORY_KEY}`;

class RootViewModel {
searchText = "";
_modelItems;
_brandItems;

constructor(modelItems, brandItems) {
mobx.makeObservable(this, {
searchText: mobx.observable,
shouldShowSearchClear: mobx.computed,
});
this._modelItems = modelItems;
this._brandItems = brandItems;
}
const { autocomplete } = autocompleteJsPkg;

get shouldShowSearchClear() {
return this.searchText !== "";
}
}
const NUM_DEFAULT_MODEL_ITEMS_TO_DISPLAY = 0;
const NUM_DEFAULT_BRAND_ITEMS_TO_DISPLAY = 0;
const MAX_SEARCH_HISTORY_ITEM = 5;

function isArray(obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
}

function appendToLocalStorageRecentSearches(item, type) {
const existingStr = localStorage.getItem(LOCAL_STORAGE_KEY);
const existingStr = localStorage.getItem(LOCAL_STORAGE_KEY) ?? "";
const existing = JSON.parse(existingStr);

const newHistoryItem = { id: item.id, label: item.name, type };
Expand Down Expand Up @@ -73,23 +56,31 @@ function moveOldHistoryToTop(oldHistoryItem) {
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(newHistory));
}

function initializeAutocomplete(viewModel) {
function injectVariables() {
return {
modelItems: window.modelItems,
brandItems: window.brandItems,
containerIds: window.containerIds,
};
}

function initializeAutocomplete(containerId, modelItems, brandItems) {
const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
key: ALGOLIA_SEARCH_HISTORY_KEY,
MAX_SEARCH_HISTORY_ITEM,
transformSource({ source }) {
return {
...source,
onSelect({ item }) {
const { id, label } = item;
const { id: itemId, label } = item;
const type = item.type ?? "";
moveOldHistoryToTop(item); // move most recent to top
switch (type) {
case "model":
window.location.href = `/model/${id}`;
window.location.href = `/model/${itemId}`;
break;
case "brand":
window.location.href = `/type/all/?brand=${id}`;
window.location.href = `/type/all/?brand=${itemId}`;
break;
default:
window.location.href = `/type/all/?query=${label}`;
Expand All @@ -98,12 +89,8 @@ function initializeAutocomplete(viewModel) {
};
},
});

const modelItems = viewModel._modelItems;
const brandItems = viewModel._brandItems;

autocomplete({
container: "#homepage-autocomplete",
container: `#${containerId}`,
openOnFocus: true,
plugins: [recentSearchesPlugin],
placeholder: "Search Device",
Expand Down Expand Up @@ -167,6 +154,13 @@ function initializeAutocomplete(viewModel) {
window.location.href = `${window.location.origin}/type/all/?query=${state.query}`;
},
});
}

function initialize() {
const { modelItems, brandItems, containerIds } = injectVariables();
containerIds.forEach((containerId) => {
initializeAutocomplete(containerId, modelItems, brandItems);
});

tippy(".aa-ClearButton", {
content: "Clear",
Expand Down Expand Up @@ -208,8 +202,7 @@ function ready(fn) {
}

function main() {
const viewModel = new RootViewModel(window.modelItems, window.brandItems);
initializeAutocomplete(viewModel);
initialize();
}

ready(main);
13 changes: 10 additions & 3 deletions src/layouts/BaseLayout/BaseLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap/dist/css/bootstrap-grid.min.css";
import "bootstrap/dist/css/bootstrap.min.css";
import "/src/styles/main.css";
import "/src/styles/tailwind.css";
import "./main.css";
import "./tailwind.css";
import { Image } from "@astrojs/image/components";
import DeviceSearch from "../../components/DeviceSearch/DeviceSearch.astro";
const title = "MockUPhone";
const description =
Expand All @@ -13,6 +14,12 @@ const social_url = "home_url";
const social_icon = `${
import.meta.env.PUBLIC_BASE_URL
}/images/mockuphone-logo.png`;
interface Props {
shouldRenderSearchBar?: boolean;
isHeaderTransparent?: boolean;
mainContainerClass?: string;
}
const {
shouldRenderSearchBar,
isHeaderTransparent = false,
Expand Down Expand Up @@ -134,7 +141,7 @@ const {
{
!!shouldRenderSearchBar ? (
<div class="header__search-container">
<div id="device-list__header__autocomplete" />
<DeviceSearch id="device-list__header__autocomplete" />
</div>
) : undefined
}
Expand Down
File renamed without changes.
File renamed without changes.
12 changes: 2 additions & 10 deletions src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,13 @@ import "/src/styles/home.css";
import BaseLayout from "../layouts/BaseLayout/BaseLayout.astro";
import { Image } from "@astrojs/image/components";
import { DEVICE_MANAGER } from "../scripts/deviceManager";
import { getModelItems, getBrandItems } from "../scripts/algolia/generate";
const modelItems = getModelItems(DEVICE_MANAGER);
const brandItems = getBrandItems(DEVICE_MANAGER);
import DeviceSearch from "../components/DeviceSearch/DeviceSearch.astro";
---

<BaseLayout
isHeaderTransparent={true}
mainContainerClass="main--landing-content"
>
<script define:vars={{ modelItems, brandItems }}>
window.modelItems = modelItems;
window.brandItems = brandItems;
</script>
<script src="./_home.js"></script>
<div class="landing-content">
<header class="headline">
<h2 class="headline__title">
Expand All @@ -27,7 +19,7 @@ const brandItems = getBrandItems(DEVICE_MANAGER);
Wrap your design in mobile devices in a few clicks!
</p>
</header>
<div id="homepage-autocomplete"></div>
<DeviceSearch id="homepage-autocomplete" />
<ul class="quick-device-list">
<li class="quick-device-list__item quick-device-list__item__light-blue">
<a
Expand Down
2 changes: 1 addition & 1 deletion src/pages/model/[model].astro
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { DEVICE_MANAGER } from "../../scripts/deviceManager";
import deviceJson from "../../scripts/device_info.json";
import type { ModelValue } from "../../scripts/model";
import { ModelEnum } from "../../scripts/parse";
import "/src/styles/upload.css";
import "./upload.css";
import * as Matrix from "../../scripts/utils/matrix";
import * as Rect from "../../scripts/utils/rect";
import * as Quad from "../../scripts/utils/quad";
Expand Down
File renamed without changes.
15 changes: 4 additions & 11 deletions src/pages/type/[type].astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import RequestDeviceCard from "../../components/RequestDeviceCard/RequestDeviceC
import "./index.css";
import { DEVICE_MANAGER } from "../../scripts/deviceManager";
import type { BrandValue, ModelThumbnail } from "../../scripts/model";
import { BrandEnum, DeviceTypeEnum } from "../../scripts/parse";
import { getModelItems, getBrandItems } from "../../scripts/algolia/generate";
const modelItems = getModelItems(DEVICE_MANAGER);
const brandItems = getBrandItems(DEVICE_MANAGER);
import { DEVICE_MANAGER } from "../../scripts/deviceManager";
import DeviceSearch from "../../components/DeviceSearch/DeviceSearch.astro";
export async function getStaticPaths() {
const devicePaths = DeviceTypeEnum.options.map((deviceType) => ({
Expand Down Expand Up @@ -47,17 +45,12 @@ const brandList: Array<BrandEnum | "all"> = ["all", ...nonEmptyBrands];
content="MockUPhone supports devices including iPhone mockup, iPad mockup, Android mockup and TV mockup. You can check out the whole device list via this page."
/>
<script src="./_device.js"></script>
<script
define:vars={{ thumbnailList, brandThumbnailList, modelItems, brandItems }}
>
<script define:vars={{ thumbnailList, brandThumbnailList }}>
window.thumbnailList = thumbnailList;
window.brandThumbnailList = brandThumbnailList;
window.modelItems = modelItems;
window.brandItems = brandItems;
</script>
<section class="search-device">
<div id="device-list__page__autocomplete"></div>
{/* Add suggestion list here */}
<DeviceSearch id="device-list__page__autocomplete" />
</section>
<section class="device-type">
<header>
Expand Down
Loading

0 comments on commit facbe31

Please sign in to comment.