diff --git a/src/components/DeviceSearch/DeviceSearch.astro b/src/components/DeviceSearch/DeviceSearch.astro new file mode 100644 index 0000000..8da111c --- /dev/null +++ b/src/components/DeviceSearch/DeviceSearch.astro @@ -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; +--- + + + +<> +
+ + diff --git a/src/styles/search.css b/src/components/DeviceSearch/search.css similarity index 77% rename from src/styles/search.css rename to src/components/DeviceSearch/search.css index aca5d49..8766a05 100644 --- a/src/styles/search.css +++ b/src/components/DeviceSearch/search.css @@ -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); +} diff --git a/src/pages/_home.js b/src/components/DeviceSearch/search.js similarity index 87% rename from src/pages/_home.js rename to src/components/DeviceSearch/search.js index 37b5559..1e04c20 100644 --- a/src/pages/_home.js +++ b/src/components/DeviceSearch/search.js @@ -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 }; @@ -73,7 +56,15 @@ 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, @@ -81,15 +72,15 @@ function initializeAutocomplete(viewModel) { 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}`; @@ -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", @@ -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", @@ -208,8 +202,7 @@ function ready(fn) { } function main() { - const viewModel = new RootViewModel(window.modelItems, window.brandItems); - initializeAutocomplete(viewModel); + initialize(); } ready(main); diff --git a/src/layouts/BaseLayout/BaseLayout.astro b/src/layouts/BaseLayout/BaseLayout.astro index 95e35a4..fd9471b 100644 --- a/src/layouts/BaseLayout/BaseLayout.astro +++ b/src/layouts/BaseLayout/BaseLayout.astro @@ -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 = @@ -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, @@ -134,7 +141,7 @@ const { { !!shouldRenderSearchBar ? (
-
+
) : undefined } diff --git a/src/styles/main.css b/src/layouts/BaseLayout/main.css similarity index 100% rename from src/styles/main.css rename to src/layouts/BaseLayout/main.css diff --git a/src/styles/tailwind.css b/src/layouts/BaseLayout/tailwind.css similarity index 100% rename from src/styles/tailwind.css rename to src/layouts/BaseLayout/tailwind.css diff --git a/src/pages/index.astro b/src/pages/index.astro index c8f0ab8..459c91c 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -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"; --- - -

@@ -27,7 +19,7 @@ const brandItems = getBrandItems(DEVICE_MANAGER); Wrap your design in mobile devices in a few clicks!

-
+