From 24a7c4e034d6f3ef989cf09832216e6d76818bab Mon Sep 17 00:00:00 2001 From: ddaoxuan Date: Mon, 2 Sep 2024 22:38:51 +0200 Subject: [PATCH 1/2] refactor!: Refactor to starters --- .github/workflows/check.yml | 33 +- .github/workflows/nextjs_bundle_analysis.yml | 91 +- .github/workflows/playwright.yml | 25 +- .gitignore | 20 - apps/web/.eslintrc.js | 3 - apps/web/.gitignore | 5 - apps/web/clients/replicate.ts | 19 - apps/web/clients/search.ts | 11 - apps/web/tailwind.config.ts | 22 - apps/web/tsconfig.json | 9 - package.json | 7 +- packages/core/.eslintignore | 12 - packages/core/.eslintrc.js | 3 - packages/core/jest.config.js | 5 - packages/core/package.json | 31 - packages/core/platform/index.ts | 19 - packages/core/tsconfig.json | 5 - packages/eslint-config-custom/package.json | 20 - packages/reviews/.eslintignore | 9 - packages/reviews/.eslintrc.js | 3 - packages/reviews/package.json | 20 - packages/reviews/tsconfig.json | 5 - packages/search/meilisearch/.eslintignore | 9 - packages/search/meilisearch/.eslintrc.js | 3 - packages/search/meilisearch/jest.config.js | 5 - packages/search/meilisearch/package.json | 21 - packages/search/meilisearch/tsconfig.json | 5 - packages/tailwind-config/package.json | 11 - packages/tailwind-config/tsconfig.json | 5 - packages/tsconfig/base.json | 24 - packages/tsconfig/nextjs.json | 21 - packages/tsconfig/package.json | 6 - packages/tsconfig/react-library.json | 11 - .../shopify-algolia/.eslintignore | 0 .../shopify-algolia/.eslintrc.js | 2 - starters/shopify-algolia/.gitignore | 21 + .../shopify-algolia}/.graphqlrc.ts | 8 +- starters/shopify-algolia/.prettierignore | 3 + .../shopify-algolia}/.storybook/main.ts | 0 .../shopify-algolia}/.storybook/preview.ts | 0 .../app/.well-known/vercel/flags/route.ts | 0 .../app/access-denied/page.tsx | 0 .../app/actions/cart.actions.ts | 0 .../app/actions/collection.actions.ts | 2 +- .../app/actions/favorites.actions.ts | 0 .../app/actions/page.actions.ts | 0 .../app/actions/product.actions.ts | 2 +- .../app/actions/reviews.actions.ts | 2 +- .../app/actions/user.actions.ts | 2 +- .../app/api/feed/sync/route.ts | 2 +- .../shopify-algolia}/app/api/health/route.ts | 0 .../app/api/redirects/route.ts | 0 .../app/api/reviews/ai-summary/route.ts | 2 +- .../app/api/reviews/sync/route.ts | 2 +- .../app/category/clp/[slug]/[page]/page.tsx | 0 .../app/category/clp/[slug]/page.tsx | 2 +- .../app/category/plp/[slug]/page.tsx | 0 .../shopify-algolia}/app/error.tsx | 0 .../shopify-algolia}/app/favorites/page.tsx | 0 .../shopify-algolia}/app/global-error.tsx | 0 .../shopify-algolia}/app/globals.css | 0 .../app/home/[bucket]/page.tsx | 2 +- .../shopify-algolia}/app/icon.png | Bin .../shopify-algolia}/app/layout.tsx | 0 .../shopify-algolia}/app/manifest.ts | 0 .../shopify-algolia}/app/not-found.tsx | 0 .../shopify-algolia}/app/opengraph-image.jpg | Bin .../app/pages/[slug]/metadata.ts | 0 .../app/pages/[slug]/page.tsx | 0 .../app/product/[slug]/draft/page.tsx | 6 +- .../app/product/[slug]/loading.tsx | 0 .../app/product/[slug]/metadata.ts | 0 .../app/product/[slug]/opengraph-image.tsx | 0 .../app/product/[slug]/page.tsx | 0 .../app/reviews/[slug]/metadata.ts | 0 .../app/reviews/[slug]/page.tsx | 0 .../shopify-algolia}/app/robots.txt | 0 .../app/search/opengraph-image.tsx | 0 .../shopify-algolia}/app/search/page.tsx | 0 .../shopify-algolia}/app/settings/page.tsx | 0 .../shopify-algolia}/app/sitemap.ts | 2 +- .../shopify-algolia}/app/styles/megamenu.css | 0 .../shopify-algolia}/app/styles/reset.css | 0 starters/shopify-algolia/clients/replicate.ts | 9 + .../shopify-algolia}/clients/reviews.ts | 2 +- starters/shopify-algolia/clients/search.ts | 7 + .../clients/storefrontClient.ts | 5 +- .../shopify-algolia}/components.json | 0 .../Accordion/Accordion.stories.tsx | 0 .../components/Accordion/Accordion.tsx | 0 .../components/Alert/Alert.tsx | 0 .../AnnouncementBar.stories.tsx | 0 .../AnnouncementBar/AnnouncementBar.tsx | 0 .../components/Badge/Badge.tsx | 0 .../components/Breadcrumb/Breadcrumb.tsx | 0 .../Breadcrumbs/Breadcrumbs.stories.tsx | 0 .../components/Breadcrumbs/Breadcrumbs.tsx | 0 .../components/Button/Button.stories.tsx | 0 .../components/Button/Button.tsx | 0 .../components/Button/ButtonNew.tsx | 0 .../CallToAction/CallToAction.stories.tsx | 0 .../components/CallToAction/CallToAction.tsx | 0 .../components/Card/Card.stories.tsx | 0 .../shopify-algolia}/components/Card/Card.tsx | 0 .../components/Carousel/Carousel.stories.tsx | 0 .../components/Carousel/Carousel.tsx | 0 .../components/Checkbox/Checkbox.stories.tsx | 0 .../components/Checkbox/Checkbox.tsx | 0 .../components/Dialog/Dialog.stories.tsx | 0 .../components/Dialog/Dialog.tsx | 0 .../DropdownMenu/DropdownMenu.stories.tsx | 0 .../components/DropdownMenu/DropdownMenu.tsx | 0 .../ExpandableContent/ExpandableContent.tsx | 0 .../components/Footer/Footer.stories.tsx | 0 .../components/Footer/Footer.tsx | 10 +- .../components/Form/Form.stories.tsx | 0 .../shopify-algolia}/components/Form/Form.tsx | 0 .../components/GenericModal/GenericModal.tsx | 0 .../components/Icons/ArrowIcon.tsx | 0 .../components/Icons/CaretSortIcon.tsx | 0 .../components/Icons/CheckIcon.tsx | 0 .../components/Icons/ChevronIcon.tsx | 0 .../components/Icons/CloseIcon.tsx | 0 .../components/Icons/FavoritesIcon.tsx | 0 .../components/Icons/FiltersIcon.tsx | 0 .../components/Icons/HeartIcon.tsx | 0 .../components/Icons/Icons.stories.tsx | 0 .../components/Icons/RobotIcon.tsx | 0 .../components/Icons/SearchIcon.tsx | 0 .../components/Icons/StarIcon.tsx | 0 .../components/Icons/ThinSearchIcon.tsx | 0 .../components/Input/Input.stories.tsx | 0 .../components/Input/Input.tsx | 0 .../components/Label/Label.stories.tsx | 0 .../components/Label/Label.tsx | 0 .../LoadingDots/LoadingDots.stories.tsx | 0 .../components/LoadingDots/LoadingDots.tsx | 0 .../shopify-algolia}/components/Logo/Logo.tsx | 0 .../components/Modals/LoginModal.tsx | 0 .../components/Modals/Modals.tsx | 0 .../components/Modals/ReviewModal.tsx | 2 +- .../components/Modals/SearchModal.tsx | 0 .../components/Modals/SignupModal.tsx | 0 .../components/NavigationBar/Autocomplete.tsx | 0 .../components/NavigationBar/Cart.tsx | 0 .../components/NavigationBar/Favorites.tsx | 0 .../NavigationBar/NavigationBar.tsx | 0 .../NavigationBar/NavigationItem.tsx | 0 .../NavigationBar/OpenCartButton.tsx | 0 .../components/NavigationBar/SearchButton.tsx | 0 .../NavigationBar/mobileInlineScript.ts | 0 .../components/NavigationBar/types.ts | 0 .../variants/ImageGridVariant.tsx | 0 .../variants/TextGridVariant.tsx | 0 .../variants/TextImageGridVariant.tsx | 0 .../Pagination/Pagination.stories.tsx | 0 .../components/Pagination/Pagination.tsx | 0 .../components/ProductCard/ProductCard.tsx | 0 .../components/ProductCard/QuickAdd.tsx | 2 +- .../components/ProductCard/QuickAddButton.tsx | 0 .../components/ProfileMenu/AuthActions.tsx | 0 .../components/ProfileMenu/ProfileBar.tsx | 4 +- .../components/ProfileMenu/ProfileMenu.tsx | 0 .../components/Select/Select.stories.tsx | 0 .../components/Select/Select.tsx | 0 .../components/Sheet/Sheet.stories.tsx | 0 .../components/Sheet/Sheet.tsx | 0 .../components/Skeleton/Skeleton.stories.tsx | 0 .../components/Skeleton/Skeleton.tsx | 0 .../components/Spinner/Spinner.stories.tsx | 0 .../components/Spinner/Spinner.tsx | 0 .../components/Textarea/Textarea.tsx | 0 .../shopify-algolia}/constants/index.ts | 0 .../shopify-algolia}/e2e/example.spec.ts | 0 starters/shopify-algolia/env.mjs | 48 + .../shopify-algolia}/jest.config.js | 0 .../shopify-algolia}/jest.setup.js | 0 .../shopify-algolia/lib/reviews}/index.ts | 13 +- .../shopify-algolia/lib/reviews}/types.ts | 0 .../lib}/shopify/fragments/cart.ts | 0 .../lib}/shopify/fragments/collection.ts | 0 .../lib}/shopify/fragments/customer.ts | 0 .../lib}/shopify/fragments/image.ts | 0 .../lib}/shopify/fragments/menu.ts | 0 .../lib}/shopify/fragments/page.ts | 0 .../lib}/shopify/fragments/product.ts | 0 .../lib}/shopify/fragments/seo.ts | 0 .../shopify-algolia/lib}/shopify/index.ts | 2 +- .../lib}/shopify/mutations/cart.storefront.ts | 0 .../shopify/mutations/customer.storefront.ts | 0 .../shopify/mutations/product-feed.admin.ts | 0 .../lib}/shopify/mutations/webhook.admin.ts | 0 .../shopify-algolia/lib}/shopify/normalize.ts | 2 +- .../lib}/shopify/queries/cart.storefront.ts | 0 .../shopify/queries/collection.storefront.ts | 0 .../shopify/queries/customer.storefront.ts | 0 .../lib}/shopify/queries/menu.storefront.ts | 2 +- .../lib}/shopify/queries/page.storefront.ts | 0 .../shopify/queries/product-feed.admin.ts | 0 .../lib}/shopify/queries/product.admin.ts | 0 .../shopify/queries/product.storefront.ts | 0 .../types/admin/admin-2024-01.schema.json | 0 .../shopify/types/admin/admin.generated.d.ts | 0 .../lib}/shopify/types/admin/admin.types.d.ts | 0 .../lib/shopify/types/index.ts | 2 +- .../types/storefront-2024-01.schema.json | 0 .../shopify/types/storefront.generated.d.ts | 2 - .../lib}/shopify/types/storefront.types.d.ts | 0 .../shopify-algolia}/middleware.ts | 0 .../shopify-algolia}/next-env.d.ts | 0 starters/shopify-algolia/next.config.mjs | 31 + .../shopify-algolia}/package.json | 20 +- .../shopify-algolia}/playwright.config.ts | 0 .../shopify-algolia}/postcss.config.js | 0 .../shopify-algolia/prettier.config.js | 0 .../public/category-placeholder-1.svg | 0 .../public/category-placeholder-2.svg | 0 .../public/category-placeholder-3.svg | 0 .../public/category-placeholder-4.svg | 0 .../public/category-placeholder-5.svg | 0 .../public/category-placeholder-6.svg | 0 .../public/default-product-image.svg | 0 .../public/demo-categories-data.json | 0 .../shopify-algolia}/public/demo-data.json | 0 .../public/demo-product-reviews-data.json | 0 .../public/fonts/Inter-Black.ttf | Bin .../public/fonts/Inter-Bold.ttf | Bin .../public/fonts/Inter-ExtraBold.ttf | Bin .../public/fonts/Inter-ExtraLight.ttf | Bin .../public/fonts/Inter-Light.ttf | Bin .../public/fonts/Inter-Medium.ttf | Bin .../public/fonts/Inter-Regular.ttf | Bin .../public/fonts/Inter-SemiBold.ttf | Bin .../public/fonts/Inter-Thin.ttf | Bin .../shopify-algolia}/public/menu/beauty-1.png | Bin .../shopify-algolia}/public/menu/beauty-2.png | Bin .../shopify-algolia}/public/menu/beauty-3.png | Bin .../shopify-algolia}/public/menu/beauty-4.png | Bin .../shopify-algolia}/public/menu/beauty-5.png | Bin .../public/menu/electronics-1.png | Bin .../public/menu/electronics-2.png | Bin .../public/menu/electronics-3.png | Bin .../public/menu/electronics-4.png | Bin .../public/menu/furniture-1.png | Bin .../public/menu/furniture-2.png | Bin .../public/menu/furniture-3.png | Bin .../public/menu/furniture-4.png | Bin .../redirects/bloom-filter.json | 0 .../redirects/generate-bloom-filter.ts | 0 .../redirects/new-redirects.json | 0 .../shopify-algolia}/redirects/redirects.json | 0 .../shopify-algolia}/report-bundle-size.js | 0 .../shopify-algolia}/reset.d.ts | 0 .../shopify-algolia}/shopify-webhooks.d.ts | 0 .../stores/addProductStore.ts | 2 +- .../shopify-algolia}/stores/cartStore.ts | 2 +- .../stores/filterTransitionStore.ts | 0 .../shopify-algolia}/stores/filtersStore.ts | 0 .../shopify-algolia}/stores/modalStore.ts | 11 +- .../shopify-algolia}/stores/userStore.ts | 4 +- .../shopify-algolia}/tailwind.config.ts | 11 +- starters/shopify-algolia/tsconfig.json | 34 + .../shopify-algolia}/types/index.ts | 2 +- .../shopify-algolia}/utils/abTesting.ts | 0 .../utils/authenticate-api-route.ts | 0 .../shopify-algolia}/utils/cn.ts | 0 .../shopify-algolia}/utils/compare-hmac.ts | 0 .../shopify-algolia}/utils/demoUtils.ts | 0 .../shopify-algolia}/utils/enrich-product.ts | 2 +- .../utils/filterBuilder.test.ts | 0 .../shopify-algolia}/utils/filterBuilder.ts | 0 .../shopify-algolia}/utils/getCookie.ts | 0 .../utils/getVercelFlagOverrides.ts | 0 .../utils/highlightedText.tsx | 0 .../shopify-algolia}/utils/makeKeywords.ts | 2 +- .../utils/mapCurrencyToSign.ts | 0 .../shopify-algolia}/utils/opt-in.ts | 4 +- .../utils/productOptionsUtils.ts | 2 +- .../shopify-algolia}/utils/slug-name.ts | 0 .../shopify-algolia}/utils/useAutocomplete.ts | 0 .../utils/useHierarchicalMenu.ts | 0 .../shopify-algolia}/utils/useReadMore.ts | 0 .../shopify-algolia}/vercel.json | 0 .../shopify-algolia}/views/Cart/CartItem.tsx | 2 +- .../shopify-algolia}/views/Cart/CartSheet.tsx | 2 +- .../shopify-algolia}/views/Cart/CartView.tsx | 0 .../views/Cart/ChangeQuantityButton.tsx | 0 .../views/Cart/DeleteButton.tsx | 0 .../views/Category/CategoryView.tsx | 0 .../views/Category/PageSkeleton.tsx | 0 .../shopify-algolia}/views/DemoModeAlert.tsx | 0 .../shopify-algolia}/views/DraftToolbar.tsx | 0 .../shopify-algolia}/views/FlagValues.tsx | 0 .../shopify-algolia}/views/GithubBadge.tsx | 0 .../views/Homepage/BestOffersSection.tsx | 0 .../views/Homepage/CarouselSection.tsx | 0 .../views/Homepage/CategoriesSection.tsx | 0 .../views/Homepage/EverythingUnderSection.tsx | 0 .../views/Homepage/HeroSection.tsx | 0 .../views/Homepage/ProductsWeekSection.tsx | 0 .../views/Listing/CategoryFacet.tsx | 0 .../views/Listing/Controls.tsx | 0 .../shopify-algolia}/views/Listing/Facet.tsx | 0 .../views/Listing/FacetsContent.tsx | 0 .../views/Listing/FacetsDesktop.tsx | 0 .../views/Listing/FacetsMobile.tsx | 0 .../views/Listing/HideFilters.tsx | 0 .../views/Listing/HitsSection.tsx | 0 .../views/Listing/PageSkeleton.tsx | 0 .../views/Listing/PaginationSection.tsx | 0 .../views/Listing/PriceFacet.tsx | 0 .../views/Listing/RatingFacet.tsx | 0 .../views/Listing/SearchFacet.tsx | 0 .../shopify-algolia}/views/Listing/Sorter.tsx | 0 .../views/Listing/composeFilters.test.ts | 0 .../views/Listing/composeFilters.ts | 0 .../views/Product/AddToCartButton.tsx | 2 +- .../views/Product/BackButton.tsx | 0 .../views/Product/CenterImageSection.tsx | 0 .../views/Product/FaqSection.tsx | 0 .../views/Product/FavoriteMarker.tsx | 0 .../views/Product/PageSkeleton.tsx | 0 .../views/Product/ProductAddedAlert.tsx | 0 .../views/Product/ProductImages.tsx | 0 .../views/Product/ProductTitle.tsx | 0 .../views/Product/ReviewButton.tsx | 0 .../views/Product/ReviewCard.tsx | 0 .../views/Product/ReviewsSection.tsx | 0 .../views/Product/RightSection.tsx | 0 .../views/Product/SideImages.tsx | 0 .../views/Product/SimilarProductsSection.tsx | 0 .../SimilarProductsSectionSkeleton.tsx | 0 .../views/Product/StarRating.tsx | 0 .../views/Product/Variant.tsx | 2 +- .../views/Product/VariantsSection.tsx | 2 +- .../views/Search/SearchView.tsx | 2 +- .../views/Settings/ProfileForm.tsx | 2 +- .../views/Settings/SettingsView.tsx | 0 .../shopify-algolia}/views/ThirdParties.tsx | 0 starters/shopify-meilisearch/.eslintignore | 8 + starters/shopify-meilisearch/.eslintrc.js | 39 + starters/shopify-meilisearch/.gitignore | 22 + starters/shopify-meilisearch/.graphqlrc.ts | 20 + .../shopify-meilisearch/.prettierignore | 0 .../shopify-meilisearch/.storybook/main.ts | 30 + .../shopify-meilisearch/.storybook/preview.ts | 17 + .../app/.well-known/vercel/flags/route.ts | 35 + .../app/access-denied/page.tsx | 13 + .../app/actions/cart.actions.ts | 86 + .../app/actions/collection.actions.ts | 27 + .../app/actions/favorites.actions.ts | 20 + .../app/actions/page.actions.ts | 8 + .../app/actions/product.actions.ts | 84 + .../app/actions/reviews.actions.ts | 15 + .../app/actions/user.actions.ts | 34 + .../app/api/feed/sync/route.ts | 127 + .../app/api/health/route.ts | 3 + .../app/api/redirects/route.ts | 25 + .../app/api/reviews/ai-summary/route.ts | 178 + .../app/api/reviews/sync/route.ts | 97 + .../app/category/clp/[slug]/[page]/page.tsx | 24 + .../app/category/clp/[slug]/page.tsx | 38 + .../app/category/plp/[slug]/page.tsx | 23 + starters/shopify-meilisearch/app/error.tsx | 33 + .../app/favorites/page.tsx | 61 + .../shopify-meilisearch/app/global-error.tsx | 19 + starters/shopify-meilisearch/app/globals.css | 22 + .../app/home/[bucket]/page.tsx | 44 + starters/shopify-meilisearch/app/icon.png | Bin 0 -> 24936 bytes starters/shopify-meilisearch/app/layout.tsx | 271 + starters/shopify-meilisearch/app/manifest.ts | 20 + .../shopify-meilisearch/app/not-found.tsx | 18 + .../app/opengraph-image.jpg | Bin 0 -> 1014388 bytes .../app/pages/[slug]/metadata.ts | 14 + .../app/pages/[slug]/page.tsx | 32 + .../app/product/[slug]/draft/page.tsx | 114 + .../app/product/[slug]/loading.tsx | 5 + .../app/product/[slug]/metadata.ts | 69 + .../app/product/[slug]/opengraph-image.tsx | 131 + .../app/product/[slug]/page.tsx | 123 + .../app/reviews/[slug]/metadata.ts | 31 + .../app/reviews/[slug]/page.tsx | 111 + starters/shopify-meilisearch/app/robots.txt | 15 + .../app/search/opengraph-image.tsx | 88 + .../shopify-meilisearch/app/search/page.tsx | 26 + .../shopify-meilisearch/app/settings/page.tsx | 5 + starters/shopify-meilisearch/app/sitemap.ts | 93 + .../app/styles/megamenu.css | 364 + .../shopify-meilisearch/app/styles/reset.css | 385 + .../shopify-meilisearch/clients/replicate.ts | 11 + .../shopify-meilisearch/clients/reviews.ts | 15 + .../shopify-meilisearch/clients/search.ts | 7 + .../clients/storefrontClient.ts | 10 + starters/shopify-meilisearch/components.json | 18 + .../Accordion/Accordion.stories.tsx | 60 + .../components/Accordion/Accordion.tsx | 46 + .../components/Alert/Alert.tsx | 36 + .../AnnouncementBar.stories.tsx | 17 + .../AnnouncementBar/AnnouncementBar.tsx | 13 + .../components/Badge/Badge.tsx | 28 + .../components/Breadcrumb/Breadcrumb.tsx | 51 + .../Breadcrumbs/Breadcrumbs.stories.tsx | 17 + .../components/Breadcrumbs/Breadcrumbs.tsx | 36 + .../components/Button/Button.stories.tsx | 33 + .../components/Button/Button.tsx | 66 + .../components/Button/ButtonNew.tsx | 42 + .../CallToAction/CallToAction.stories.tsx | 17 + .../components/CallToAction/CallToAction.tsx | 32 + .../components/Card/Card.stories.tsx | 29 + .../components/Card/Card.tsx | 35 + .../components/Carousel/Carousel.stories.tsx | 27 + .../components/Carousel/Carousel.tsx | 198 + .../components/Checkbox/Checkbox.stories.tsx | 23 + .../components/Checkbox/Checkbox.tsx | 26 + .../components/Dialog/Dialog.stories.tsx | 26 + .../components/Dialog/Dialog.tsx | 68 + .../DropdownMenu/DropdownMenu.stories.tsx | 29 + .../components/DropdownMenu/DropdownMenu.tsx | 162 + .../ExpandableContent/ExpandableContent.tsx | 52 + .../components/Footer/Footer.stories.tsx | 17 + .../components/Footer/Footer.tsx | 156 + .../components/Form/Form.stories.tsx | 52 + .../components/Form/Form.tsx | 103 + .../components/GenericModal/GenericModal.tsx | 30 + .../components/Icons/ArrowIcon.tsx | 12 + .../components/Icons/CaretSortIcon.tsx | 12 + .../components/Icons/CheckIcon.tsx | 12 + .../components/Icons/ChevronIcon.tsx | 7 + .../components/Icons/CloseIcon.tsx | 7 + .../components/Icons/FavoritesIcon.tsx | 10 + .../components/Icons/FiltersIcon.tsx | 60 + .../components/Icons/HeartIcon.tsx | 14 + .../components/Icons/Icons.stories.tsx | 35 + .../components/Icons/RobotIcon.tsx | 23 + .../components/Icons/SearchIcon.tsx | 7 + .../components/Icons/StarIcon.tsx | 18 + .../components/Icons/ThinSearchIcon.tsx | 16 + .../components/Input/Input.stories.tsx | 23 + .../components/Input/Input.tsx | 21 + .../components/Label/Label.stories.tsx | 17 + .../components/Label/Label.tsx | 15 + .../LoadingDots/LoadingDots.stories.tsx | 17 + .../components/LoadingDots/LoadingDots.tsx | 12 + .../components/Logo/Logo.tsx | 23 + .../components/Modals/LoginModal.tsx | 93 + .../components/Modals/Modals.tsx | 41 + .../components/Modals/ReviewModal.tsx | 183 + .../components/Modals/SearchModal.tsx | 138 + .../components/Modals/SignupModal.tsx | 92 + .../components/NavigationBar/Autocomplete.tsx | 78 + .../components/NavigationBar/Cart.tsx | 30 + .../components/NavigationBar/Favorites.tsx | 17 + .../NavigationBar/NavigationBar.tsx | 111 + .../NavigationBar/NavigationItem.tsx | 24 + .../NavigationBar/OpenCartButton.tsx | 13 + .../components/NavigationBar/SearchButton.tsx | 16 + .../NavigationBar/mobileInlineScript.ts | 78 + .../components/NavigationBar/types.ts | 30 + .../variants/ImageGridVariant.tsx | 28 + .../variants/TextGridVariant.tsx | 35 + .../variants/TextImageGridVariant.tsx | 44 + .../Pagination/Pagination.stories.tsx | 65 + .../components/Pagination/Pagination.tsx | 81 + .../components/ProductCard/ProductCard.tsx | 55 + .../components/ProductCard/QuickAdd.tsx | 27 + .../components/ProductCard/QuickAddButton.tsx | 75 + .../components/ProfileMenu/AuthActions.tsx | 19 + .../components/ProfileMenu/ProfileBar.tsx | 35 + .../components/ProfileMenu/ProfileMenu.tsx | 40 + .../components/Select/Select.stories.tsx | 34 + .../components/Select/Select.tsx | 108 + .../components/Sheet/Sheet.stories.tsx | 47 + .../components/Sheet/Sheet.tsx | 80 + .../components/Skeleton/Skeleton.stories.tsx | 17 + .../components/Skeleton/Skeleton.tsx | 7 + .../components/Spinner/Spinner.stories.tsx | 17 + .../components/Spinner/Spinner.tsx | 5 + .../components/Textarea/Textarea.tsx | 21 + .../shopify-meilisearch/constants/index.ts | 17 + .../shopify-meilisearch/e2e/example.spec.ts | 6 + .../shopify-meilisearch}/env.mjs | 0 starters/shopify-meilisearch/jest.config.js | 14 + starters/shopify-meilisearch/jest.setup.js | 2 + .../lib/meilisearch/filterBuilder.test.ts | 208 + .../lib/meilisearch/filterBuilder.ts | 106 + .../lib}/meilisearch/index.ts | 0 .../shopify-meilisearch/lib/reviews/index.ts | 106 + .../shopify-meilisearch/lib/reviews/types.ts | 62 + .../lib/shopify/fragments/cart.ts | 58 + .../lib/shopify/fragments/collection.ts | 23 + .../lib/shopify/fragments/customer.ts | 16 + .../lib/shopify/fragments/image.ts | 10 + .../lib/shopify/fragments/menu.ts | 28 + .../lib/shopify/fragments/page.ts | 21 + .../lib/shopify/fragments/product.ts | 72 + .../lib/shopify/fragments/seo.ts | 8 + .../shopify-meilisearch/lib/shopify/index.ts | 265 + .../lib/shopify/mutations/cart.storefront.ts | 45 + .../shopify/mutations/customer.storefront.ts | 60 + .../shopify/mutations/product-feed.admin.ts | 25 + .../lib/shopify/mutations/webhook.admin.ts | 13 + .../lib/shopify/normalize.ts | 50 + .../lib/shopify/queries/cart.storefront.ts | 10 + .../shopify/queries/collection.storefront.ts | 32 + .../shopify/queries/customer.storefront.ts | 10 + .../lib/shopify/queries/menu.storefront.ts | 20 + .../lib/shopify/queries/page.storefront.ts | 23 + .../lib/shopify/queries/product-feed.admin.ts | 11 + .../lib/shopify/queries/product.admin.ts | 94 + .../lib/shopify/queries/product.storefront.ts | 49 + .../types/admin/admin-2024-01.schema.json | 1 + .../shopify/types/admin/admin.generated.d.ts | 103 + .../lib/shopify/types/admin/admin.types.d.ts | 49082 ++++++++++++++++ .../lib/shopify/types/index.ts | 153 + .../types/storefront-2024-01.schema.json | 1 + .../shopify/types/storefront.generated.d.ts | 791 + .../lib/shopify/types/storefront.types.d.ts | 7894 +++ starters/shopify-meilisearch/middleware.ts | 138 + starters/shopify-meilisearch/next-env.d.ts | 5 + .../shopify-meilisearch}/next.config.mjs | 0 starters/shopify-meilisearch/package.json | 104 + .../shopify-meilisearch/playwright.config.ts | 69 + .../shopify-meilisearch/postcss.config.js | 6 + .../shopify-meilisearch/prettier.config.js | 7 + .../public/category-placeholder-1.svg | 8 + .../public/category-placeholder-2.svg | 10 + .../public/category-placeholder-3.svg | 8 + .../public/category-placeholder-4.svg | 9 + .../public/category-placeholder-5.svg | 9 + .../public/category-placeholder-6.svg | 10 + .../public/default-product-image.svg | 8 + .../public/demo-categories-data.json | 62 + .../shopify-meilisearch/public/demo-data.json | 3433 ++ .../public/demo-product-reviews-data.json | 103 + .../public/fonts/Inter-Black.ttf | Bin 0 -> 316848 bytes .../public/fonts/Inter-Bold.ttf | Bin 0 -> 316584 bytes .../public/fonts/Inter-ExtraBold.ttf | Bin 0 -> 317184 bytes .../public/fonts/Inter-ExtraLight.ttf | Bin 0 -> 311232 bytes .../public/fonts/Inter-Light.ttf | Bin 0 -> 310832 bytes .../public/fonts/Inter-Medium.ttf | Bin 0 -> 315132 bytes .../public/fonts/Inter-Regular.ttf | Bin 0 -> 310252 bytes .../public/fonts/Inter-SemiBold.ttf | Bin 0 -> 316220 bytes .../public/fonts/Inter-Thin.ttf | Bin 0 -> 310984 bytes .../public/menu/beauty-1.png | Bin 0 -> 669562 bytes .../public/menu/beauty-2.png | Bin 0 -> 658313 bytes .../public/menu/beauty-3.png | Bin 0 -> 453603 bytes .../public/menu/beauty-4.png | Bin 0 -> 492662 bytes .../public/menu/beauty-5.png | Bin 0 -> 565160 bytes .../public/menu/electronics-1.png | Bin 0 -> 540528 bytes .../public/menu/electronics-2.png | Bin 0 -> 453412 bytes .../public/menu/electronics-3.png | Bin 0 -> 426547 bytes .../public/menu/electronics-4.png | Bin 0 -> 727915 bytes .../public/menu/furniture-1.png | Bin 0 -> 296512 bytes .../public/menu/furniture-2.png | Bin 0 -> 632055 bytes .../public/menu/furniture-3.png | Bin 0 -> 489733 bytes .../public/menu/furniture-4.png | Bin 0 -> 501430 bytes .../redirects/bloom-filter.json | 1 + .../redirects/generate-bloom-filter.ts | 12 + .../redirects/new-redirects.json | 1 + .../redirects/redirects.json | 6 + .../shopify-meilisearch/report-bundle-size.js | 131 + starters/shopify-meilisearch/reset.d.ts | 13 + .../shopify-meilisearch/shopify-webhooks.d.ts | 109 + .../stores/addProductStore.ts | 18 + .../shopify-meilisearch/stores/cartStore.ts | 28 + .../stores/filterTransitionStore.ts | 11 + .../stores/filtersStore.ts | 13 + .../shopify-meilisearch/stores/modalStore.ts | 35 + .../shopify-meilisearch/stores/userStore.ts | 12 + .../shopify-meilisearch/tailwind.config.ts | 148 + starters/shopify-meilisearch/tsconfig.json | 34 + starters/shopify-meilisearch/types/index.ts | 10 + .../shopify-meilisearch/utils/abTesting.ts | 18 + .../utils/authenticate-api-route.ts | 15 + starters/shopify-meilisearch/utils/cn.ts | 6 + .../shopify-meilisearch/utils/compare-hmac.ts | 7 + .../shopify-meilisearch/utils/demoUtils.ts | 52 + .../utils/enrich-product.ts | 89 + .../shopify-meilisearch/utils/getCookie.ts | 15 + .../utils/getVercelFlagOverrides.ts | 16 + .../utils/highlightedText.tsx | 22 + .../shopify-meilisearch/utils/makeKeywords.ts | 78 + .../utils/mapCurrencyToSign.ts | 15 + starters/shopify-meilisearch/utils/opt-in.ts | 31 + .../utils/productOptionsUtils.ts | 70 + .../shopify-meilisearch/utils/slug-name.ts | 10 + .../utils/useAutocomplete.ts | 59 + .../utils/useHierarchicalMenu.ts | 85 + .../shopify-meilisearch/utils/useReadMore.ts | 14 + starters/shopify-meilisearch/vercel.json | 13 + .../views/Cart/CartItem.tsx | 45 + .../views/Cart/CartSheet.tsx | 98 + .../views/Cart/CartView.tsx | 30 + .../views/Cart/ChangeQuantityButton.tsx | 37 + .../views/Cart/DeleteButton.tsx | 33 + .../views/Category/CategoryView.tsx | 17 + .../views/Category/PageSkeleton.tsx | 37 + .../views/DemoModeAlert.tsx | 24 + .../views/DraftToolbar.tsx | 11 + .../shopify-meilisearch/views/FlagValues.tsx | 18 + .../shopify-meilisearch/views/GithubBadge.tsx | 40 + .../views/Homepage/BestOffersSection.tsx | 33 + .../views/Homepage/CarouselSection.tsx | 53 + .../views/Homepage/CategoriesSection.tsx | 63 + .../views/Homepage/EverythingUnderSection.tsx | 35 + .../views/Homepage/HeroSection.tsx | 21 + .../views/Homepage/ProductsWeekSection.tsx | 82 + .../views/Listing/CategoryFacet.tsx | 83 + .../views/Listing/Controls.tsx | 17 + .../views/Listing/Facet.tsx | 37 + .../views/Listing/FacetsContent.tsx | 208 + .../views/Listing/FacetsDesktop.tsx | 25 + .../views/Listing/FacetsMobile.tsx | 36 + .../views/Listing/HideFilters.tsx | 26 + .../views/Listing/HitsSection.tsx | 19 + .../views/Listing/PageSkeleton.tsx | 37 + .../views/Listing/PaginationSection.tsx | 59 + .../views/Listing/PriceFacet.tsx | 77 + .../views/Listing/RatingFacet.tsx | 38 + .../views/Listing/SearchFacet.tsx | 49 + .../views/Listing/Sorter.tsx | 59 + .../views/Listing/composeFilters.test.ts | 76 + .../views/Listing/composeFilters.ts | 48 + .../views/Product/AddToCartButton.tsx | 65 + .../views/Product/BackButton.tsx | 10 + .../views/Product/CenterImageSection.tsx | 36 + .../views/Product/FaqSection.tsx | 51 + .../views/Product/FavoriteMarker.tsx | 56 + .../views/Product/PageSkeleton.tsx | 62 + .../views/Product/ProductAddedAlert.tsx | 63 + .../views/Product/ProductImages.tsx | 32 + .../views/Product/ProductTitle.tsx | 20 + .../views/Product/ReviewButton.tsx | 25 + .../views/Product/ReviewCard.tsx | 33 + .../views/Product/ReviewsSection.tsx | 88 + .../views/Product/RightSection.tsx | 5 + .../views/Product/SideImages.tsx | 40 + .../views/Product/SimilarProductsSection.tsx | 72 + .../SimilarProductsSectionSkeleton.tsx | 20 + .../views/Product/StarRating.tsx | 14 + .../views/Product/Variant.tsx | 39 + .../views/Product/VariantsSection.tsx | 39 + .../views/Search/SearchView.tsx | 142 + .../views/Settings/ProfileForm.tsx | 102 + .../views/Settings/SettingsView.tsx | 26 + .../views/ThirdParties.tsx | 17 + tsconfig.json | 3 - turbo.json | 8 + yarn.lock | 1604 +- 649 files changed, 74520 insertions(+), 2009 deletions(-) delete mode 100644 apps/web/.eslintrc.js delete mode 100644 apps/web/.gitignore delete mode 100644 apps/web/clients/replicate.ts delete mode 100644 apps/web/clients/search.ts delete mode 100644 apps/web/tailwind.config.ts delete mode 100644 apps/web/tsconfig.json delete mode 100644 packages/core/.eslintignore delete mode 100644 packages/core/.eslintrc.js delete mode 100644 packages/core/jest.config.js delete mode 100644 packages/core/package.json delete mode 100644 packages/core/platform/index.ts delete mode 100644 packages/core/tsconfig.json delete mode 100644 packages/eslint-config-custom/package.json delete mode 100644 packages/reviews/.eslintignore delete mode 100644 packages/reviews/.eslintrc.js delete mode 100644 packages/reviews/package.json delete mode 100644 packages/reviews/tsconfig.json delete mode 100644 packages/search/meilisearch/.eslintignore delete mode 100644 packages/search/meilisearch/.eslintrc.js delete mode 100644 packages/search/meilisearch/jest.config.js delete mode 100644 packages/search/meilisearch/package.json delete mode 100644 packages/search/meilisearch/tsconfig.json delete mode 100644 packages/tailwind-config/package.json delete mode 100644 packages/tailwind-config/tsconfig.json delete mode 100644 packages/tsconfig/base.json delete mode 100644 packages/tsconfig/nextjs.json delete mode 100644 packages/tsconfig/package.json delete mode 100644 packages/tsconfig/react-library.json rename .eslintignore => starters/shopify-algolia/.eslintignore (100%) rename packages/eslint-config-custom/base.js => starters/shopify-algolia/.eslintrc.js (97%) create mode 100644 starters/shopify-algolia/.gitignore rename {packages/core => starters/shopify-algolia}/.graphqlrc.ts (62%) create mode 100644 starters/shopify-algolia/.prettierignore rename {apps/web => starters/shopify-algolia}/.storybook/main.ts (100%) rename {apps/web => starters/shopify-algolia}/.storybook/preview.ts (100%) rename {apps/web => starters/shopify-algolia}/app/.well-known/vercel/flags/route.ts (100%) rename {apps/web => starters/shopify-algolia}/app/access-denied/page.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/actions/cart.actions.ts (100%) rename {apps/web => starters/shopify-algolia}/app/actions/collection.actions.ts (90%) rename {apps/web => starters/shopify-algolia}/app/actions/favorites.actions.ts (100%) rename {apps/web => starters/shopify-algolia}/app/actions/page.actions.ts (100%) rename {apps/web => starters/shopify-algolia}/app/actions/product.actions.ts (97%) rename {apps/web => starters/shopify-algolia}/app/actions/reviews.actions.ts (84%) rename {apps/web => starters/shopify-algolia}/app/actions/user.actions.ts (93%) rename {apps/web => starters/shopify-algolia}/app/api/feed/sync/route.ts (98%) rename {apps/web => starters/shopify-algolia}/app/api/health/route.ts (100%) rename {apps/web => starters/shopify-algolia}/app/api/redirects/route.ts (100%) rename {apps/web => starters/shopify-algolia}/app/api/reviews/ai-summary/route.ts (98%) rename {apps/web => starters/shopify-algolia}/app/api/reviews/sync/route.ts (98%) rename {apps/web => starters/shopify-algolia}/app/category/clp/[slug]/[page]/page.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/category/clp/[slug]/page.tsx (92%) rename {apps/web => starters/shopify-algolia}/app/category/plp/[slug]/page.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/error.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/favorites/page.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/global-error.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/globals.css (100%) rename {apps/web => starters/shopify-algolia}/app/home/[bucket]/page.tsx (97%) rename {apps/web => starters/shopify-algolia}/app/icon.png (100%) rename {apps/web => starters/shopify-algolia}/app/layout.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/manifest.ts (100%) rename {apps/web => starters/shopify-algolia}/app/not-found.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/opengraph-image.jpg (100%) rename {apps/web => starters/shopify-algolia}/app/pages/[slug]/metadata.ts (100%) rename {apps/web => starters/shopify-algolia}/app/pages/[slug]/page.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/product/[slug]/draft/page.tsx (95%) rename {apps/web => starters/shopify-algolia}/app/product/[slug]/loading.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/product/[slug]/metadata.ts (100%) rename {apps/web => starters/shopify-algolia}/app/product/[slug]/opengraph-image.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/product/[slug]/page.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/reviews/[slug]/metadata.ts (100%) rename {apps/web => starters/shopify-algolia}/app/reviews/[slug]/page.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/robots.txt (100%) rename {apps/web => starters/shopify-algolia}/app/search/opengraph-image.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/search/page.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/settings/page.tsx (100%) rename {apps/web => starters/shopify-algolia}/app/sitemap.ts (96%) rename {apps/web => starters/shopify-algolia}/app/styles/megamenu.css (100%) rename {apps/web => starters/shopify-algolia}/app/styles/reset.css (100%) create mode 100644 starters/shopify-algolia/clients/replicate.ts rename {apps/web => starters/shopify-algolia}/clients/reviews.ts (85%) create mode 100644 starters/shopify-algolia/clients/search.ts rename {apps/web => starters/shopify-algolia}/clients/storefrontClient.ts (59%) rename {apps/web => starters/shopify-algolia}/components.json (100%) rename {apps/web => starters/shopify-algolia}/components/Accordion/Accordion.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Accordion/Accordion.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Alert/Alert.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/AnnouncementBar/AnnouncementBar.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/AnnouncementBar/AnnouncementBar.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Badge/Badge.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Breadcrumb/Breadcrumb.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Breadcrumbs/Breadcrumbs.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Breadcrumbs/Breadcrumbs.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Button/Button.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Button/Button.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Button/ButtonNew.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/CallToAction/CallToAction.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/CallToAction/CallToAction.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Card/Card.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Card/Card.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Carousel/Carousel.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Carousel/Carousel.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Checkbox/Checkbox.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Checkbox/Checkbox.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Dialog/Dialog.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Dialog/Dialog.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/DropdownMenu/DropdownMenu.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/DropdownMenu/DropdownMenu.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/ExpandableContent/ExpandableContent.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Footer/Footer.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Footer/Footer.tsx (94%) rename {apps/web => starters/shopify-algolia}/components/Form/Form.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Form/Form.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/GenericModal/GenericModal.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/ArrowIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/CaretSortIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/CheckIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/ChevronIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/CloseIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/FavoritesIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/FiltersIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/HeartIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/Icons.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/RobotIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/SearchIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/StarIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Icons/ThinSearchIcon.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Input/Input.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Input/Input.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Label/Label.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Label/Label.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/LoadingDots/LoadingDots.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/LoadingDots/LoadingDots.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Logo/Logo.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Modals/LoginModal.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Modals/Modals.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Modals/ReviewModal.tsx (98%) rename {apps/web => starters/shopify-algolia}/components/Modals/SearchModal.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Modals/SignupModal.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/Autocomplete.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/Cart.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/Favorites.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/NavigationBar.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/NavigationItem.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/OpenCartButton.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/SearchButton.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/mobileInlineScript.ts (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/types.ts (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/variants/ImageGridVariant.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/variants/TextGridVariant.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/NavigationBar/variants/TextImageGridVariant.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Pagination/Pagination.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Pagination/Pagination.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/ProductCard/ProductCard.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/ProductCard/QuickAdd.tsx (93%) rename {apps/web => starters/shopify-algolia}/components/ProductCard/QuickAddButton.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/ProfileMenu/AuthActions.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/ProfileMenu/ProfileBar.tsx (94%) rename {apps/web => starters/shopify-algolia}/components/ProfileMenu/ProfileMenu.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Select/Select.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Select/Select.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Sheet/Sheet.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Sheet/Sheet.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Skeleton/Skeleton.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Skeleton/Skeleton.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Spinner/Spinner.stories.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Spinner/Spinner.tsx (100%) rename {apps/web => starters/shopify-algolia}/components/Textarea/Textarea.tsx (100%) rename {apps/web => starters/shopify-algolia}/constants/index.ts (100%) rename {apps/web => starters/shopify-algolia}/e2e/example.spec.ts (100%) create mode 100644 starters/shopify-algolia/env.mjs rename {apps/web => starters/shopify-algolia}/jest.config.js (100%) rename {apps/web => starters/shopify-algolia}/jest.setup.js (100%) rename {packages/reviews/judge/src => starters/shopify-algolia/lib/reviews}/index.ts (87%) rename {packages/reviews/judge/src => starters/shopify-algolia/lib/reviews}/types.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/fragments/cart.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/fragments/collection.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/fragments/customer.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/fragments/image.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/fragments/menu.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/fragments/page.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/fragments/product.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/fragments/seo.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/index.ts (99%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/mutations/cart.storefront.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/mutations/customer.storefront.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/mutations/product-feed.admin.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/mutations/webhook.admin.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/normalize.ts (94%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/queries/cart.storefront.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/queries/collection.storefront.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/queries/customer.storefront.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/queries/menu.storefront.ts (91%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/queries/page.storefront.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/queries/product-feed.admin.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/queries/product.admin.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/queries/product.storefront.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/types/admin/admin-2024-01.schema.json (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/types/admin/admin.generated.d.ts (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/types/admin/admin.types.d.ts (100%) rename packages/core/platform/types.ts => starters/shopify-algolia/lib/shopify/types/index.ts (98%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/types/storefront-2024-01.schema.json (100%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/types/storefront.generated.d.ts (99%) rename {packages/core/platform => starters/shopify-algolia/lib}/shopify/types/storefront.types.d.ts (100%) rename {apps/web => starters/shopify-algolia}/middleware.ts (100%) rename {apps/web => starters/shopify-algolia}/next-env.d.ts (100%) create mode 100644 starters/shopify-algolia/next.config.mjs rename {apps/web => starters/shopify-algolia}/package.json (87%) rename {apps/web => starters/shopify-algolia}/playwright.config.ts (100%) rename {apps/web => starters/shopify-algolia}/postcss.config.js (100%) rename prettier.config.js => starters/shopify-algolia/prettier.config.js (100%) rename {apps/web => starters/shopify-algolia}/public/category-placeholder-1.svg (100%) rename {apps/web => starters/shopify-algolia}/public/category-placeholder-2.svg (100%) rename {apps/web => starters/shopify-algolia}/public/category-placeholder-3.svg (100%) rename {apps/web => starters/shopify-algolia}/public/category-placeholder-4.svg (100%) rename {apps/web => starters/shopify-algolia}/public/category-placeholder-5.svg (100%) rename {apps/web => starters/shopify-algolia}/public/category-placeholder-6.svg (100%) rename {apps/web => starters/shopify-algolia}/public/default-product-image.svg (100%) rename {apps/web => starters/shopify-algolia}/public/demo-categories-data.json (100%) rename {apps/web => starters/shopify-algolia}/public/demo-data.json (100%) rename {apps/web => starters/shopify-algolia}/public/demo-product-reviews-data.json (100%) rename {apps/web => starters/shopify-algolia}/public/fonts/Inter-Black.ttf (100%) rename {apps/web => starters/shopify-algolia}/public/fonts/Inter-Bold.ttf (100%) rename {apps/web => starters/shopify-algolia}/public/fonts/Inter-ExtraBold.ttf (100%) rename {apps/web => starters/shopify-algolia}/public/fonts/Inter-ExtraLight.ttf (100%) rename {apps/web => starters/shopify-algolia}/public/fonts/Inter-Light.ttf (100%) rename {apps/web => starters/shopify-algolia}/public/fonts/Inter-Medium.ttf (100%) rename {apps/web => starters/shopify-algolia}/public/fonts/Inter-Regular.ttf (100%) rename {apps/web => starters/shopify-algolia}/public/fonts/Inter-SemiBold.ttf (100%) rename {apps/web => starters/shopify-algolia}/public/fonts/Inter-Thin.ttf (100%) rename {apps/web => starters/shopify-algolia}/public/menu/beauty-1.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/beauty-2.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/beauty-3.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/beauty-4.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/beauty-5.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/electronics-1.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/electronics-2.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/electronics-3.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/electronics-4.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/furniture-1.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/furniture-2.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/furniture-3.png (100%) rename {apps/web => starters/shopify-algolia}/public/menu/furniture-4.png (100%) rename {apps/web => starters/shopify-algolia}/redirects/bloom-filter.json (100%) rename {apps/web => starters/shopify-algolia}/redirects/generate-bloom-filter.ts (100%) rename {apps/web => starters/shopify-algolia}/redirects/new-redirects.json (100%) rename {apps/web => starters/shopify-algolia}/redirects/redirects.json (100%) rename {apps/web => starters/shopify-algolia}/report-bundle-size.js (100%) rename {apps/web => starters/shopify-algolia}/reset.d.ts (100%) rename {apps/web => starters/shopify-algolia}/shopify-webhooks.d.ts (100%) rename {apps/web => starters/shopify-algolia}/stores/addProductStore.ts (88%) rename {apps/web => starters/shopify-algolia}/stores/cartStore.ts (92%) rename {apps/web => starters/shopify-algolia}/stores/filterTransitionStore.ts (100%) rename {apps/web => starters/shopify-algolia}/stores/filtersStore.ts (100%) rename {apps/web => starters/shopify-algolia}/stores/modalStore.ts (77%) rename {apps/web => starters/shopify-algolia}/stores/userStore.ts (60%) rename {packages/tailwind-config => starters/shopify-algolia}/tailwind.config.ts (91%) create mode 100644 starters/shopify-algolia/tsconfig.json rename {apps/web => starters/shopify-algolia}/types/index.ts (80%) rename {apps/web => starters/shopify-algolia}/utils/abTesting.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/authenticate-api-route.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/cn.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/compare-hmac.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/demoUtils.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/enrich-product.ts (96%) rename {apps/web => starters/shopify-algolia}/utils/filterBuilder.test.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/filterBuilder.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/getCookie.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/getVercelFlagOverrides.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/highlightedText.tsx (100%) rename {apps/web => starters/shopify-algolia}/utils/makeKeywords.ts (95%) rename {apps/web => starters/shopify-algolia}/utils/mapCurrencyToSign.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/opt-in.ts (84%) rename {apps/web => starters/shopify-algolia}/utils/productOptionsUtils.ts (96%) rename {apps/web => starters/shopify-algolia}/utils/slug-name.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/useAutocomplete.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/useHierarchicalMenu.ts (100%) rename {apps/web => starters/shopify-algolia}/utils/useReadMore.ts (100%) rename {apps/web => starters/shopify-algolia}/vercel.json (100%) rename {apps/web => starters/shopify-algolia}/views/Cart/CartItem.tsx (96%) rename {apps/web => starters/shopify-algolia}/views/Cart/CartSheet.tsx (98%) rename {apps/web => starters/shopify-algolia}/views/Cart/CartView.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Cart/ChangeQuantityButton.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Cart/DeleteButton.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Category/CategoryView.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Category/PageSkeleton.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/DemoModeAlert.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/DraftToolbar.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/FlagValues.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/GithubBadge.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Homepage/BestOffersSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Homepage/CarouselSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Homepage/CategoriesSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Homepage/EverythingUnderSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Homepage/HeroSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Homepage/ProductsWeekSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/CategoryFacet.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/Controls.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/Facet.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/FacetsContent.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/FacetsDesktop.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/FacetsMobile.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/HideFilters.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/HitsSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/PageSkeleton.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/PaginationSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/PriceFacet.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/RatingFacet.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/SearchFacet.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/Sorter.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/composeFilters.test.ts (100%) rename {apps/web => starters/shopify-algolia}/views/Listing/composeFilters.ts (100%) rename {apps/web => starters/shopify-algolia}/views/Product/AddToCartButton.tsx (96%) rename {apps/web => starters/shopify-algolia}/views/Product/BackButton.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/CenterImageSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/FaqSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/FavoriteMarker.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/PageSkeleton.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/ProductAddedAlert.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/ProductImages.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/ProductTitle.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/ReviewButton.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/ReviewCard.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/ReviewsSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/RightSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/SideImages.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/SimilarProductsSection.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/SimilarProductsSectionSkeleton.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/StarRating.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/Product/Variant.tsx (94%) rename {apps/web => starters/shopify-algolia}/views/Product/VariantsSection.tsx (94%) rename {apps/web => starters/shopify-algolia}/views/Search/SearchView.tsx (98%) rename {apps/web => starters/shopify-algolia}/views/Settings/ProfileForm.tsx (97%) rename {apps/web => starters/shopify-algolia}/views/Settings/SettingsView.tsx (100%) rename {apps/web => starters/shopify-algolia}/views/ThirdParties.tsx (100%) create mode 100644 starters/shopify-meilisearch/.eslintignore create mode 100644 starters/shopify-meilisearch/.eslintrc.js create mode 100644 starters/shopify-meilisearch/.gitignore create mode 100644 starters/shopify-meilisearch/.graphqlrc.ts rename .prettierignore => starters/shopify-meilisearch/.prettierignore (100%) create mode 100644 starters/shopify-meilisearch/.storybook/main.ts create mode 100644 starters/shopify-meilisearch/.storybook/preview.ts create mode 100644 starters/shopify-meilisearch/app/.well-known/vercel/flags/route.ts create mode 100644 starters/shopify-meilisearch/app/access-denied/page.tsx create mode 100644 starters/shopify-meilisearch/app/actions/cart.actions.ts create mode 100644 starters/shopify-meilisearch/app/actions/collection.actions.ts create mode 100644 starters/shopify-meilisearch/app/actions/favorites.actions.ts create mode 100644 starters/shopify-meilisearch/app/actions/page.actions.ts create mode 100644 starters/shopify-meilisearch/app/actions/product.actions.ts create mode 100644 starters/shopify-meilisearch/app/actions/reviews.actions.ts create mode 100644 starters/shopify-meilisearch/app/actions/user.actions.ts create mode 100644 starters/shopify-meilisearch/app/api/feed/sync/route.ts create mode 100644 starters/shopify-meilisearch/app/api/health/route.ts create mode 100644 starters/shopify-meilisearch/app/api/redirects/route.ts create mode 100644 starters/shopify-meilisearch/app/api/reviews/ai-summary/route.ts create mode 100644 starters/shopify-meilisearch/app/api/reviews/sync/route.ts create mode 100644 starters/shopify-meilisearch/app/category/clp/[slug]/[page]/page.tsx create mode 100644 starters/shopify-meilisearch/app/category/clp/[slug]/page.tsx create mode 100644 starters/shopify-meilisearch/app/category/plp/[slug]/page.tsx create mode 100644 starters/shopify-meilisearch/app/error.tsx create mode 100644 starters/shopify-meilisearch/app/favorites/page.tsx create mode 100644 starters/shopify-meilisearch/app/global-error.tsx create mode 100644 starters/shopify-meilisearch/app/globals.css create mode 100644 starters/shopify-meilisearch/app/home/[bucket]/page.tsx create mode 100644 starters/shopify-meilisearch/app/icon.png create mode 100644 starters/shopify-meilisearch/app/layout.tsx create mode 100644 starters/shopify-meilisearch/app/manifest.ts create mode 100644 starters/shopify-meilisearch/app/not-found.tsx create mode 100644 starters/shopify-meilisearch/app/opengraph-image.jpg create mode 100644 starters/shopify-meilisearch/app/pages/[slug]/metadata.ts create mode 100644 starters/shopify-meilisearch/app/pages/[slug]/page.tsx create mode 100644 starters/shopify-meilisearch/app/product/[slug]/draft/page.tsx create mode 100644 starters/shopify-meilisearch/app/product/[slug]/loading.tsx create mode 100644 starters/shopify-meilisearch/app/product/[slug]/metadata.ts create mode 100644 starters/shopify-meilisearch/app/product/[slug]/opengraph-image.tsx create mode 100644 starters/shopify-meilisearch/app/product/[slug]/page.tsx create mode 100644 starters/shopify-meilisearch/app/reviews/[slug]/metadata.ts create mode 100644 starters/shopify-meilisearch/app/reviews/[slug]/page.tsx create mode 100644 starters/shopify-meilisearch/app/robots.txt create mode 100644 starters/shopify-meilisearch/app/search/opengraph-image.tsx create mode 100644 starters/shopify-meilisearch/app/search/page.tsx create mode 100644 starters/shopify-meilisearch/app/settings/page.tsx create mode 100644 starters/shopify-meilisearch/app/sitemap.ts create mode 100644 starters/shopify-meilisearch/app/styles/megamenu.css create mode 100644 starters/shopify-meilisearch/app/styles/reset.css create mode 100644 starters/shopify-meilisearch/clients/replicate.ts create mode 100644 starters/shopify-meilisearch/clients/reviews.ts create mode 100644 starters/shopify-meilisearch/clients/search.ts create mode 100644 starters/shopify-meilisearch/clients/storefrontClient.ts create mode 100644 starters/shopify-meilisearch/components.json create mode 100644 starters/shopify-meilisearch/components/Accordion/Accordion.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Accordion/Accordion.tsx create mode 100644 starters/shopify-meilisearch/components/Alert/Alert.tsx create mode 100644 starters/shopify-meilisearch/components/AnnouncementBar/AnnouncementBar.stories.tsx create mode 100644 starters/shopify-meilisearch/components/AnnouncementBar/AnnouncementBar.tsx create mode 100644 starters/shopify-meilisearch/components/Badge/Badge.tsx create mode 100644 starters/shopify-meilisearch/components/Breadcrumb/Breadcrumb.tsx create mode 100644 starters/shopify-meilisearch/components/Breadcrumbs/Breadcrumbs.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Breadcrumbs/Breadcrumbs.tsx create mode 100644 starters/shopify-meilisearch/components/Button/Button.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Button/Button.tsx create mode 100644 starters/shopify-meilisearch/components/Button/ButtonNew.tsx create mode 100644 starters/shopify-meilisearch/components/CallToAction/CallToAction.stories.tsx create mode 100644 starters/shopify-meilisearch/components/CallToAction/CallToAction.tsx create mode 100644 starters/shopify-meilisearch/components/Card/Card.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Card/Card.tsx create mode 100644 starters/shopify-meilisearch/components/Carousel/Carousel.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Carousel/Carousel.tsx create mode 100644 starters/shopify-meilisearch/components/Checkbox/Checkbox.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Checkbox/Checkbox.tsx create mode 100644 starters/shopify-meilisearch/components/Dialog/Dialog.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Dialog/Dialog.tsx create mode 100644 starters/shopify-meilisearch/components/DropdownMenu/DropdownMenu.stories.tsx create mode 100644 starters/shopify-meilisearch/components/DropdownMenu/DropdownMenu.tsx create mode 100644 starters/shopify-meilisearch/components/ExpandableContent/ExpandableContent.tsx create mode 100644 starters/shopify-meilisearch/components/Footer/Footer.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Footer/Footer.tsx create mode 100644 starters/shopify-meilisearch/components/Form/Form.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Form/Form.tsx create mode 100644 starters/shopify-meilisearch/components/GenericModal/GenericModal.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/ArrowIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/CaretSortIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/CheckIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/ChevronIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/CloseIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/FavoritesIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/FiltersIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/HeartIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/Icons.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/RobotIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/SearchIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/StarIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Icons/ThinSearchIcon.tsx create mode 100644 starters/shopify-meilisearch/components/Input/Input.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Input/Input.tsx create mode 100644 starters/shopify-meilisearch/components/Label/Label.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Label/Label.tsx create mode 100644 starters/shopify-meilisearch/components/LoadingDots/LoadingDots.stories.tsx create mode 100644 starters/shopify-meilisearch/components/LoadingDots/LoadingDots.tsx create mode 100644 starters/shopify-meilisearch/components/Logo/Logo.tsx create mode 100644 starters/shopify-meilisearch/components/Modals/LoginModal.tsx create mode 100644 starters/shopify-meilisearch/components/Modals/Modals.tsx create mode 100644 starters/shopify-meilisearch/components/Modals/ReviewModal.tsx create mode 100644 starters/shopify-meilisearch/components/Modals/SearchModal.tsx create mode 100644 starters/shopify-meilisearch/components/Modals/SignupModal.tsx create mode 100644 starters/shopify-meilisearch/components/NavigationBar/Autocomplete.tsx create mode 100644 starters/shopify-meilisearch/components/NavigationBar/Cart.tsx create mode 100644 starters/shopify-meilisearch/components/NavigationBar/Favorites.tsx create mode 100644 starters/shopify-meilisearch/components/NavigationBar/NavigationBar.tsx create mode 100644 starters/shopify-meilisearch/components/NavigationBar/NavigationItem.tsx create mode 100644 starters/shopify-meilisearch/components/NavigationBar/OpenCartButton.tsx create mode 100644 starters/shopify-meilisearch/components/NavigationBar/SearchButton.tsx create mode 100644 starters/shopify-meilisearch/components/NavigationBar/mobileInlineScript.ts create mode 100644 starters/shopify-meilisearch/components/NavigationBar/types.ts create mode 100644 starters/shopify-meilisearch/components/NavigationBar/variants/ImageGridVariant.tsx create mode 100644 starters/shopify-meilisearch/components/NavigationBar/variants/TextGridVariant.tsx create mode 100644 starters/shopify-meilisearch/components/NavigationBar/variants/TextImageGridVariant.tsx create mode 100644 starters/shopify-meilisearch/components/Pagination/Pagination.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Pagination/Pagination.tsx create mode 100644 starters/shopify-meilisearch/components/ProductCard/ProductCard.tsx create mode 100644 starters/shopify-meilisearch/components/ProductCard/QuickAdd.tsx create mode 100644 starters/shopify-meilisearch/components/ProductCard/QuickAddButton.tsx create mode 100644 starters/shopify-meilisearch/components/ProfileMenu/AuthActions.tsx create mode 100644 starters/shopify-meilisearch/components/ProfileMenu/ProfileBar.tsx create mode 100644 starters/shopify-meilisearch/components/ProfileMenu/ProfileMenu.tsx create mode 100644 starters/shopify-meilisearch/components/Select/Select.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Select/Select.tsx create mode 100644 starters/shopify-meilisearch/components/Sheet/Sheet.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Sheet/Sheet.tsx create mode 100644 starters/shopify-meilisearch/components/Skeleton/Skeleton.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Skeleton/Skeleton.tsx create mode 100644 starters/shopify-meilisearch/components/Spinner/Spinner.stories.tsx create mode 100644 starters/shopify-meilisearch/components/Spinner/Spinner.tsx create mode 100644 starters/shopify-meilisearch/components/Textarea/Textarea.tsx create mode 100644 starters/shopify-meilisearch/constants/index.ts create mode 100644 starters/shopify-meilisearch/e2e/example.spec.ts rename {apps/web => starters/shopify-meilisearch}/env.mjs (100%) create mode 100644 starters/shopify-meilisearch/jest.config.js create mode 100644 starters/shopify-meilisearch/jest.setup.js create mode 100644 starters/shopify-meilisearch/lib/meilisearch/filterBuilder.test.ts create mode 100644 starters/shopify-meilisearch/lib/meilisearch/filterBuilder.ts rename {packages/search => starters/shopify-meilisearch/lib}/meilisearch/index.ts (100%) create mode 100644 starters/shopify-meilisearch/lib/reviews/index.ts create mode 100644 starters/shopify-meilisearch/lib/reviews/types.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/fragments/cart.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/fragments/collection.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/fragments/customer.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/fragments/image.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/fragments/menu.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/fragments/page.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/fragments/product.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/fragments/seo.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/index.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/mutations/cart.storefront.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/mutations/customer.storefront.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/mutations/product-feed.admin.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/mutations/webhook.admin.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/normalize.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/queries/cart.storefront.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/queries/collection.storefront.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/queries/customer.storefront.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/queries/menu.storefront.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/queries/page.storefront.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/queries/product-feed.admin.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/queries/product.admin.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/queries/product.storefront.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/types/admin/admin-2024-01.schema.json create mode 100644 starters/shopify-meilisearch/lib/shopify/types/admin/admin.generated.d.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/types/admin/admin.types.d.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/types/index.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/types/storefront-2024-01.schema.json create mode 100644 starters/shopify-meilisearch/lib/shopify/types/storefront.generated.d.ts create mode 100644 starters/shopify-meilisearch/lib/shopify/types/storefront.types.d.ts create mode 100644 starters/shopify-meilisearch/middleware.ts create mode 100644 starters/shopify-meilisearch/next-env.d.ts rename {apps/web => starters/shopify-meilisearch}/next.config.mjs (100%) create mode 100644 starters/shopify-meilisearch/package.json create mode 100644 starters/shopify-meilisearch/playwright.config.ts create mode 100644 starters/shopify-meilisearch/postcss.config.js create mode 100644 starters/shopify-meilisearch/prettier.config.js create mode 100644 starters/shopify-meilisearch/public/category-placeholder-1.svg create mode 100644 starters/shopify-meilisearch/public/category-placeholder-2.svg create mode 100644 starters/shopify-meilisearch/public/category-placeholder-3.svg create mode 100644 starters/shopify-meilisearch/public/category-placeholder-4.svg create mode 100644 starters/shopify-meilisearch/public/category-placeholder-5.svg create mode 100644 starters/shopify-meilisearch/public/category-placeholder-6.svg create mode 100644 starters/shopify-meilisearch/public/default-product-image.svg create mode 100644 starters/shopify-meilisearch/public/demo-categories-data.json create mode 100644 starters/shopify-meilisearch/public/demo-data.json create mode 100644 starters/shopify-meilisearch/public/demo-product-reviews-data.json create mode 100644 starters/shopify-meilisearch/public/fonts/Inter-Black.ttf create mode 100644 starters/shopify-meilisearch/public/fonts/Inter-Bold.ttf create mode 100644 starters/shopify-meilisearch/public/fonts/Inter-ExtraBold.ttf create mode 100644 starters/shopify-meilisearch/public/fonts/Inter-ExtraLight.ttf create mode 100644 starters/shopify-meilisearch/public/fonts/Inter-Light.ttf create mode 100644 starters/shopify-meilisearch/public/fonts/Inter-Medium.ttf create mode 100644 starters/shopify-meilisearch/public/fonts/Inter-Regular.ttf create mode 100644 starters/shopify-meilisearch/public/fonts/Inter-SemiBold.ttf create mode 100644 starters/shopify-meilisearch/public/fonts/Inter-Thin.ttf create mode 100644 starters/shopify-meilisearch/public/menu/beauty-1.png create mode 100644 starters/shopify-meilisearch/public/menu/beauty-2.png create mode 100644 starters/shopify-meilisearch/public/menu/beauty-3.png create mode 100644 starters/shopify-meilisearch/public/menu/beauty-4.png create mode 100644 starters/shopify-meilisearch/public/menu/beauty-5.png create mode 100644 starters/shopify-meilisearch/public/menu/electronics-1.png create mode 100644 starters/shopify-meilisearch/public/menu/electronics-2.png create mode 100644 starters/shopify-meilisearch/public/menu/electronics-3.png create mode 100644 starters/shopify-meilisearch/public/menu/electronics-4.png create mode 100644 starters/shopify-meilisearch/public/menu/furniture-1.png create mode 100644 starters/shopify-meilisearch/public/menu/furniture-2.png create mode 100644 starters/shopify-meilisearch/public/menu/furniture-3.png create mode 100644 starters/shopify-meilisearch/public/menu/furniture-4.png create mode 100644 starters/shopify-meilisearch/redirects/bloom-filter.json create mode 100644 starters/shopify-meilisearch/redirects/generate-bloom-filter.ts create mode 100644 starters/shopify-meilisearch/redirects/new-redirects.json create mode 100644 starters/shopify-meilisearch/redirects/redirects.json create mode 100644 starters/shopify-meilisearch/report-bundle-size.js create mode 100644 starters/shopify-meilisearch/reset.d.ts create mode 100644 starters/shopify-meilisearch/shopify-webhooks.d.ts create mode 100644 starters/shopify-meilisearch/stores/addProductStore.ts create mode 100644 starters/shopify-meilisearch/stores/cartStore.ts create mode 100644 starters/shopify-meilisearch/stores/filterTransitionStore.ts create mode 100644 starters/shopify-meilisearch/stores/filtersStore.ts create mode 100644 starters/shopify-meilisearch/stores/modalStore.ts create mode 100644 starters/shopify-meilisearch/stores/userStore.ts create mode 100644 starters/shopify-meilisearch/tailwind.config.ts create mode 100644 starters/shopify-meilisearch/tsconfig.json create mode 100644 starters/shopify-meilisearch/types/index.ts create mode 100644 starters/shopify-meilisearch/utils/abTesting.ts create mode 100644 starters/shopify-meilisearch/utils/authenticate-api-route.ts create mode 100644 starters/shopify-meilisearch/utils/cn.ts create mode 100644 starters/shopify-meilisearch/utils/compare-hmac.ts create mode 100644 starters/shopify-meilisearch/utils/demoUtils.ts create mode 100644 starters/shopify-meilisearch/utils/enrich-product.ts create mode 100644 starters/shopify-meilisearch/utils/getCookie.ts create mode 100644 starters/shopify-meilisearch/utils/getVercelFlagOverrides.ts create mode 100644 starters/shopify-meilisearch/utils/highlightedText.tsx create mode 100644 starters/shopify-meilisearch/utils/makeKeywords.ts create mode 100644 starters/shopify-meilisearch/utils/mapCurrencyToSign.ts create mode 100644 starters/shopify-meilisearch/utils/opt-in.ts create mode 100644 starters/shopify-meilisearch/utils/productOptionsUtils.ts create mode 100644 starters/shopify-meilisearch/utils/slug-name.ts create mode 100644 starters/shopify-meilisearch/utils/useAutocomplete.ts create mode 100644 starters/shopify-meilisearch/utils/useHierarchicalMenu.ts create mode 100644 starters/shopify-meilisearch/utils/useReadMore.ts create mode 100644 starters/shopify-meilisearch/vercel.json create mode 100644 starters/shopify-meilisearch/views/Cart/CartItem.tsx create mode 100644 starters/shopify-meilisearch/views/Cart/CartSheet.tsx create mode 100644 starters/shopify-meilisearch/views/Cart/CartView.tsx create mode 100644 starters/shopify-meilisearch/views/Cart/ChangeQuantityButton.tsx create mode 100644 starters/shopify-meilisearch/views/Cart/DeleteButton.tsx create mode 100644 starters/shopify-meilisearch/views/Category/CategoryView.tsx create mode 100644 starters/shopify-meilisearch/views/Category/PageSkeleton.tsx create mode 100644 starters/shopify-meilisearch/views/DemoModeAlert.tsx create mode 100644 starters/shopify-meilisearch/views/DraftToolbar.tsx create mode 100644 starters/shopify-meilisearch/views/FlagValues.tsx create mode 100644 starters/shopify-meilisearch/views/GithubBadge.tsx create mode 100644 starters/shopify-meilisearch/views/Homepage/BestOffersSection.tsx create mode 100644 starters/shopify-meilisearch/views/Homepage/CarouselSection.tsx create mode 100644 starters/shopify-meilisearch/views/Homepage/CategoriesSection.tsx create mode 100644 starters/shopify-meilisearch/views/Homepage/EverythingUnderSection.tsx create mode 100644 starters/shopify-meilisearch/views/Homepage/HeroSection.tsx create mode 100644 starters/shopify-meilisearch/views/Homepage/ProductsWeekSection.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/CategoryFacet.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/Controls.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/Facet.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/FacetsContent.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/FacetsDesktop.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/FacetsMobile.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/HideFilters.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/HitsSection.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/PageSkeleton.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/PaginationSection.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/PriceFacet.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/RatingFacet.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/SearchFacet.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/Sorter.tsx create mode 100644 starters/shopify-meilisearch/views/Listing/composeFilters.test.ts create mode 100644 starters/shopify-meilisearch/views/Listing/composeFilters.ts create mode 100644 starters/shopify-meilisearch/views/Product/AddToCartButton.tsx create mode 100644 starters/shopify-meilisearch/views/Product/BackButton.tsx create mode 100644 starters/shopify-meilisearch/views/Product/CenterImageSection.tsx create mode 100644 starters/shopify-meilisearch/views/Product/FaqSection.tsx create mode 100644 starters/shopify-meilisearch/views/Product/FavoriteMarker.tsx create mode 100644 starters/shopify-meilisearch/views/Product/PageSkeleton.tsx create mode 100644 starters/shopify-meilisearch/views/Product/ProductAddedAlert.tsx create mode 100644 starters/shopify-meilisearch/views/Product/ProductImages.tsx create mode 100644 starters/shopify-meilisearch/views/Product/ProductTitle.tsx create mode 100644 starters/shopify-meilisearch/views/Product/ReviewButton.tsx create mode 100644 starters/shopify-meilisearch/views/Product/ReviewCard.tsx create mode 100644 starters/shopify-meilisearch/views/Product/ReviewsSection.tsx create mode 100644 starters/shopify-meilisearch/views/Product/RightSection.tsx create mode 100644 starters/shopify-meilisearch/views/Product/SideImages.tsx create mode 100644 starters/shopify-meilisearch/views/Product/SimilarProductsSection.tsx create mode 100644 starters/shopify-meilisearch/views/Product/SimilarProductsSectionSkeleton.tsx create mode 100644 starters/shopify-meilisearch/views/Product/StarRating.tsx create mode 100644 starters/shopify-meilisearch/views/Product/Variant.tsx create mode 100644 starters/shopify-meilisearch/views/Product/VariantsSection.tsx create mode 100644 starters/shopify-meilisearch/views/Search/SearchView.tsx create mode 100644 starters/shopify-meilisearch/views/Settings/ProfileForm.tsx create mode 100644 starters/shopify-meilisearch/views/Settings/SettingsView.tsx create mode 100644 starters/shopify-meilisearch/views/ThirdParties.tsx delete mode 100644 tsconfig.json diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index bf007743..2fcb9588 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -8,10 +8,23 @@ on: jobs: build: + strategy: + matrix: + app: [shopify-meilisearch, shopify-algolia] + include: + - app: shopify-meilisearch + working-directory: ./starters/shopify-meilisearch + - app: shopify-algolia + working-directory: ./starters/shopify-algolia + environment: production - name: Build and Test + name: Build and Test (${{ matrix.app }}) timeout-minutes: 15 runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ matrix.app }}-${{ github.ref }} + cancel-in-progress: true + env: SKIP_ENV_VALIDATION: true TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} @@ -35,7 +48,7 @@ jobs: - uses: actions/cache@v2 with: path: "**/node_modules" - key: ${{ runner.os }}-check-modules-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-${{ matrix.app }}-modules-${{ hashFiles('**/yarn.lock') }} - name: Install dependencies run: yarn install --frozen-lockfile --prefer-offline @@ -43,8 +56,18 @@ jobs: - name: Licenses check run: npx --yes license-checker-rseidelsohn --production --excludePrivatePackages --onlyAllow "MPL-2.0;UNKNOWN;MIT;Apache;AAL;BSD;Artistic;CC0;ISC;ISCL;PostgreSQL License;Public Domain;Unlicense;UPL;W3C;WTFPL;Python;CC-;BlueOak" - - name: Build - run: yarn build - - name: Test run: yarn test + working-directory: ${{ matrix.working-directory }} + + - name: Lint + run: yarn lint + working-directory: ${{ matrix.working-directory }} + + - name: Format + run: yarn format + working-directory: ${{ matrix.working-directory }} + + - name: Build + run: yarn build + working-directory: ${{ matrix.working-directory }} diff --git a/.github/workflows/nextjs_bundle_analysis.yml b/.github/workflows/nextjs_bundle_analysis.yml index 67390625..92590400 100644 --- a/.github/workflows/nextjs_bundle_analysis.yml +++ b/.github/workflows/nextjs_bundle_analysis.yml @@ -11,14 +11,24 @@ on: - develop workflow_dispatch: -defaults: - run: - # change this if your nextjs app does not live at the root of the repo - working-directory: ./apps/web/ - jobs: analyze: + strategy: + matrix: + app: [shopify-meilisearch, shopify-algolia] + include: + - app: shopify-meilisearch + working-directory: ./starters/shopify-meilisearch + - app: shopify-algolia + working-directory: ./starters/shopify-algolia + environment: production + name: Analyze (${{ matrix.app }}) + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ matrix.app }}-${{ github.ref }} + cancel-in-progress: true + env: SKIP_ENV_VALIDATION: true TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} @@ -30,7 +40,7 @@ jobs: MEILISEARCH_HOST: ${{ secrets.MEILISEARCH_HOST }} SHOPIFY_APP_API_SECRET_KEY: ${{ secrets.SHOPIFY_APP_API_SECRET_KEY }} REPLICATE_API_KEY: ${{ secrets.REPLICATE_API_KEY }} - runs-on: ubuntu-latest + steps: - uses: actions/checkout@v4 - run: echo "node_version=$(cat ../../.github/nodejs.version)" >> $GITHUB_ENV @@ -42,7 +52,7 @@ jobs: - uses: actions/cache@v2 with: path: "**/node_modules" - key: ${{ runner.os }}-bundle-modules-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-${{ matrix.app }}-bundle-modules-${{ hashFiles('**/yarn.lock') }} - name: Install dependencies run: yarn install --frozen-lockfile --prefer-offline @@ -51,28 +61,25 @@ jobs: uses: actions/cache@v3 id: restore-build-cache env: - cache-name: cache-next-build + cache-name: cache-next-build-${{ matrix.app }} with: - path: .next/cache - # change this if you prefer a more strict cache + path: ${{ matrix.working-directory }}/.next/cache key: ${{ runner.os }}-build-${{ env.cache-name }} - name: Build next.js app env: SKIP_BUILD_PRODUCT_REDIRECTS: 1 - # change this if your site requires a custom build command - run: cd ../../ && yarn build && cd - + run: cd ${{ matrix.working-directory }} && yarn build && cd - - # Here's the first place where next-bundle-analysis' own script is used - # This step pulls the raw bundle stats for the current bundle - name: Analyze bundle + working-directory: ${{ matrix.working-directory }} run: node report-bundle-size.js - name: Upload bundle uses: actions/upload-artifact@v3 with: - name: bundle - path: .next/analyze/__bundle_analysis.json + name: bundle-${{ matrix.app }} + path: ${{ matrix.working-directory }}/.next/analyze/__bundle_analysis.json - name: Download base branch bundle stats uses: dawidd6/action-download-artifact@v2 @@ -80,35 +87,24 @@ jobs: with: workflow: nextjs_bundle_analysis.yml branch: ${{ github.event.pull_request.base.ref }} - path: .next/analyze/base - - # And here's the second place - this runs after we have both the current and - # base branch bundle stats, and will compare them to determine what changed. - # There are two configurable arguments that come from package.json: - # - # - budget: optional, set a budget (bytes) against which size changes are measured - # it's set to 350kb here by default, as informed by the following piece: - # https://infrequently.org/2021/03/the-performance-inequality-gap/ - # - # - red-status-percentage: sets the percent size increase where you get a red - # status indicator, defaults to 20% - # - # Either of these arguments can be changed or removed by editing the `nextBundleAnalysis` - # entry in your package.json file. + name: bundle-${{ matrix.app }} + path: ${{ matrix.working-directory }}/.next/analyze/base + - name: Compare with base branch bundle if: success() && github.event.number + working-directory: ${{ matrix.working-directory }} run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare - name: Get comment body id: get-comment-body if: success() && github.event.number - uses: actions/github-script@v6 - with: - result-encoding: string - script: | - const fs = require('fs') - const comment = fs.readFileSync('.next/analyze/__bundle_analysis_comment.txt', 'utf8') - core.setOutput('body', comment) + working-directory: ${{ matrix.working-directory }} + run: | + body=$(cat .next/analyze/__bundle_analysis_comment.txt) + body="${body//'%'/'%25'}" + body="${body//$'\n'/'%0A'}" + body="${body//$'\r'/'%0D'}" + echo "::set-output name=body::$body" - name: Find Comment uses: peter-evans/find-comment@v2 @@ -116,20 +112,17 @@ jobs: id: fc with: issue-number: ${{ github.event.number }} - body-includes: "" - - - name: Create Comment - uses: peter-evans/create-or-update-comment@v3 - if: success() && github.event.number && steps.fc.outputs.comment-id == 0 - with: - issue-number: ${{ github.event.number }} - body: ${{ steps.get-comment-body.outputs.body }} + comment-author: "github-actions[bot]" + body-includes: "" - - name: Update Comment + - name: Create or update comment uses: peter-evans/create-or-update-comment@v3 - if: success() && github.event.number && steps.fc.outputs.comment-id != 0 + if: success() && github.event.number with: issue-number: ${{ github.event.number }} - body: ${{ steps.get-comment-body.outputs.body }} + body: | + + # Next.js Bundle Analysis (${{ matrix.app }}) + ${{ steps.get-comment-body.outputs.body }} comment-id: ${{ steps.fc.outputs.comment-id }} edit-mode: replace diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index a4587892..cbb24759 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -7,9 +7,20 @@ on: - develop pull_request: null workflow_dispatch: null + jobs: test: + strategy: + matrix: + app: [shopify-meilisearch, shopify-algolia] + include: + - app: shopify-meilisearch + working-directory: ./starters/shopify-meilisearch + - app: shopify-algolia + working-directory: ./starters/shopify-algolia + environment: test + name: E2E Tests (${{ matrix.app }}) env: NODE_ENV: test SKIP_ENV_VALIDATION: true @@ -25,6 +36,10 @@ jobs: FLAGS_SECRET: EAMwX-AhlPipEaZfTc-24bxAZ7BvLikwuIV2Zq7FP64 timeout-minutes: 60 runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ matrix.app }}-${{ github.ref }} + cancel-in-progress: true + steps: - uses: actions/checkout@v4 - run: echo "node_version=$(cat .github/nodejs.version)" >> $GITHUB_ENV @@ -36,17 +51,21 @@ jobs: - uses: actions/cache@v2 with: path: "**/node_modules" - key: ${{ runner.os }}-playwright-modules-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-${{ matrix.app }}-playwright-modules-${{ hashFiles('**/yarn.lock') }} - name: Install dependencies run: yarn install --frozen-lockfile --prefer-offline + - name: Install Playwright Browsers run: yarn playwright install + - name: Run Playwright tests run: yarn e2e + working-directory: ${{ matrix.working-directory }} + - uses: actions/upload-artifact@v3 if: always() with: - name: playwright-report - path: playwright-report/ + name: playwright-report-${{ matrix.app }} + path: ${{ matrix.working-directory }}/playwright-report/ retention-days: 30 diff --git a/.gitignore b/.gitignore index dd8c585a..cfe06e1c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,19 +5,6 @@ node_modules .pnp .pnp.js -# testing -coverage - -# next.js -.next/ -out/ -build - -build/** -dist/** -**/dist/** -.next/** - # misc .DS_Store *.pem @@ -33,9 +20,6 @@ yarn-error.log* .env.development.local .env.test.local .env.production.local -/test-results/ -/playwright-report/ -/playwright/.cache/ **/**/.env.* **/**/.env @@ -45,9 +29,5 @@ yarn-error.log* .turbo -.vitepress/cache/ -apps/docs/.vitepress/cache/ -apps/docs/.vitepress/config.mts.timestamp-* -apps/docs/.vitepress/dist/ .vercel .env*.local diff --git a/apps/web/.eslintrc.js b/apps/web/.eslintrc.js deleted file mode 100644 index c3d14328..00000000 --- a/apps/web/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ["@enterprise-commerce/eslint-config-custom/base"], -} diff --git a/apps/web/.gitignore b/apps/web/.gitignore deleted file mode 100644 index ce936515..00000000 --- a/apps/web/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ - -/.npm-only-allow - -storybook-static/ -playwright-report/ \ No newline at end of file diff --git a/apps/web/clients/replicate.ts b/apps/web/clients/replicate.ts deleted file mode 100644 index a6b9c512..00000000 --- a/apps/web/clients/replicate.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { env } from "env.mjs" -import Replicate from "replicate" - -const replicateClientSingleton = () => { - if (!env.REPLICATE_API_KEY) return null - return new Replicate({ - auth: env.REPLICATE_API_KEY || "", - }) -} - -declare global { - var replicate: undefined | ReturnType -} - -const replicate = globalThis.replicate ?? replicateClientSingleton() - -export { replicate } - -if (process.env.NODE_ENV !== "production") globalThis.replicate = replicate diff --git a/apps/web/clients/search.ts b/apps/web/clients/search.ts deleted file mode 100644 index f6ba5fac..00000000 --- a/apps/web/clients/search.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { env } from "env.mjs" -import { meilisearch as searchClient } from "@enterprise-commerce/search-meilisearch" - -export const meilisearch: ReturnType = - globalThis.meilisearch ?? - searchClient({ - host: env.MEILISEARCH_HOST || "", - adminApiKey: env.MEILISEARCH_ADMIN_KEY || "", - }) - -if (process.env.NODE_ENV !== "production") globalThis.meilisearch = meilisearch diff --git a/apps/web/tailwind.config.ts b/apps/web/tailwind.config.ts deleted file mode 100644 index 941de9fc..00000000 --- a/apps/web/tailwind.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { Config } from "tailwindcss" -import sharedConfig from "../../packages/tailwind-config/tailwind.config.js" - -/** @type {import('tailwindcss').Config} */ -const config: Pick = { - content: [ - "./index.html", - "./src/**/*.{js,ts,jsx,tsx}", - "./**/*.{js,ts,jsx,tsx}", - "./dist/**/*.{js,ts,jsx,tsx}", - "./app/**/*.{js,ts,jsx,tsx,mdx}", - "./pages/**/*.{js,ts,jsx,tsx,mdx}", - "./components/**/*.{js,ts,jsx,tsx,mdx}", - "./src/**/*.{js,ts,jsx,tsx,mdx}", - ], - corePlugins: { - preflight: false, - }, - presets: [sharedConfig], -} - -export default config diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json deleted file mode 100644 index ca74703a..00000000 --- a/apps/web/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "@enterprise-commerce/tsconfig/nextjs.json", - "compilerOptions": { - "plugins": [{ "name": "next" }], - "baseUrl": "." - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] -} diff --git a/package.json b/package.json index b670bc34..ee999409 100644 --- a/package.json +++ b/package.json @@ -3,16 +3,12 @@ "version": "link", "private": true, "workspaces": [ - "packages/**", - "apps/**" + "starters/**" ], "scripts": { - "build": "turbo run build", - "dev": "turbo run dev", "lint": "turbo run lint", "test": "turbo run test", "e2e": "turbo run e2e", - "format": "prettier --write \"**/*.{ts,tsx,md}\"", "commitlint": "commitlint --edit" }, "devDependencies": { @@ -24,7 +20,6 @@ "@semantic-release/release-notes-generator": "^12.1.0", "@commitlint/cli": "19.2.1", "@commitlint/config-conventional": "19.1.0", - "@enterprise-commerce/tsconfig": "*", "@jest/globals": "^29.7.0", "@t3-oss/env-core": "^0.9.2", "@total-typescript/ts-reset": "^0.5.1", diff --git a/packages/core/.eslintignore b/packages/core/.eslintignore deleted file mode 100644 index 5c87d8c8..00000000 --- a/packages/core/.eslintignore +++ /dev/null @@ -1,12 +0,0 @@ -.next -node_modules -gql - -dist -/dist -dist/* -dist/**/* - -**/types/**.*.d.ts -**/types/*.d.ts -platform/shopify/types \ No newline at end of file diff --git a/packages/core/.eslintrc.js b/packages/core/.eslintrc.js deleted file mode 100644 index c3d14328..00000000 --- a/packages/core/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ["@enterprise-commerce/eslint-config-custom/base"], -} diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js deleted file mode 100644 index 99e66d0a..00000000 --- a/packages/core/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('ts-jest').JestConfigWithTsJest} */ -module.exports = { - preset: "ts-jest", - testEnvironment: "node", -} diff --git a/packages/core/package.json b/packages/core/package.json deleted file mode 100644 index bcaa5826..00000000 --- a/packages/core/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "@enterprise-commerce/core", - "version": "0.0.0", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", - "sideEffects": false, - "license": "MIT", - "files": [ - "dist/**" - ], - "scripts": { - "prebuild": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", - "build": "cross-env FORCE_COLOR=1 tsup **/*.ts --format esm,cjs --dts --external react", - "dev": "yarn clean && cross-env FORCE_COLOR=1 tsup **/*.ts --format esm,cjs --watch --dts --external react --onSuccess 'node dist/index.mjs about'", - "lint": "cross-env FORCE_COLOR=1 eslint .", - "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", - "test": "cross-env FORCE_COLOR=1 jest --passWithNoTests", - "codegen": "graphql-codegen && graphql-codegen -p admin" - }, - "dependencies": { - "@shopify/admin-api-client": "0.2.3", - "@shopify/storefront-api-client": "0.2.3" - }, - "devDependencies": { - "graphql": "^16.8.1", - "@graphql-codegen/cli": "5.0.2", - "@graphql-codegen/client-preset": "4.1.0", - "@shopify/api-codegen-preset": "0.0.6" - } -} diff --git a/packages/core/platform/index.ts b/packages/core/platform/index.ts deleted file mode 100644 index 684da961..00000000 --- a/packages/core/platform/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { createShopifyClient } from "./shopify" - -type Strategy = "shopify" - -interface CreateStorefrontClientProps { - strategy: Strategy - storeDomain: string - storefrontAccessToken?: string - adminAccessToken?: string -} - -export function createStorefrontClient({ storefrontAccessToken, adminAccessToken, storeDomain, strategy }: CreateStorefrontClientProps) { - switch (strategy) { - case "shopify": - return createShopifyClient({ storeDomain, storefrontAccessToken, adminAccessToken }) - default: - throw new Error("Unknown strategy used for creating storefront client") - } -} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json deleted file mode 100644 index f97735fa..00000000 --- a/packages/core/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "@enterprise-commerce/tsconfig/base.json", - "include": ["."], - "exclude": ["dist", "build", "node_modules"] -} diff --git a/packages/eslint-config-custom/package.json b/packages/eslint-config-custom/package.json deleted file mode 100644 index a0133565..00000000 --- a/packages/eslint-config-custom/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "@enterprise-commerce/eslint-config-custom", - "license": "MIT", - "version": "0.0.0", - "private": true, - "devDependencies": { - "@vercel/style-guide": "^5.0.0", - "eslint-config-turbo": "^1.10.12", - "eslint": "8.54.0", - "eslint-config-next": "14.0.3", - "eslint-config-prettier": "^9.0.0", - "eslint-config-react-app": "^7.0.1", - "eslint-plugin-import": "^2.29.0", - "eslint-plugin-react": "7.33.2", - "eslint-plugin-storybook": "^0.6.15", - "eslint-plugin-tailwindcss": "^3.13.0", - "@typescript-eslint/eslint-plugin": "^6.12.0", - "@typescript-eslint/parser": "^6.12.0" - } -} diff --git a/packages/reviews/.eslintignore b/packages/reviews/.eslintignore deleted file mode 100644 index 7cf98316..00000000 --- a/packages/reviews/.eslintignore +++ /dev/null @@ -1,9 +0,0 @@ -node_modules - -dist -/dist -dist/* -dist/**/* - -**/types/**.*.d.ts -**/types/*.d.ts diff --git a/packages/reviews/.eslintrc.js b/packages/reviews/.eslintrc.js deleted file mode 100644 index c3d14328..00000000 --- a/packages/reviews/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ["@enterprise-commerce/eslint-config-custom/base"], -} diff --git a/packages/reviews/package.json b/packages/reviews/package.json deleted file mode 100644 index b29bb844..00000000 --- a/packages/reviews/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "@enterprise-commerce/reviews", - "version": "1.0.0", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", - "sideEffects": false, - "license": "MIT", - "files": [ - "dist/**" - ], - "scripts": { - "prebuild": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", - "build": "cross-env FORCE_COLOR=1 tsup **/*.ts --format esm,cjs --dts --external react", - "dev": "rm -rf dist && cross-env FORCE_COLOR=1 tsup **/*.ts --format esm,cjs --watch --dts --external react --onSuccess 'node dist/index.mjs about'", - "lint": "cross-env FORCE_COLOR=1 eslint .", - "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", - "test": "cross-env FORCE_COLOR=1 jest --passWithNoTests" - } -} diff --git a/packages/reviews/tsconfig.json b/packages/reviews/tsconfig.json deleted file mode 100644 index f97735fa..00000000 --- a/packages/reviews/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "@enterprise-commerce/tsconfig/base.json", - "include": ["."], - "exclude": ["dist", "build", "node_modules"] -} diff --git a/packages/search/meilisearch/.eslintignore b/packages/search/meilisearch/.eslintignore deleted file mode 100644 index 7cf98316..00000000 --- a/packages/search/meilisearch/.eslintignore +++ /dev/null @@ -1,9 +0,0 @@ -node_modules - -dist -/dist -dist/* -dist/**/* - -**/types/**.*.d.ts -**/types/*.d.ts diff --git a/packages/search/meilisearch/.eslintrc.js b/packages/search/meilisearch/.eslintrc.js deleted file mode 100644 index c3d14328..00000000 --- a/packages/search/meilisearch/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ["@enterprise-commerce/eslint-config-custom/base"], -} diff --git a/packages/search/meilisearch/jest.config.js b/packages/search/meilisearch/jest.config.js deleted file mode 100644 index 99e66d0a..00000000 --- a/packages/search/meilisearch/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('ts-jest').JestConfigWithTsJest} */ -module.exports = { - preset: "ts-jest", - testEnvironment: "node", -} diff --git a/packages/search/meilisearch/package.json b/packages/search/meilisearch/package.json deleted file mode 100644 index 8b3fd4c5..00000000 --- a/packages/search/meilisearch/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@enterprise-commerce/search-meilisearch", - "version": "0.0.0", - "license": "MIT", - "files": [ - "dist/**" - ], - "sideEffects": false, - "scripts": { - "prebuild": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", - "build": "cross-env FORCE_COLOR=1 tsup **/*.ts --format esm,cjs --dts --external react", - "dev": "yarn clean && cross-env FORCE_COLOR=1 tsup **/*.ts --format esm,cjs --watch --dts --external react --onSuccess 'node dist/index.mjs about'", - "lint": "cross-env FORCE_COLOR=1 eslint .", - "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", - "test": "cross-env FORCE_COLOR=1 jest --passWithNoTests", - "codegen": "graphql-codegen && graphql-codegen -p admin" - }, - "dependencies": { - "meilisearch": "^0.41.0" - } -} diff --git a/packages/search/meilisearch/tsconfig.json b/packages/search/meilisearch/tsconfig.json deleted file mode 100644 index f97735fa..00000000 --- a/packages/search/meilisearch/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "@enterprise-commerce/tsconfig/base.json", - "include": ["."], - "exclude": ["dist", "build", "node_modules"] -} diff --git a/packages/tailwind-config/package.json b/packages/tailwind-config/package.json deleted file mode 100644 index 8ed43f76..00000000 --- a/packages/tailwind-config/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@enterprise-commerce/tailwind-config", - "version": "1.0.0", - "private": true, - "exports": { - ".": "./tailwind.config.ts" - }, - "devDependencies": { - "@enterprise-commerce/tsconfig": "*" - } -} diff --git a/packages/tailwind-config/tsconfig.json b/packages/tailwind-config/tsconfig.json deleted file mode 100644 index f97735fa..00000000 --- a/packages/tailwind-config/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "@enterprise-commerce/tsconfig/base.json", - "include": ["."], - "exclude": ["dist", "build", "node_modules"] -} diff --git a/packages/tsconfig/base.json b/packages/tsconfig/base.json deleted file mode 100644 index 8f8d63d5..00000000 --- a/packages/tsconfig/base.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "Default", - "compilerOptions": { - "composite": false, - "declaration": true, - "declarationMap": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "allowImportingTsExtensions": true, - "noEmit": true, - "inlineSources": false, - "isolatedModules": true, - "module": "ESNext", - "moduleResolution": "Bundler", - "noUnusedLocals": false, - "noUnusedParameters": false, - "preserveWatchOutput": true, - "skipLibCheck": true, - "strict": true, - "strictNullChecks": true - }, - "exclude": ["node_modules"] -} diff --git a/packages/tsconfig/nextjs.json b/packages/tsconfig/nextjs.json deleted file mode 100644 index d5010a1b..00000000 --- a/packages/tsconfig/nextjs.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "Next.js", - "extends": "./base.json", - "compilerOptions": { - "plugins": [{ "name": "next" }], - "allowJs": true, - "declaration": false, - "declarationMap": false, - "incremental": true, - "jsx": "preserve", - "lib": ["dom", "dom.iterable", "esnext"], - "module": "esnext", - "noEmit": true, - "resolveJsonModule": true, - "strict": false, - "target": "es5" - }, - "include": ["src", "next-env.d.ts"], - "exclude": ["node_modules"] -} diff --git a/packages/tsconfig/package.json b/packages/tsconfig/package.json deleted file mode 100644 index fa9a7da8..00000000 --- a/packages/tsconfig/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "@enterprise-commerce/tsconfig", - "version": "0.0.0", - "private": true, - "license": "MIT" -} diff --git a/packages/tsconfig/react-library.json b/packages/tsconfig/react-library.json deleted file mode 100644 index 044ee3ea..00000000 --- a/packages/tsconfig/react-library.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "React Library", - "extends": "./base.json", - "compilerOptions": { - "jsx": "react-jsx", - "lib": ["dom", "dom.iterable", "esnext"], - "module": "ESNext", - "target": "es6" - } -} diff --git a/.eslintignore b/starters/shopify-algolia/.eslintignore similarity index 100% rename from .eslintignore rename to starters/shopify-algolia/.eslintignore diff --git a/packages/eslint-config-custom/base.js b/starters/shopify-algolia/.eslintrc.js similarity index 97% rename from packages/eslint-config-custom/base.js rename to starters/shopify-algolia/.eslintrc.js index 686ace74..44fd1243 100644 --- a/packages/eslint-config-custom/base.js +++ b/starters/shopify-algolia/.eslintrc.js @@ -1,8 +1,6 @@ /* eslint-env es6 */ /* eslint-disable no-console */ -const fs = require("fs") - module.exports = { globals: { React: true, diff --git a/starters/shopify-algolia/.gitignore b/starters/shopify-algolia/.gitignore new file mode 100644 index 00000000..6e6c971f --- /dev/null +++ b/starters/shopify-algolia/.gitignore @@ -0,0 +1,21 @@ +.next/ +out/ +build + +build/** +dist/** +**/dist/** +.next/** + + +/.npm-only-allow + +storybook-static/ +playwright-report/ +playwright/.cache/ +test-results/ + +graph.svg + +# testing +coverage \ No newline at end of file diff --git a/packages/core/.graphqlrc.ts b/starters/shopify-algolia/.graphqlrc.ts similarity index 62% rename from packages/core/.graphqlrc.ts rename to starters/shopify-algolia/.graphqlrc.ts index 7add0c20..38b7dc73 100644 --- a/packages/core/.graphqlrc.ts +++ b/starters/shopify-algolia/.graphqlrc.ts @@ -7,14 +7,14 @@ export default { default: shopifyApiProject({ apiType: ApiType.Storefront, apiVersion: "2024-01", - documents: ["./platform/shopify/**/*.storefront.{js,ts,jsx,tsx}", "./platform/shopify/**/fragments/*.{js,ts,jsx,tsx}"], - outputDir: "./platform/shopify/types", + documents: ["./lib/shopify/**/*.storefront.{js,ts,jsx,tsx}", "./lib/shopify/**/fragments/*.{js,ts,jsx,tsx}"], + outputDir: "./lib/shopify/types", }), admin: shopifyApiProject({ apiType: ApiType.Admin, apiVersion: "2024-01", - documents: ["./platform/shopify/**/*.admin.{js,ts,jsx,tsx}"], - outputDir: "./platform/shopify/types/admin", + documents: ["./lib/shopify/**/*.admin.{js,ts,jsx,tsx}"], + outputDir: "./lib/shopify/types/admin", }), }, } diff --git a/starters/shopify-algolia/.prettierignore b/starters/shopify-algolia/.prettierignore new file mode 100644 index 00000000..76550769 --- /dev/null +++ b/starters/shopify-algolia/.prettierignore @@ -0,0 +1,3 @@ +.next +node_modules +gql diff --git a/apps/web/.storybook/main.ts b/starters/shopify-algolia/.storybook/main.ts similarity index 100% rename from apps/web/.storybook/main.ts rename to starters/shopify-algolia/.storybook/main.ts diff --git a/apps/web/.storybook/preview.ts b/starters/shopify-algolia/.storybook/preview.ts similarity index 100% rename from apps/web/.storybook/preview.ts rename to starters/shopify-algolia/.storybook/preview.ts diff --git a/apps/web/app/.well-known/vercel/flags/route.ts b/starters/shopify-algolia/app/.well-known/vercel/flags/route.ts similarity index 100% rename from apps/web/app/.well-known/vercel/flags/route.ts rename to starters/shopify-algolia/app/.well-known/vercel/flags/route.ts diff --git a/apps/web/app/access-denied/page.tsx b/starters/shopify-algolia/app/access-denied/page.tsx similarity index 100% rename from apps/web/app/access-denied/page.tsx rename to starters/shopify-algolia/app/access-denied/page.tsx diff --git a/apps/web/app/actions/cart.actions.ts b/starters/shopify-algolia/app/actions/cart.actions.ts similarity index 100% rename from apps/web/app/actions/cart.actions.ts rename to starters/shopify-algolia/app/actions/cart.actions.ts diff --git a/apps/web/app/actions/collection.actions.ts b/starters/shopify-algolia/app/actions/collection.actions.ts similarity index 90% rename from apps/web/app/actions/collection.actions.ts rename to starters/shopify-algolia/app/actions/collection.actions.ts index 1ce5fcfd..4dca9765 100644 --- a/apps/web/app/actions/collection.actions.ts +++ b/starters/shopify-algolia/app/actions/collection.actions.ts @@ -4,7 +4,7 @@ import { unstable_cache } from "next/cache" import { meilisearch } from "clients/search" import { ComparisonOperators, FilterBuilder } from "utils/filterBuilder" import { getDemoSingleCategory, isDemoMode } from "utils/demoUtils" -import type { PlatformCollection } from "@enterprise-commerce/core/platform/types" +import type { PlatformCollection } from "lib/shopify/types" import { env } from "env.mjs" export const getCollection = unstable_cache( diff --git a/apps/web/app/actions/favorites.actions.ts b/starters/shopify-algolia/app/actions/favorites.actions.ts similarity index 100% rename from apps/web/app/actions/favorites.actions.ts rename to starters/shopify-algolia/app/actions/favorites.actions.ts diff --git a/apps/web/app/actions/page.actions.ts b/starters/shopify-algolia/app/actions/page.actions.ts similarity index 100% rename from apps/web/app/actions/page.actions.ts rename to starters/shopify-algolia/app/actions/page.actions.ts diff --git a/apps/web/app/actions/product.actions.ts b/starters/shopify-algolia/app/actions/product.actions.ts similarity index 97% rename from apps/web/app/actions/product.actions.ts rename to starters/shopify-algolia/app/actions/product.actions.ts index 795d2d6b..a889edb1 100644 --- a/apps/web/app/actions/product.actions.ts +++ b/starters/shopify-algolia/app/actions/product.actions.ts @@ -4,7 +4,7 @@ import { unstable_cache } from "next/cache" import { env } from "env.mjs" import { meilisearch } from "clients/search" -import type { Review } from "@enterprise-commerce/reviews" +import type { Review } from "lib/reviews/types" import { ComparisonOperators, FilterBuilder } from "utils/filterBuilder" import { getDemoProductReviews, getDemoSingleProduct, isDemoMode } from "utils/demoUtils" diff --git a/apps/web/app/actions/reviews.actions.ts b/starters/shopify-algolia/app/actions/reviews.actions.ts similarity index 84% rename from apps/web/app/actions/reviews.actions.ts rename to starters/shopify-algolia/app/actions/reviews.actions.ts index c3ebfe2f..fb3e2bee 100644 --- a/apps/web/app/actions/reviews.actions.ts +++ b/starters/shopify-algolia/app/actions/reviews.actions.ts @@ -1,7 +1,7 @@ "use server" import { reviewsClient } from "clients/reviews" -import type { ProductReviewBody } from "@enterprise-commerce/reviews" +import type { ProductReviewBody } from "lib/reviews/types" import { headers } from "next/headers" diff --git a/apps/web/app/actions/user.actions.ts b/starters/shopify-algolia/app/actions/user.actions.ts similarity index 93% rename from apps/web/app/actions/user.actions.ts rename to starters/shopify-algolia/app/actions/user.actions.ts index d2f7f341..f79d8f5f 100644 --- a/apps/web/app/actions/user.actions.ts +++ b/starters/shopify-algolia/app/actions/user.actions.ts @@ -1,6 +1,6 @@ "use server" -import { PlatformUserCreateInput } from "@enterprise-commerce/core/platform/types" +import { PlatformUserCreateInput } from "lib/shopify/types" import { cookies } from "next/headers" import { storefrontClient } from "clients/storefrontClient" import { COOKIE_ACCESS_TOKEN } from "constants/index" diff --git a/apps/web/app/api/feed/sync/route.ts b/starters/shopify-algolia/app/api/feed/sync/route.ts similarity index 98% rename from apps/web/app/api/feed/sync/route.ts rename to starters/shopify-algolia/app/api/feed/sync/route.ts index 5fb27145..d0512146 100644 --- a/apps/web/app/api/feed/sync/route.ts +++ b/starters/shopify-algolia/app/api/feed/sync/route.ts @@ -1,4 +1,4 @@ -import type { PlatformProduct } from "@enterprise-commerce/core/platform/types" +import type { PlatformProduct } from "lib/shopify/types" import { meilisearch } from "clients/search" import { storefrontClient } from "clients/storefrontClient" import { env } from "env.mjs" diff --git a/apps/web/app/api/health/route.ts b/starters/shopify-algolia/app/api/health/route.ts similarity index 100% rename from apps/web/app/api/health/route.ts rename to starters/shopify-algolia/app/api/health/route.ts diff --git a/apps/web/app/api/redirects/route.ts b/starters/shopify-algolia/app/api/redirects/route.ts similarity index 100% rename from apps/web/app/api/redirects/route.ts rename to starters/shopify-algolia/app/api/redirects/route.ts diff --git a/apps/web/app/api/reviews/ai-summary/route.ts b/starters/shopify-algolia/app/api/reviews/ai-summary/route.ts similarity index 98% rename from apps/web/app/api/reviews/ai-summary/route.ts rename to starters/shopify-algolia/app/api/reviews/ai-summary/route.ts index 7e4fcbb5..764c7084 100644 --- a/apps/web/app/api/reviews/ai-summary/route.ts +++ b/starters/shopify-algolia/app/api/reviews/ai-summary/route.ts @@ -1,7 +1,7 @@ import { generateObject } from "ai" import z from "zod" import { openai } from "@ai-sdk/openai" -import type { Review } from "@enterprise-commerce/reviews" +import type { Review } from "lib/reviews/types" import type { CommerceProduct } from "types" import { meilisearch } from "clients/search" import { env } from "env.mjs" diff --git a/apps/web/app/api/reviews/sync/route.ts b/starters/shopify-algolia/app/api/reviews/sync/route.ts similarity index 98% rename from apps/web/app/api/reviews/sync/route.ts rename to starters/shopify-algolia/app/api/reviews/sync/route.ts index 3cbe7345..51183e6f 100644 --- a/apps/web/app/api/reviews/sync/route.ts +++ b/starters/shopify-algolia/app/api/reviews/sync/route.ts @@ -4,7 +4,7 @@ import { reviewsClient } from "clients/reviews" import { env } from "env.mjs" import { authenticate } from "utils/authenticate-api-route" import { isOptIn, notifyOptIn } from "utils/opt-in" -import type { Review } from "@enterprise-commerce/reviews" +import type { Review } from "lib/reviews/types" import type { CommerceProduct } from "types" import { isDemoMode } from "utils/demoUtils" diff --git a/apps/web/app/category/clp/[slug]/[page]/page.tsx b/starters/shopify-algolia/app/category/clp/[slug]/[page]/page.tsx similarity index 100% rename from apps/web/app/category/clp/[slug]/[page]/page.tsx rename to starters/shopify-algolia/app/category/clp/[slug]/[page]/page.tsx diff --git a/apps/web/app/category/clp/[slug]/page.tsx b/starters/shopify-algolia/app/category/clp/[slug]/page.tsx similarity index 92% rename from apps/web/app/category/clp/[slug]/page.tsx rename to starters/shopify-algolia/app/category/clp/[slug]/page.tsx index 686aee0d..6f7210a4 100644 --- a/apps/web/app/category/clp/[slug]/page.tsx +++ b/starters/shopify-algolia/app/category/clp/[slug]/page.tsx @@ -1,4 +1,4 @@ -import { PlatformCollection } from "@enterprise-commerce/core/platform/types" +import { PlatformCollection } from "lib/shopify/types" import { meilisearch } from "clients/search" import { env } from "env.mjs" import type { Metadata } from "next" diff --git a/apps/web/app/category/plp/[slug]/page.tsx b/starters/shopify-algolia/app/category/plp/[slug]/page.tsx similarity index 100% rename from apps/web/app/category/plp/[slug]/page.tsx rename to starters/shopify-algolia/app/category/plp/[slug]/page.tsx diff --git a/apps/web/app/error.tsx b/starters/shopify-algolia/app/error.tsx similarity index 100% rename from apps/web/app/error.tsx rename to starters/shopify-algolia/app/error.tsx diff --git a/apps/web/app/favorites/page.tsx b/starters/shopify-algolia/app/favorites/page.tsx similarity index 100% rename from apps/web/app/favorites/page.tsx rename to starters/shopify-algolia/app/favorites/page.tsx diff --git a/apps/web/app/global-error.tsx b/starters/shopify-algolia/app/global-error.tsx similarity index 100% rename from apps/web/app/global-error.tsx rename to starters/shopify-algolia/app/global-error.tsx diff --git a/apps/web/app/globals.css b/starters/shopify-algolia/app/globals.css similarity index 100% rename from apps/web/app/globals.css rename to starters/shopify-algolia/app/globals.css diff --git a/apps/web/app/home/[bucket]/page.tsx b/starters/shopify-algolia/app/home/[bucket]/page.tsx similarity index 97% rename from apps/web/app/home/[bucket]/page.tsx rename to starters/shopify-algolia/app/home/[bucket]/page.tsx index 7508ec70..9e78392c 100644 --- a/apps/web/app/home/[bucket]/page.tsx +++ b/starters/shopify-algolia/app/home/[bucket]/page.tsx @@ -21,7 +21,7 @@ export default function Homepage({ params: { bucket } }: { params: { bucket: str return (
- + }> diff --git a/apps/web/app/icon.png b/starters/shopify-algolia/app/icon.png similarity index 100% rename from apps/web/app/icon.png rename to starters/shopify-algolia/app/icon.png diff --git a/apps/web/app/layout.tsx b/starters/shopify-algolia/app/layout.tsx similarity index 100% rename from apps/web/app/layout.tsx rename to starters/shopify-algolia/app/layout.tsx diff --git a/apps/web/app/manifest.ts b/starters/shopify-algolia/app/manifest.ts similarity index 100% rename from apps/web/app/manifest.ts rename to starters/shopify-algolia/app/manifest.ts diff --git a/apps/web/app/not-found.tsx b/starters/shopify-algolia/app/not-found.tsx similarity index 100% rename from apps/web/app/not-found.tsx rename to starters/shopify-algolia/app/not-found.tsx diff --git a/apps/web/app/opengraph-image.jpg b/starters/shopify-algolia/app/opengraph-image.jpg similarity index 100% rename from apps/web/app/opengraph-image.jpg rename to starters/shopify-algolia/app/opengraph-image.jpg diff --git a/apps/web/app/pages/[slug]/metadata.ts b/starters/shopify-algolia/app/pages/[slug]/metadata.ts similarity index 100% rename from apps/web/app/pages/[slug]/metadata.ts rename to starters/shopify-algolia/app/pages/[slug]/metadata.ts diff --git a/apps/web/app/pages/[slug]/page.tsx b/starters/shopify-algolia/app/pages/[slug]/page.tsx similarity index 100% rename from apps/web/app/pages/[slug]/page.tsx rename to starters/shopify-algolia/app/pages/[slug]/page.tsx diff --git a/apps/web/app/product/[slug]/draft/page.tsx b/starters/shopify-algolia/app/product/[slug]/draft/page.tsx similarity index 95% rename from apps/web/app/product/[slug]/draft/page.tsx rename to starters/shopify-algolia/app/product/[slug]/draft/page.tsx index 33c86313..966515eb 100644 --- a/apps/web/app/product/[slug]/draft/page.tsx +++ b/starters/shopify-algolia/app/product/[slug]/draft/page.tsx @@ -7,7 +7,7 @@ import type { CommerceProduct } from "types" import { Breadcrumbs } from "components/Breadcrumbs/Breadcrumbs" -import type { PlatformProduct } from "@enterprise-commerce/core/platform/types" +import type { PlatformProduct } from "lib/shopify/types" import { getCombination, getOptionsFromUrl, hasValidOption, removeOptionsFromUrl } from "utils/productOptionsUtils" import { BackButton } from "views/Product/BackButton" import { SimilarProductsSection } from "views/Product/SimilarProductsSection" @@ -56,11 +56,11 @@ async function ProductView({ slug }: { slug: string }) { const hasOnlyOneVariant = product.variants.length <= 1 return ( -
+
-
+
{ + if (!env.REPLICATE_API_KEY) return null + return new Replicate({ + auth: env.REPLICATE_API_KEY || "", + }) +} diff --git a/apps/web/clients/reviews.ts b/starters/shopify-algolia/clients/reviews.ts similarity index 85% rename from apps/web/clients/reviews.ts rename to starters/shopify-algolia/clients/reviews.ts index 94111ef4..a83ce96c 100644 --- a/apps/web/clients/reviews.ts +++ b/starters/shopify-algolia/clients/reviews.ts @@ -1,4 +1,4 @@ -import { createJudgeClient } from "@enterprise-commerce/reviews" +import { createJudgeClient } from "lib/reviews" import { env } from "env.mjs" import { isOptIn, notifyOptIn } from "utils/opt-in" diff --git a/starters/shopify-algolia/clients/search.ts b/starters/shopify-algolia/clients/search.ts new file mode 100644 index 00000000..484faf5d --- /dev/null +++ b/starters/shopify-algolia/clients/search.ts @@ -0,0 +1,7 @@ +import { env } from "env.mjs" +import { algolia as searchClient } from "lib/algolia" + +export const meilisearch: ReturnType = searchClient({ + host: env.MEILISEARCH_HOST || "", + adminApiKey: env.MEILISEARCH_ADMIN_KEY || "", +}) diff --git a/apps/web/clients/storefrontClient.ts b/starters/shopify-algolia/clients/storefrontClient.ts similarity index 59% rename from apps/web/clients/storefrontClient.ts rename to starters/shopify-algolia/clients/storefrontClient.ts index d611f02b..fd277f65 100644 --- a/apps/web/clients/storefrontClient.ts +++ b/starters/shopify-algolia/clients/storefrontClient.ts @@ -1,10 +1,9 @@ import "server-only" -import { createStorefrontClient } from "@enterprise-commerce/core/platform" +import { createShopifyClient } from "lib/shopify" import { env } from "../env.mjs" -export const storefrontClient = createStorefrontClient({ - strategy: "shopify", +export const storefrontClient = createShopifyClient({ storeDomain: env.SHOPIFY_STORE_DOMAIN || "", storefrontAccessToken: env.SHOPIFY_STOREFRONT_ACCESS_TOKEN || "", adminAccessToken: env.SHOPIFY_ADMIN_ACCESS_TOKEN || "", diff --git a/apps/web/components.json b/starters/shopify-algolia/components.json similarity index 100% rename from apps/web/components.json rename to starters/shopify-algolia/components.json diff --git a/apps/web/components/Accordion/Accordion.stories.tsx b/starters/shopify-algolia/components/Accordion/Accordion.stories.tsx similarity index 100% rename from apps/web/components/Accordion/Accordion.stories.tsx rename to starters/shopify-algolia/components/Accordion/Accordion.stories.tsx diff --git a/apps/web/components/Accordion/Accordion.tsx b/starters/shopify-algolia/components/Accordion/Accordion.tsx similarity index 100% rename from apps/web/components/Accordion/Accordion.tsx rename to starters/shopify-algolia/components/Accordion/Accordion.tsx diff --git a/apps/web/components/Alert/Alert.tsx b/starters/shopify-algolia/components/Alert/Alert.tsx similarity index 100% rename from apps/web/components/Alert/Alert.tsx rename to starters/shopify-algolia/components/Alert/Alert.tsx diff --git a/apps/web/components/AnnouncementBar/AnnouncementBar.stories.tsx b/starters/shopify-algolia/components/AnnouncementBar/AnnouncementBar.stories.tsx similarity index 100% rename from apps/web/components/AnnouncementBar/AnnouncementBar.stories.tsx rename to starters/shopify-algolia/components/AnnouncementBar/AnnouncementBar.stories.tsx diff --git a/apps/web/components/AnnouncementBar/AnnouncementBar.tsx b/starters/shopify-algolia/components/AnnouncementBar/AnnouncementBar.tsx similarity index 100% rename from apps/web/components/AnnouncementBar/AnnouncementBar.tsx rename to starters/shopify-algolia/components/AnnouncementBar/AnnouncementBar.tsx diff --git a/apps/web/components/Badge/Badge.tsx b/starters/shopify-algolia/components/Badge/Badge.tsx similarity index 100% rename from apps/web/components/Badge/Badge.tsx rename to starters/shopify-algolia/components/Badge/Badge.tsx diff --git a/apps/web/components/Breadcrumb/Breadcrumb.tsx b/starters/shopify-algolia/components/Breadcrumb/Breadcrumb.tsx similarity index 100% rename from apps/web/components/Breadcrumb/Breadcrumb.tsx rename to starters/shopify-algolia/components/Breadcrumb/Breadcrumb.tsx diff --git a/apps/web/components/Breadcrumbs/Breadcrumbs.stories.tsx b/starters/shopify-algolia/components/Breadcrumbs/Breadcrumbs.stories.tsx similarity index 100% rename from apps/web/components/Breadcrumbs/Breadcrumbs.stories.tsx rename to starters/shopify-algolia/components/Breadcrumbs/Breadcrumbs.stories.tsx diff --git a/apps/web/components/Breadcrumbs/Breadcrumbs.tsx b/starters/shopify-algolia/components/Breadcrumbs/Breadcrumbs.tsx similarity index 100% rename from apps/web/components/Breadcrumbs/Breadcrumbs.tsx rename to starters/shopify-algolia/components/Breadcrumbs/Breadcrumbs.tsx diff --git a/apps/web/components/Button/Button.stories.tsx b/starters/shopify-algolia/components/Button/Button.stories.tsx similarity index 100% rename from apps/web/components/Button/Button.stories.tsx rename to starters/shopify-algolia/components/Button/Button.stories.tsx diff --git a/apps/web/components/Button/Button.tsx b/starters/shopify-algolia/components/Button/Button.tsx similarity index 100% rename from apps/web/components/Button/Button.tsx rename to starters/shopify-algolia/components/Button/Button.tsx diff --git a/apps/web/components/Button/ButtonNew.tsx b/starters/shopify-algolia/components/Button/ButtonNew.tsx similarity index 100% rename from apps/web/components/Button/ButtonNew.tsx rename to starters/shopify-algolia/components/Button/ButtonNew.tsx diff --git a/apps/web/components/CallToAction/CallToAction.stories.tsx b/starters/shopify-algolia/components/CallToAction/CallToAction.stories.tsx similarity index 100% rename from apps/web/components/CallToAction/CallToAction.stories.tsx rename to starters/shopify-algolia/components/CallToAction/CallToAction.stories.tsx diff --git a/apps/web/components/CallToAction/CallToAction.tsx b/starters/shopify-algolia/components/CallToAction/CallToAction.tsx similarity index 100% rename from apps/web/components/CallToAction/CallToAction.tsx rename to starters/shopify-algolia/components/CallToAction/CallToAction.tsx diff --git a/apps/web/components/Card/Card.stories.tsx b/starters/shopify-algolia/components/Card/Card.stories.tsx similarity index 100% rename from apps/web/components/Card/Card.stories.tsx rename to starters/shopify-algolia/components/Card/Card.stories.tsx diff --git a/apps/web/components/Card/Card.tsx b/starters/shopify-algolia/components/Card/Card.tsx similarity index 100% rename from apps/web/components/Card/Card.tsx rename to starters/shopify-algolia/components/Card/Card.tsx diff --git a/apps/web/components/Carousel/Carousel.stories.tsx b/starters/shopify-algolia/components/Carousel/Carousel.stories.tsx similarity index 100% rename from apps/web/components/Carousel/Carousel.stories.tsx rename to starters/shopify-algolia/components/Carousel/Carousel.stories.tsx diff --git a/apps/web/components/Carousel/Carousel.tsx b/starters/shopify-algolia/components/Carousel/Carousel.tsx similarity index 100% rename from apps/web/components/Carousel/Carousel.tsx rename to starters/shopify-algolia/components/Carousel/Carousel.tsx diff --git a/apps/web/components/Checkbox/Checkbox.stories.tsx b/starters/shopify-algolia/components/Checkbox/Checkbox.stories.tsx similarity index 100% rename from apps/web/components/Checkbox/Checkbox.stories.tsx rename to starters/shopify-algolia/components/Checkbox/Checkbox.stories.tsx diff --git a/apps/web/components/Checkbox/Checkbox.tsx b/starters/shopify-algolia/components/Checkbox/Checkbox.tsx similarity index 100% rename from apps/web/components/Checkbox/Checkbox.tsx rename to starters/shopify-algolia/components/Checkbox/Checkbox.tsx diff --git a/apps/web/components/Dialog/Dialog.stories.tsx b/starters/shopify-algolia/components/Dialog/Dialog.stories.tsx similarity index 100% rename from apps/web/components/Dialog/Dialog.stories.tsx rename to starters/shopify-algolia/components/Dialog/Dialog.stories.tsx diff --git a/apps/web/components/Dialog/Dialog.tsx b/starters/shopify-algolia/components/Dialog/Dialog.tsx similarity index 100% rename from apps/web/components/Dialog/Dialog.tsx rename to starters/shopify-algolia/components/Dialog/Dialog.tsx diff --git a/apps/web/components/DropdownMenu/DropdownMenu.stories.tsx b/starters/shopify-algolia/components/DropdownMenu/DropdownMenu.stories.tsx similarity index 100% rename from apps/web/components/DropdownMenu/DropdownMenu.stories.tsx rename to starters/shopify-algolia/components/DropdownMenu/DropdownMenu.stories.tsx diff --git a/apps/web/components/DropdownMenu/DropdownMenu.tsx b/starters/shopify-algolia/components/DropdownMenu/DropdownMenu.tsx similarity index 100% rename from apps/web/components/DropdownMenu/DropdownMenu.tsx rename to starters/shopify-algolia/components/DropdownMenu/DropdownMenu.tsx diff --git a/apps/web/components/ExpandableContent/ExpandableContent.tsx b/starters/shopify-algolia/components/ExpandableContent/ExpandableContent.tsx similarity index 100% rename from apps/web/components/ExpandableContent/ExpandableContent.tsx rename to starters/shopify-algolia/components/ExpandableContent/ExpandableContent.tsx diff --git a/apps/web/components/Footer/Footer.stories.tsx b/starters/shopify-algolia/components/Footer/Footer.stories.tsx similarity index 100% rename from apps/web/components/Footer/Footer.stories.tsx rename to starters/shopify-algolia/components/Footer/Footer.stories.tsx diff --git a/apps/web/components/Footer/Footer.tsx b/starters/shopify-algolia/components/Footer/Footer.tsx similarity index 94% rename from apps/web/components/Footer/Footer.tsx rename to starters/shopify-algolia/components/Footer/Footer.tsx index 0dc45e0a..967d7bdf 100644 --- a/apps/web/components/Footer/Footer.tsx +++ b/starters/shopify-algolia/components/Footer/Footer.tsx @@ -55,7 +55,7 @@ export function Footer() { ) } -function FacebookIcon(props) { +function FacebookIcon(props: React.SVGProps) { return ( ) { return ( ) { return ( ) { return ( ) { return ( void }) { const [hover, setHover] = useState(0) return ( diff --git a/apps/web/components/Modals/SearchModal.tsx b/starters/shopify-algolia/components/Modals/SearchModal.tsx similarity index 100% rename from apps/web/components/Modals/SearchModal.tsx rename to starters/shopify-algolia/components/Modals/SearchModal.tsx diff --git a/apps/web/components/Modals/SignupModal.tsx b/starters/shopify-algolia/components/Modals/SignupModal.tsx similarity index 100% rename from apps/web/components/Modals/SignupModal.tsx rename to starters/shopify-algolia/components/Modals/SignupModal.tsx diff --git a/apps/web/components/NavigationBar/Autocomplete.tsx b/starters/shopify-algolia/components/NavigationBar/Autocomplete.tsx similarity index 100% rename from apps/web/components/NavigationBar/Autocomplete.tsx rename to starters/shopify-algolia/components/NavigationBar/Autocomplete.tsx diff --git a/apps/web/components/NavigationBar/Cart.tsx b/starters/shopify-algolia/components/NavigationBar/Cart.tsx similarity index 100% rename from apps/web/components/NavigationBar/Cart.tsx rename to starters/shopify-algolia/components/NavigationBar/Cart.tsx diff --git a/apps/web/components/NavigationBar/Favorites.tsx b/starters/shopify-algolia/components/NavigationBar/Favorites.tsx similarity index 100% rename from apps/web/components/NavigationBar/Favorites.tsx rename to starters/shopify-algolia/components/NavigationBar/Favorites.tsx diff --git a/apps/web/components/NavigationBar/NavigationBar.tsx b/starters/shopify-algolia/components/NavigationBar/NavigationBar.tsx similarity index 100% rename from apps/web/components/NavigationBar/NavigationBar.tsx rename to starters/shopify-algolia/components/NavigationBar/NavigationBar.tsx diff --git a/apps/web/components/NavigationBar/NavigationItem.tsx b/starters/shopify-algolia/components/NavigationBar/NavigationItem.tsx similarity index 100% rename from apps/web/components/NavigationBar/NavigationItem.tsx rename to starters/shopify-algolia/components/NavigationBar/NavigationItem.tsx diff --git a/apps/web/components/NavigationBar/OpenCartButton.tsx b/starters/shopify-algolia/components/NavigationBar/OpenCartButton.tsx similarity index 100% rename from apps/web/components/NavigationBar/OpenCartButton.tsx rename to starters/shopify-algolia/components/NavigationBar/OpenCartButton.tsx diff --git a/apps/web/components/NavigationBar/SearchButton.tsx b/starters/shopify-algolia/components/NavigationBar/SearchButton.tsx similarity index 100% rename from apps/web/components/NavigationBar/SearchButton.tsx rename to starters/shopify-algolia/components/NavigationBar/SearchButton.tsx diff --git a/apps/web/components/NavigationBar/mobileInlineScript.ts b/starters/shopify-algolia/components/NavigationBar/mobileInlineScript.ts similarity index 100% rename from apps/web/components/NavigationBar/mobileInlineScript.ts rename to starters/shopify-algolia/components/NavigationBar/mobileInlineScript.ts diff --git a/apps/web/components/NavigationBar/types.ts b/starters/shopify-algolia/components/NavigationBar/types.ts similarity index 100% rename from apps/web/components/NavigationBar/types.ts rename to starters/shopify-algolia/components/NavigationBar/types.ts diff --git a/apps/web/components/NavigationBar/variants/ImageGridVariant.tsx b/starters/shopify-algolia/components/NavigationBar/variants/ImageGridVariant.tsx similarity index 100% rename from apps/web/components/NavigationBar/variants/ImageGridVariant.tsx rename to starters/shopify-algolia/components/NavigationBar/variants/ImageGridVariant.tsx diff --git a/apps/web/components/NavigationBar/variants/TextGridVariant.tsx b/starters/shopify-algolia/components/NavigationBar/variants/TextGridVariant.tsx similarity index 100% rename from apps/web/components/NavigationBar/variants/TextGridVariant.tsx rename to starters/shopify-algolia/components/NavigationBar/variants/TextGridVariant.tsx diff --git a/apps/web/components/NavigationBar/variants/TextImageGridVariant.tsx b/starters/shopify-algolia/components/NavigationBar/variants/TextImageGridVariant.tsx similarity index 100% rename from apps/web/components/NavigationBar/variants/TextImageGridVariant.tsx rename to starters/shopify-algolia/components/NavigationBar/variants/TextImageGridVariant.tsx diff --git a/apps/web/components/Pagination/Pagination.stories.tsx b/starters/shopify-algolia/components/Pagination/Pagination.stories.tsx similarity index 100% rename from apps/web/components/Pagination/Pagination.stories.tsx rename to starters/shopify-algolia/components/Pagination/Pagination.stories.tsx diff --git a/apps/web/components/Pagination/Pagination.tsx b/starters/shopify-algolia/components/Pagination/Pagination.tsx similarity index 100% rename from apps/web/components/Pagination/Pagination.tsx rename to starters/shopify-algolia/components/Pagination/Pagination.tsx diff --git a/apps/web/components/ProductCard/ProductCard.tsx b/starters/shopify-algolia/components/ProductCard/ProductCard.tsx similarity index 100% rename from apps/web/components/ProductCard/ProductCard.tsx rename to starters/shopify-algolia/components/ProductCard/ProductCard.tsx diff --git a/apps/web/components/ProductCard/QuickAdd.tsx b/starters/shopify-algolia/components/ProductCard/QuickAdd.tsx similarity index 93% rename from apps/web/components/ProductCard/QuickAdd.tsx rename to starters/shopify-algolia/components/ProductCard/QuickAdd.tsx index 97f130cd..6423b047 100644 --- a/apps/web/components/ProductCard/QuickAdd.tsx +++ b/starters/shopify-algolia/components/ProductCard/QuickAdd.tsx @@ -1,4 +1,4 @@ -import type { PlatformVariant } from "@enterprise-commerce/core/platform/types" +import type { PlatformVariant } from "lib/shopify/types" import { getAllCombinations } from "utils/productOptionsUtils" import QuickAddButton from "./QuickAddButton" import { CommerceProduct } from "types" diff --git a/apps/web/components/ProductCard/QuickAddButton.tsx b/starters/shopify-algolia/components/ProductCard/QuickAddButton.tsx similarity index 100% rename from apps/web/components/ProductCard/QuickAddButton.tsx rename to starters/shopify-algolia/components/ProductCard/QuickAddButton.tsx diff --git a/apps/web/components/ProfileMenu/AuthActions.tsx b/starters/shopify-algolia/components/ProfileMenu/AuthActions.tsx similarity index 100% rename from apps/web/components/ProfileMenu/AuthActions.tsx rename to starters/shopify-algolia/components/ProfileMenu/AuthActions.tsx diff --git a/apps/web/components/ProfileMenu/ProfileBar.tsx b/starters/shopify-algolia/components/ProfileMenu/ProfileBar.tsx similarity index 94% rename from apps/web/components/ProfileMenu/ProfileBar.tsx rename to starters/shopify-algolia/components/ProfileMenu/ProfileBar.tsx index 7bda1a9a..470eff69 100644 --- a/apps/web/components/ProfileMenu/ProfileBar.tsx +++ b/starters/shopify-algolia/components/ProfileMenu/ProfileBar.tsx @@ -1,6 +1,6 @@ "use client" -import { PlatformUser } from "@enterprise-commerce/core/platform/types" +import { PlatformUser } from "lib/shopify/types" import Link from "next/link" import { useRouter } from "next/navigation" import { logoutUser } from "app/actions/user.actions" @@ -15,7 +15,7 @@ export default function ProfileBar({ user }: { user: PlatformUser }) { function handleLogout() { logoutUser() setUser(null) - + router.refresh() } diff --git a/apps/web/components/ProfileMenu/ProfileMenu.tsx b/starters/shopify-algolia/components/ProfileMenu/ProfileMenu.tsx similarity index 100% rename from apps/web/components/ProfileMenu/ProfileMenu.tsx rename to starters/shopify-algolia/components/ProfileMenu/ProfileMenu.tsx diff --git a/apps/web/components/Select/Select.stories.tsx b/starters/shopify-algolia/components/Select/Select.stories.tsx similarity index 100% rename from apps/web/components/Select/Select.stories.tsx rename to starters/shopify-algolia/components/Select/Select.stories.tsx diff --git a/apps/web/components/Select/Select.tsx b/starters/shopify-algolia/components/Select/Select.tsx similarity index 100% rename from apps/web/components/Select/Select.tsx rename to starters/shopify-algolia/components/Select/Select.tsx diff --git a/apps/web/components/Sheet/Sheet.stories.tsx b/starters/shopify-algolia/components/Sheet/Sheet.stories.tsx similarity index 100% rename from apps/web/components/Sheet/Sheet.stories.tsx rename to starters/shopify-algolia/components/Sheet/Sheet.stories.tsx diff --git a/apps/web/components/Sheet/Sheet.tsx b/starters/shopify-algolia/components/Sheet/Sheet.tsx similarity index 100% rename from apps/web/components/Sheet/Sheet.tsx rename to starters/shopify-algolia/components/Sheet/Sheet.tsx diff --git a/apps/web/components/Skeleton/Skeleton.stories.tsx b/starters/shopify-algolia/components/Skeleton/Skeleton.stories.tsx similarity index 100% rename from apps/web/components/Skeleton/Skeleton.stories.tsx rename to starters/shopify-algolia/components/Skeleton/Skeleton.stories.tsx diff --git a/apps/web/components/Skeleton/Skeleton.tsx b/starters/shopify-algolia/components/Skeleton/Skeleton.tsx similarity index 100% rename from apps/web/components/Skeleton/Skeleton.tsx rename to starters/shopify-algolia/components/Skeleton/Skeleton.tsx diff --git a/apps/web/components/Spinner/Spinner.stories.tsx b/starters/shopify-algolia/components/Spinner/Spinner.stories.tsx similarity index 100% rename from apps/web/components/Spinner/Spinner.stories.tsx rename to starters/shopify-algolia/components/Spinner/Spinner.stories.tsx diff --git a/apps/web/components/Spinner/Spinner.tsx b/starters/shopify-algolia/components/Spinner/Spinner.tsx similarity index 100% rename from apps/web/components/Spinner/Spinner.tsx rename to starters/shopify-algolia/components/Spinner/Spinner.tsx diff --git a/apps/web/components/Textarea/Textarea.tsx b/starters/shopify-algolia/components/Textarea/Textarea.tsx similarity index 100% rename from apps/web/components/Textarea/Textarea.tsx rename to starters/shopify-algolia/components/Textarea/Textarea.tsx diff --git a/apps/web/constants/index.ts b/starters/shopify-algolia/constants/index.ts similarity index 100% rename from apps/web/constants/index.ts rename to starters/shopify-algolia/constants/index.ts diff --git a/apps/web/e2e/example.spec.ts b/starters/shopify-algolia/e2e/example.spec.ts similarity index 100% rename from apps/web/e2e/example.spec.ts rename to starters/shopify-algolia/e2e/example.spec.ts diff --git a/starters/shopify-algolia/env.mjs b/starters/shopify-algolia/env.mjs new file mode 100644 index 00000000..3f5badfd --- /dev/null +++ b/starters/shopify-algolia/env.mjs @@ -0,0 +1,48 @@ +import { createEnv } from "@t3-oss/env-nextjs" +import { z } from "zod" + +export const env = createEnv({ + skipValidation: process.env.NODE_ENV !== "production" || process.env.SKIP_ENV_VALIDATION === "true", + server: { + SHOPIFY_STOREFRONT_ACCESS_TOKEN: z.string(), + SHOPIFY_STORE_DOMAIN: z.string(), + SHOPIFY_ADMIN_ACCESS_TOKEN: z.string().optional(), + SHOPIFY_APP_API_SECRET_KEY: z.string().optional(), + SHOPIFY_HIERARCHICAL_NAV_HANDLE: z.string().optional(), + REPLICATE_API_KEY: z.string().optional(), + OPENAI_API_KEY: z.string().optional(), + LIVE_URL: z.string().optional(), + GTM_ID: z.string().optional().default(), + IS_GTM_ENABLED: z.enum(["true", "false"]).optional(), + IS_SPEED_INSIGHTS_ENABLED: z.enum(["true", "false"]).optional(), + IS_VERCEL_ANALYTICS_ENABLED: z.enum(["true", "false"]).optional(), + IS_DEMO_MODE: z.enum(["true", "false"]).optional(), + ANALYZE: z + .enum(["true", "false"]) + .optional() + .transform((value) => value === "true"), + JUDGE_BASE_URL: z.string().optional(), + JUDGE_API_TOKEN: z.string().optional(), + CRON_SECRET: z.string().optional(), + }, + client: {}, + runtimeEnv: { + IS_DEMO_MODE: process.env.NEXT_PUBLIC_IS_DEMO_MODE, + SHOPIFY_STOREFRONT_ACCESS_TOKEN: process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN || "demo", + SHOPIFY_ADMIN_ACCESS_TOKEN: process.env.SHOPIFY_ADMIN_ACCESS_TOKEN || "demo", + SHOPIFY_APP_API_SECRET_KEY: process.env.SHOPIFY_APP_API_SECRET_KEY || "demo", + SHOPIFY_STORE_DOMAIN: process.env.SHOPIFY_STORE_DOMAIN || "demo", + SHOPIFY_HIERARCHICAL_NAV_HANDLE: process.env.SHOPIFY_HIERARCHICAL_NAV_HANDLE, + OPENAI_API_KEY: process.env.OPENAI_API_KEY, + LIVE_URL: process.env.LIVE_URL || "https://commerce.blazity.com", + ANALYZE: process.env.ANALYZE, + IS_GTM_ENABLED: process.env.IS_GTM_ENABLED, + IS_VERCEL_ANALYTICS_ENABLED: process.env.IS_VERCEL_ANALYTICS_ENABLED || "true", + IS_SPEED_INSIGHTS_ENABLED: process.env.IS_SPEED_INSIGHTS_ENABLED || "true", + GTM_ID: process.env.NEXT_PUBLIC_GTM_ID, + REPLICATE_API_KEY: process.env.REPLICATE_API_KEY, + JUDGE_BASE_URL: process.env.JUDGE_BASE_URL || "https://judge.me/api/v1", + JUDGE_API_TOKEN: process.env.JUDGE_API_TOKEN, + CRON_SECRET: process.env.CRON_SECRET, + }, +}) diff --git a/apps/web/jest.config.js b/starters/shopify-algolia/jest.config.js similarity index 100% rename from apps/web/jest.config.js rename to starters/shopify-algolia/jest.config.js diff --git a/apps/web/jest.setup.js b/starters/shopify-algolia/jest.setup.js similarity index 100% rename from apps/web/jest.setup.js rename to starters/shopify-algolia/jest.setup.js diff --git a/packages/reviews/judge/src/index.ts b/starters/shopify-algolia/lib/reviews/index.ts similarity index 87% rename from packages/reviews/judge/src/index.ts rename to starters/shopify-algolia/lib/reviews/index.ts index 8a09e7b1..15f89253 100644 --- a/packages/reviews/judge/src/index.ts +++ b/starters/shopify-algolia/lib/reviews/index.ts @@ -1,6 +1,4 @@ -import type { GetProductReviewsOpts, GetProductReviewsResponse, JudgeMeWebhookKey, ProductReviewArgs, ProductReviewBody } from "./types" - -export * from "./types" +import type { GetProductReviewsOpts, GetProductReviewsResponse, JudgeMeWebhookKey, ProductReviewArgs, ProductReviewBody, Review } from "./types" type CreateJudgeClientArgs = { baseUrl: string @@ -38,16 +36,15 @@ async function getProductReviews( const reviewsCountUrl = `${baseUrl.origin}${baseUrl.pathname}/reviews/count?${baseUrl.searchParams.toString()}` const reviewsCount = await fetch(reviewsCountUrl) - const { count } = await reviewsCount.json() + const { count } = (await reviewsCount.json()) as { count: number } - const reviews = await fetch(url) - const jsonReviews: Pick = await reviews.json() + const reviews = (await fetch(url).then((res) => res.json())) as Pick - return { ...jsonReviews, total: count, totalPages: Math.ceil(count / jsonReviews.per_page) } + return { ...reviews, total: count, totalPages: Math.ceil(count / reviews.per_page) } } async function getAllProductReviews(baseUrl: URL) { - const allReviews = [] + const allReviews: Review[] = [] const { reviews, totalPages } = await getProductReviews(baseUrl, { per_page: 100 }) allReviews.push(...reviews) diff --git a/packages/reviews/judge/src/types.ts b/starters/shopify-algolia/lib/reviews/types.ts similarity index 100% rename from packages/reviews/judge/src/types.ts rename to starters/shopify-algolia/lib/reviews/types.ts diff --git a/packages/core/platform/shopify/fragments/cart.ts b/starters/shopify-algolia/lib/shopify/fragments/cart.ts similarity index 100% rename from packages/core/platform/shopify/fragments/cart.ts rename to starters/shopify-algolia/lib/shopify/fragments/cart.ts diff --git a/packages/core/platform/shopify/fragments/collection.ts b/starters/shopify-algolia/lib/shopify/fragments/collection.ts similarity index 100% rename from packages/core/platform/shopify/fragments/collection.ts rename to starters/shopify-algolia/lib/shopify/fragments/collection.ts diff --git a/packages/core/platform/shopify/fragments/customer.ts b/starters/shopify-algolia/lib/shopify/fragments/customer.ts similarity index 100% rename from packages/core/platform/shopify/fragments/customer.ts rename to starters/shopify-algolia/lib/shopify/fragments/customer.ts diff --git a/packages/core/platform/shopify/fragments/image.ts b/starters/shopify-algolia/lib/shopify/fragments/image.ts similarity index 100% rename from packages/core/platform/shopify/fragments/image.ts rename to starters/shopify-algolia/lib/shopify/fragments/image.ts diff --git a/packages/core/platform/shopify/fragments/menu.ts b/starters/shopify-algolia/lib/shopify/fragments/menu.ts similarity index 100% rename from packages/core/platform/shopify/fragments/menu.ts rename to starters/shopify-algolia/lib/shopify/fragments/menu.ts diff --git a/packages/core/platform/shopify/fragments/page.ts b/starters/shopify-algolia/lib/shopify/fragments/page.ts similarity index 100% rename from packages/core/platform/shopify/fragments/page.ts rename to starters/shopify-algolia/lib/shopify/fragments/page.ts diff --git a/packages/core/platform/shopify/fragments/product.ts b/starters/shopify-algolia/lib/shopify/fragments/product.ts similarity index 100% rename from packages/core/platform/shopify/fragments/product.ts rename to starters/shopify-algolia/lib/shopify/fragments/product.ts diff --git a/packages/core/platform/shopify/fragments/seo.ts b/starters/shopify-algolia/lib/shopify/fragments/seo.ts similarity index 100% rename from packages/core/platform/shopify/fragments/seo.ts rename to starters/shopify-algolia/lib/shopify/fragments/seo.ts diff --git a/packages/core/platform/shopify/index.ts b/starters/shopify-algolia/lib/shopify/index.ts similarity index 99% rename from packages/core/platform/shopify/index.ts rename to starters/shopify-algolia/lib/shopify/index.ts index 2658feed..17c01fe7 100644 --- a/packages/core/platform/shopify/index.ts +++ b/starters/shopify-algolia/lib/shopify/index.ts @@ -54,7 +54,7 @@ import { PlatformProductStatus, PlatformUser, PlatformUserCreateInput, -} from "../types" +} from "./types" interface CreateShopifyClientProps { storeDomain: string diff --git a/packages/core/platform/shopify/mutations/cart.storefront.ts b/starters/shopify-algolia/lib/shopify/mutations/cart.storefront.ts similarity index 100% rename from packages/core/platform/shopify/mutations/cart.storefront.ts rename to starters/shopify-algolia/lib/shopify/mutations/cart.storefront.ts diff --git a/packages/core/platform/shopify/mutations/customer.storefront.ts b/starters/shopify-algolia/lib/shopify/mutations/customer.storefront.ts similarity index 100% rename from packages/core/platform/shopify/mutations/customer.storefront.ts rename to starters/shopify-algolia/lib/shopify/mutations/customer.storefront.ts diff --git a/packages/core/platform/shopify/mutations/product-feed.admin.ts b/starters/shopify-algolia/lib/shopify/mutations/product-feed.admin.ts similarity index 100% rename from packages/core/platform/shopify/mutations/product-feed.admin.ts rename to starters/shopify-algolia/lib/shopify/mutations/product-feed.admin.ts diff --git a/packages/core/platform/shopify/mutations/webhook.admin.ts b/starters/shopify-algolia/lib/shopify/mutations/webhook.admin.ts similarity index 100% rename from packages/core/platform/shopify/mutations/webhook.admin.ts rename to starters/shopify-algolia/lib/shopify/mutations/webhook.admin.ts diff --git a/packages/core/platform/shopify/normalize.ts b/starters/shopify-algolia/lib/shopify/normalize.ts similarity index 94% rename from packages/core/platform/shopify/normalize.ts rename to starters/shopify-algolia/lib/shopify/normalize.ts index aa9e2a27..7142b2aa 100644 --- a/packages/core/platform/shopify/normalize.ts +++ b/starters/shopify-algolia/lib/shopify/normalize.ts @@ -1,5 +1,5 @@ import { SingleCartQuery, SingleCollectionQuery, SingleProductQuery } from "./types/storefront.generated" -import { PlatformCart, PlatformCartItem, PlatformCollection, PlatformProduct } from "../types" +import type { PlatformCart, PlatformCartItem, PlatformCollection, PlatformProduct } from "./types" export function normalizeProduct(product: SingleProductQuery["product"]): PlatformProduct | null { if (!product) return null diff --git a/packages/core/platform/shopify/queries/cart.storefront.ts b/starters/shopify-algolia/lib/shopify/queries/cart.storefront.ts similarity index 100% rename from packages/core/platform/shopify/queries/cart.storefront.ts rename to starters/shopify-algolia/lib/shopify/queries/cart.storefront.ts diff --git a/packages/core/platform/shopify/queries/collection.storefront.ts b/starters/shopify-algolia/lib/shopify/queries/collection.storefront.ts similarity index 100% rename from packages/core/platform/shopify/queries/collection.storefront.ts rename to starters/shopify-algolia/lib/shopify/queries/collection.storefront.ts diff --git a/packages/core/platform/shopify/queries/customer.storefront.ts b/starters/shopify-algolia/lib/shopify/queries/customer.storefront.ts similarity index 100% rename from packages/core/platform/shopify/queries/customer.storefront.ts rename to starters/shopify-algolia/lib/shopify/queries/customer.storefront.ts diff --git a/packages/core/platform/shopify/queries/menu.storefront.ts b/starters/shopify-algolia/lib/shopify/queries/menu.storefront.ts similarity index 91% rename from packages/core/platform/shopify/queries/menu.storefront.ts rename to starters/shopify-algolia/lib/shopify/queries/menu.storefront.ts index 6899db50..a87bd02c 100644 --- a/packages/core/platform/shopify/queries/menu.storefront.ts +++ b/starters/shopify-algolia/lib/shopify/queries/menu.storefront.ts @@ -1,4 +1,4 @@ -import { PlatformMenu } from "../../types" +import { PlatformMenu } from "../types" import { createMenuItemFragment, menuItemFragment } from "../fragments/menu" /* Not using auto generated types here, as I'm either too bad using codegen-cli or it just does not work for such code */ diff --git a/packages/core/platform/shopify/queries/page.storefront.ts b/starters/shopify-algolia/lib/shopify/queries/page.storefront.ts similarity index 100% rename from packages/core/platform/shopify/queries/page.storefront.ts rename to starters/shopify-algolia/lib/shopify/queries/page.storefront.ts diff --git a/packages/core/platform/shopify/queries/product-feed.admin.ts b/starters/shopify-algolia/lib/shopify/queries/product-feed.admin.ts similarity index 100% rename from packages/core/platform/shopify/queries/product-feed.admin.ts rename to starters/shopify-algolia/lib/shopify/queries/product-feed.admin.ts diff --git a/packages/core/platform/shopify/queries/product.admin.ts b/starters/shopify-algolia/lib/shopify/queries/product.admin.ts similarity index 100% rename from packages/core/platform/shopify/queries/product.admin.ts rename to starters/shopify-algolia/lib/shopify/queries/product.admin.ts diff --git a/packages/core/platform/shopify/queries/product.storefront.ts b/starters/shopify-algolia/lib/shopify/queries/product.storefront.ts similarity index 100% rename from packages/core/platform/shopify/queries/product.storefront.ts rename to starters/shopify-algolia/lib/shopify/queries/product.storefront.ts diff --git a/packages/core/platform/shopify/types/admin/admin-2024-01.schema.json b/starters/shopify-algolia/lib/shopify/types/admin/admin-2024-01.schema.json similarity index 100% rename from packages/core/platform/shopify/types/admin/admin-2024-01.schema.json rename to starters/shopify-algolia/lib/shopify/types/admin/admin-2024-01.schema.json diff --git a/packages/core/platform/shopify/types/admin/admin.generated.d.ts b/starters/shopify-algolia/lib/shopify/types/admin/admin.generated.d.ts similarity index 100% rename from packages/core/platform/shopify/types/admin/admin.generated.d.ts rename to starters/shopify-algolia/lib/shopify/types/admin/admin.generated.d.ts diff --git a/packages/core/platform/shopify/types/admin/admin.types.d.ts b/starters/shopify-algolia/lib/shopify/types/admin/admin.types.d.ts similarity index 100% rename from packages/core/platform/shopify/types/admin/admin.types.d.ts rename to starters/shopify-algolia/lib/shopify/types/admin/admin.types.d.ts diff --git a/packages/core/platform/types.ts b/starters/shopify-algolia/lib/shopify/types/index.ts similarity index 98% rename from packages/core/platform/types.ts rename to starters/shopify-algolia/lib/shopify/types/index.ts index e29dfc2f..a2ee3a6b 100644 --- a/packages/core/platform/types.ts +++ b/starters/shopify-algolia/lib/shopify/types/index.ts @@ -1,4 +1,4 @@ -import { MenuItem } from "./shopify/types/storefront.types" +import { MenuItem } from "./storefront.types" export interface PlatformMenu { items: Array> diff --git a/packages/core/platform/shopify/types/storefront-2024-01.schema.json b/starters/shopify-algolia/lib/shopify/types/storefront-2024-01.schema.json similarity index 100% rename from packages/core/platform/shopify/types/storefront-2024-01.schema.json rename to starters/shopify-algolia/lib/shopify/types/storefront-2024-01.schema.json diff --git a/packages/core/platform/shopify/types/storefront.generated.d.ts b/starters/shopify-algolia/lib/shopify/types/storefront.generated.d.ts similarity index 99% rename from packages/core/platform/shopify/types/storefront.generated.d.ts rename to starters/shopify-algolia/lib/shopify/types/storefront.generated.d.ts index 8f473dc3..9115d23e 100644 --- a/packages/core/platform/shopify/types/storefront.generated.d.ts +++ b/starters/shopify-algolia/lib/shopify/types/storefront.generated.d.ts @@ -1,5 +1,3 @@ -/* eslint-disable eslint-comments/disable-enable-pair */ -/* eslint-disable eslint-comments/no-unlimited-disable */ /* eslint-disable */ import * as StorefrontTypes from './storefront.types.d.ts'; diff --git a/packages/core/platform/shopify/types/storefront.types.d.ts b/starters/shopify-algolia/lib/shopify/types/storefront.types.d.ts similarity index 100% rename from packages/core/platform/shopify/types/storefront.types.d.ts rename to starters/shopify-algolia/lib/shopify/types/storefront.types.d.ts diff --git a/apps/web/middleware.ts b/starters/shopify-algolia/middleware.ts similarity index 100% rename from apps/web/middleware.ts rename to starters/shopify-algolia/middleware.ts diff --git a/apps/web/next-env.d.ts b/starters/shopify-algolia/next-env.d.ts similarity index 100% rename from apps/web/next-env.d.ts rename to starters/shopify-algolia/next-env.d.ts diff --git a/starters/shopify-algolia/next.config.mjs b/starters/shopify-algolia/next.config.mjs new file mode 100644 index 00000000..83649460 --- /dev/null +++ b/starters/shopify-algolia/next.config.mjs @@ -0,0 +1,31 @@ +import withBundleAnalyzer from "@next/bundle-analyzer" +import withVercelToolbar from "@vercel/toolbar/plugins/next" +import withPlugins from "next-compose-plugins" + +/** + * @type {import('next').NextConfig} + */ +const config = withPlugins([[withVercelToolbar(), withBundleAnalyzer({ enabled: process.env.ANALYZE === "true" })]], { + reactStrictMode: true, + logging: { + fetches: { + fullUrl: true, + }, + }, + images: { + imageSizes: [256, 384], + deviceSizes: [320, 500, 750, 1080, 1200], + minimumCacheTTL: 31_556_926, + // formats: ["image/avif", "image/webp"], + formats: ["image/webp"], + remotePatterns: [ + { + protocol: "https", + hostname: "cdn.shopify.com", + port: "", + }, + ], + }, +}) + +export default config diff --git a/apps/web/package.json b/starters/shopify-algolia/package.json similarity index 87% rename from apps/web/package.json rename to starters/shopify-algolia/package.json index 66528c26..614afac5 100644 --- a/apps/web/package.json +++ b/starters/shopify-algolia/package.json @@ -1,5 +1,5 @@ { - "name": "@enterprise-commerce/web", + "name": "blazity-shopify-algolia-starter", "version": "1.0.0", "private": true, "scripts": { @@ -21,12 +21,11 @@ "format": "prettier --write \"**/*.{ts,tsx,md}\"", "postinstall": "npx patch-package -y", "generate-bloom-filter": "ts-node redirects/generate-bloom-filter.ts", + "codegen": "graphql-codegen && graphql-codegen -p admin", "coupling-graph": "npx madge --extensions js,jsx,ts,tsx,css,md,mdx ./ --exclude '.next|tailwind.config.js|reset.d.ts|prettier.config.js|postcss.config.js|playwright.config.ts|next.config.js|next-env.d.ts|instrumentation.ts|e2e/|README.md|.storybook/|.eslintrc.js' --image graph.svg" }, "dependencies": { "@ai-sdk/openai": "^0.0.16", - "@enterprise-commerce/reviews": "*", - "@enterprise-commerce/search-meilisearch": "*", "@hookform/resolvers": "^3.3.4", "@next/bundle-analyzer": "14.2.5", "@next/third-parties": "^14.1.4", @@ -76,9 +75,6 @@ "postcss": "^8.4.38" }, "devDependencies": { - "@enterprise-commerce/eslint-config-custom": "*", - "@enterprise-commerce/tailwind-config": "*", - "@enterprise-commerce/tsconfig": "*", "@playwright/test": "^1.42.1", "@storybook/addon-essentials": "^8.0.4", "@storybook/addon-interactions": "^8.0.4", @@ -93,6 +89,16 @@ "@testing-library/react": "^14.2.2", "@testing-library/dom": "^10.3.2", "@testing-library/user-event": "14.5.2", - "storybook": "^8.0.4" + "storybook": "^8.0.4", + "@vercel/style-guide": "^5.0.0", + "eslint-config-turbo": "^1.10.12", + "eslint": "8.54.0", + "eslint-config-next": "14.0.3", + "eslint-config-prettier": "^9.0.0", + "eslint-config-react-app": "^7.0.1", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-react": "7.33.2", + "eslint-plugin-storybook": "^0.6.15", + "eslint-plugin-tailwindcss": "^3.13.0" } } diff --git a/apps/web/playwright.config.ts b/starters/shopify-algolia/playwright.config.ts similarity index 100% rename from apps/web/playwright.config.ts rename to starters/shopify-algolia/playwright.config.ts diff --git a/apps/web/postcss.config.js b/starters/shopify-algolia/postcss.config.js similarity index 100% rename from apps/web/postcss.config.js rename to starters/shopify-algolia/postcss.config.js diff --git a/prettier.config.js b/starters/shopify-algolia/prettier.config.js similarity index 100% rename from prettier.config.js rename to starters/shopify-algolia/prettier.config.js diff --git a/apps/web/public/category-placeholder-1.svg b/starters/shopify-algolia/public/category-placeholder-1.svg similarity index 100% rename from apps/web/public/category-placeholder-1.svg rename to starters/shopify-algolia/public/category-placeholder-1.svg diff --git a/apps/web/public/category-placeholder-2.svg b/starters/shopify-algolia/public/category-placeholder-2.svg similarity index 100% rename from apps/web/public/category-placeholder-2.svg rename to starters/shopify-algolia/public/category-placeholder-2.svg diff --git a/apps/web/public/category-placeholder-3.svg b/starters/shopify-algolia/public/category-placeholder-3.svg similarity index 100% rename from apps/web/public/category-placeholder-3.svg rename to starters/shopify-algolia/public/category-placeholder-3.svg diff --git a/apps/web/public/category-placeholder-4.svg b/starters/shopify-algolia/public/category-placeholder-4.svg similarity index 100% rename from apps/web/public/category-placeholder-4.svg rename to starters/shopify-algolia/public/category-placeholder-4.svg diff --git a/apps/web/public/category-placeholder-5.svg b/starters/shopify-algolia/public/category-placeholder-5.svg similarity index 100% rename from apps/web/public/category-placeholder-5.svg rename to starters/shopify-algolia/public/category-placeholder-5.svg diff --git a/apps/web/public/category-placeholder-6.svg b/starters/shopify-algolia/public/category-placeholder-6.svg similarity index 100% rename from apps/web/public/category-placeholder-6.svg rename to starters/shopify-algolia/public/category-placeholder-6.svg diff --git a/apps/web/public/default-product-image.svg b/starters/shopify-algolia/public/default-product-image.svg similarity index 100% rename from apps/web/public/default-product-image.svg rename to starters/shopify-algolia/public/default-product-image.svg diff --git a/apps/web/public/demo-categories-data.json b/starters/shopify-algolia/public/demo-categories-data.json similarity index 100% rename from apps/web/public/demo-categories-data.json rename to starters/shopify-algolia/public/demo-categories-data.json diff --git a/apps/web/public/demo-data.json b/starters/shopify-algolia/public/demo-data.json similarity index 100% rename from apps/web/public/demo-data.json rename to starters/shopify-algolia/public/demo-data.json diff --git a/apps/web/public/demo-product-reviews-data.json b/starters/shopify-algolia/public/demo-product-reviews-data.json similarity index 100% rename from apps/web/public/demo-product-reviews-data.json rename to starters/shopify-algolia/public/demo-product-reviews-data.json diff --git a/apps/web/public/fonts/Inter-Black.ttf b/starters/shopify-algolia/public/fonts/Inter-Black.ttf similarity index 100% rename from apps/web/public/fonts/Inter-Black.ttf rename to starters/shopify-algolia/public/fonts/Inter-Black.ttf diff --git a/apps/web/public/fonts/Inter-Bold.ttf b/starters/shopify-algolia/public/fonts/Inter-Bold.ttf similarity index 100% rename from apps/web/public/fonts/Inter-Bold.ttf rename to starters/shopify-algolia/public/fonts/Inter-Bold.ttf diff --git a/apps/web/public/fonts/Inter-ExtraBold.ttf b/starters/shopify-algolia/public/fonts/Inter-ExtraBold.ttf similarity index 100% rename from apps/web/public/fonts/Inter-ExtraBold.ttf rename to starters/shopify-algolia/public/fonts/Inter-ExtraBold.ttf diff --git a/apps/web/public/fonts/Inter-ExtraLight.ttf b/starters/shopify-algolia/public/fonts/Inter-ExtraLight.ttf similarity index 100% rename from apps/web/public/fonts/Inter-ExtraLight.ttf rename to starters/shopify-algolia/public/fonts/Inter-ExtraLight.ttf diff --git a/apps/web/public/fonts/Inter-Light.ttf b/starters/shopify-algolia/public/fonts/Inter-Light.ttf similarity index 100% rename from apps/web/public/fonts/Inter-Light.ttf rename to starters/shopify-algolia/public/fonts/Inter-Light.ttf diff --git a/apps/web/public/fonts/Inter-Medium.ttf b/starters/shopify-algolia/public/fonts/Inter-Medium.ttf similarity index 100% rename from apps/web/public/fonts/Inter-Medium.ttf rename to starters/shopify-algolia/public/fonts/Inter-Medium.ttf diff --git a/apps/web/public/fonts/Inter-Regular.ttf b/starters/shopify-algolia/public/fonts/Inter-Regular.ttf similarity index 100% rename from apps/web/public/fonts/Inter-Regular.ttf rename to starters/shopify-algolia/public/fonts/Inter-Regular.ttf diff --git a/apps/web/public/fonts/Inter-SemiBold.ttf b/starters/shopify-algolia/public/fonts/Inter-SemiBold.ttf similarity index 100% rename from apps/web/public/fonts/Inter-SemiBold.ttf rename to starters/shopify-algolia/public/fonts/Inter-SemiBold.ttf diff --git a/apps/web/public/fonts/Inter-Thin.ttf b/starters/shopify-algolia/public/fonts/Inter-Thin.ttf similarity index 100% rename from apps/web/public/fonts/Inter-Thin.ttf rename to starters/shopify-algolia/public/fonts/Inter-Thin.ttf diff --git a/apps/web/public/menu/beauty-1.png b/starters/shopify-algolia/public/menu/beauty-1.png similarity index 100% rename from apps/web/public/menu/beauty-1.png rename to starters/shopify-algolia/public/menu/beauty-1.png diff --git a/apps/web/public/menu/beauty-2.png b/starters/shopify-algolia/public/menu/beauty-2.png similarity index 100% rename from apps/web/public/menu/beauty-2.png rename to starters/shopify-algolia/public/menu/beauty-2.png diff --git a/apps/web/public/menu/beauty-3.png b/starters/shopify-algolia/public/menu/beauty-3.png similarity index 100% rename from apps/web/public/menu/beauty-3.png rename to starters/shopify-algolia/public/menu/beauty-3.png diff --git a/apps/web/public/menu/beauty-4.png b/starters/shopify-algolia/public/menu/beauty-4.png similarity index 100% rename from apps/web/public/menu/beauty-4.png rename to starters/shopify-algolia/public/menu/beauty-4.png diff --git a/apps/web/public/menu/beauty-5.png b/starters/shopify-algolia/public/menu/beauty-5.png similarity index 100% rename from apps/web/public/menu/beauty-5.png rename to starters/shopify-algolia/public/menu/beauty-5.png diff --git a/apps/web/public/menu/electronics-1.png b/starters/shopify-algolia/public/menu/electronics-1.png similarity index 100% rename from apps/web/public/menu/electronics-1.png rename to starters/shopify-algolia/public/menu/electronics-1.png diff --git a/apps/web/public/menu/electronics-2.png b/starters/shopify-algolia/public/menu/electronics-2.png similarity index 100% rename from apps/web/public/menu/electronics-2.png rename to starters/shopify-algolia/public/menu/electronics-2.png diff --git a/apps/web/public/menu/electronics-3.png b/starters/shopify-algolia/public/menu/electronics-3.png similarity index 100% rename from apps/web/public/menu/electronics-3.png rename to starters/shopify-algolia/public/menu/electronics-3.png diff --git a/apps/web/public/menu/electronics-4.png b/starters/shopify-algolia/public/menu/electronics-4.png similarity index 100% rename from apps/web/public/menu/electronics-4.png rename to starters/shopify-algolia/public/menu/electronics-4.png diff --git a/apps/web/public/menu/furniture-1.png b/starters/shopify-algolia/public/menu/furniture-1.png similarity index 100% rename from apps/web/public/menu/furniture-1.png rename to starters/shopify-algolia/public/menu/furniture-1.png diff --git a/apps/web/public/menu/furniture-2.png b/starters/shopify-algolia/public/menu/furniture-2.png similarity index 100% rename from apps/web/public/menu/furniture-2.png rename to starters/shopify-algolia/public/menu/furniture-2.png diff --git a/apps/web/public/menu/furniture-3.png b/starters/shopify-algolia/public/menu/furniture-3.png similarity index 100% rename from apps/web/public/menu/furniture-3.png rename to starters/shopify-algolia/public/menu/furniture-3.png diff --git a/apps/web/public/menu/furniture-4.png b/starters/shopify-algolia/public/menu/furniture-4.png similarity index 100% rename from apps/web/public/menu/furniture-4.png rename to starters/shopify-algolia/public/menu/furniture-4.png diff --git a/apps/web/redirects/bloom-filter.json b/starters/shopify-algolia/redirects/bloom-filter.json similarity index 100% rename from apps/web/redirects/bloom-filter.json rename to starters/shopify-algolia/redirects/bloom-filter.json diff --git a/apps/web/redirects/generate-bloom-filter.ts b/starters/shopify-algolia/redirects/generate-bloom-filter.ts similarity index 100% rename from apps/web/redirects/generate-bloom-filter.ts rename to starters/shopify-algolia/redirects/generate-bloom-filter.ts diff --git a/apps/web/redirects/new-redirects.json b/starters/shopify-algolia/redirects/new-redirects.json similarity index 100% rename from apps/web/redirects/new-redirects.json rename to starters/shopify-algolia/redirects/new-redirects.json diff --git a/apps/web/redirects/redirects.json b/starters/shopify-algolia/redirects/redirects.json similarity index 100% rename from apps/web/redirects/redirects.json rename to starters/shopify-algolia/redirects/redirects.json diff --git a/apps/web/report-bundle-size.js b/starters/shopify-algolia/report-bundle-size.js similarity index 100% rename from apps/web/report-bundle-size.js rename to starters/shopify-algolia/report-bundle-size.js diff --git a/apps/web/reset.d.ts b/starters/shopify-algolia/reset.d.ts similarity index 100% rename from apps/web/reset.d.ts rename to starters/shopify-algolia/reset.d.ts diff --git a/apps/web/shopify-webhooks.d.ts b/starters/shopify-algolia/shopify-webhooks.d.ts similarity index 100% rename from apps/web/shopify-webhooks.d.ts rename to starters/shopify-algolia/shopify-webhooks.d.ts diff --git a/apps/web/stores/addProductStore.ts b/starters/shopify-algolia/stores/addProductStore.ts similarity index 88% rename from apps/web/stores/addProductStore.ts rename to starters/shopify-algolia/stores/addProductStore.ts index ec33583c..847aed1e 100644 --- a/apps/web/stores/addProductStore.ts +++ b/starters/shopify-algolia/stores/addProductStore.ts @@ -1,4 +1,4 @@ -import type { PlatformVariant } from "@enterprise-commerce/core/platform/types" +import type { PlatformVariant } from "lib/shopify/types" import type { CommerceProduct } from "types" import type { Combination } from "utils/productOptionsUtils" import { create } from "zustand" diff --git a/apps/web/stores/cartStore.ts b/starters/shopify-algolia/stores/cartStore.ts similarity index 92% rename from apps/web/stores/cartStore.ts rename to starters/shopify-algolia/stores/cartStore.ts index 96d4ddbc..97c065fb 100644 --- a/apps/web/stores/cartStore.ts +++ b/starters/shopify-algolia/stores/cartStore.ts @@ -1,4 +1,4 @@ -import { PlatformCart } from "@enterprise-commerce/core/platform/types" +import { PlatformCart } from "lib/shopify/types" import { create } from "zustand" interface CartStore { diff --git a/apps/web/stores/filterTransitionStore.ts b/starters/shopify-algolia/stores/filterTransitionStore.ts similarity index 100% rename from apps/web/stores/filterTransitionStore.ts rename to starters/shopify-algolia/stores/filterTransitionStore.ts diff --git a/apps/web/stores/filtersStore.ts b/starters/shopify-algolia/stores/filtersStore.ts similarity index 100% rename from apps/web/stores/filtersStore.ts rename to starters/shopify-algolia/stores/filtersStore.ts diff --git a/apps/web/stores/modalStore.ts b/starters/shopify-algolia/stores/modalStore.ts similarity index 77% rename from apps/web/stores/modalStore.ts rename to starters/shopify-algolia/stores/modalStore.ts index a498342d..cc57ad55 100644 --- a/apps/web/stores/modalStore.ts +++ b/starters/shopify-algolia/stores/modalStore.ts @@ -24,9 +24,12 @@ export const useModalStore = create((set) => ({ closeAllModals: () => set((state) => ({ - modals: Object.keys(state.modals).reduce((acc, modalId) => { - acc[modalId] = false - return acc - }, {}), + modals: Object.keys(state.modals).reduce( + (acc, modalId) => { + acc[modalId as Modal] = false + return acc + }, + {} as Record + ), })), })) diff --git a/apps/web/stores/userStore.ts b/starters/shopify-algolia/stores/userStore.ts similarity index 60% rename from apps/web/stores/userStore.ts rename to starters/shopify-algolia/stores/userStore.ts index f92c66ea..28ea92da 100644 --- a/apps/web/stores/userStore.ts +++ b/starters/shopify-algolia/stores/userStore.ts @@ -1,4 +1,4 @@ -import { PlatformUser } from "@enterprise-commerce/core/platform/types" +import { PlatformUser } from "lib/shopify/types" import { create } from "zustand" interface UserStore { @@ -8,5 +8,5 @@ interface UserStore { export const useUserStore = create((set) => ({ user: null, - setUser: (payload: PlatformUser) => set(() => ({ user: payload })), + setUser: (payload: PlatformUser | null) => set(() => ({ user: payload })), })) diff --git a/packages/tailwind-config/tailwind.config.ts b/starters/shopify-algolia/tailwind.config.ts similarity index 91% rename from packages/tailwind-config/tailwind.config.ts rename to starters/shopify-algolia/tailwind.config.ts index 1bfc701b..f8967d12 100644 --- a/packages/tailwind-config/tailwind.config.ts +++ b/starters/shopify-algolia/tailwind.config.ts @@ -1,8 +1,17 @@ import type { Config } from "tailwindcss" import defaultTheme from "tailwindcss/defaultTheme" -// We want each package to be responsible for its own content. const config: Omit = { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + "./**/*.{js,ts,jsx,tsx}", + "./dist/**/*.{js,ts,jsx,tsx}", + "./app/**/*.{js,ts,jsx,tsx,mdx}", + "./pages/**/*.{js,ts,jsx,tsx,mdx}", + "./components/**/*.{js,ts,jsx,tsx,mdx}", + "./src/**/*.{js,ts,jsx,tsx,mdx}", + ], darkMode: "class", corePlugins: { preflight: false, diff --git a/starters/shopify-algolia/tsconfig.json b/starters/shopify-algolia/tsconfig.json new file mode 100644 index 00000000..ac9fbb9d --- /dev/null +++ b/starters/shopify-algolia/tsconfig.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Next.js", + "compilerOptions": { + "composite": false, + "declaration": false, + "declarationMap": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "allowImportingTsExtensions": true, + "noEmit": true, + "inlineSources": false, + "isolatedModules": true, + "module": "esnext", + "moduleResolution": "bundler", + "noUnusedLocals": false, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "noImplicitAny": false, + "skipLibCheck": true, + "strict": true, + "strictNullChecks": true, + "allowJs": true, + "incremental": true, + "jsx": "preserve", + "lib": ["dom", "dom.iterable", "esnext"], + "resolveJsonModule": true, + "target": "es5", + "plugins": [{ "name": "next" }], + "baseUrl": "." + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/apps/web/types/index.ts b/starters/shopify-algolia/types/index.ts similarity index 80% rename from apps/web/types/index.ts rename to starters/shopify-algolia/types/index.ts index 3a9e68e3..490232a2 100644 --- a/apps/web/types/index.ts +++ b/starters/shopify-algolia/types/index.ts @@ -1,4 +1,4 @@ -import { PlatformProduct } from "@enterprise-commerce/core/platform/types" +import { PlatformProduct } from "lib/shopify/types" export type SearchParamsType = Record diff --git a/apps/web/utils/abTesting.ts b/starters/shopify-algolia/utils/abTesting.ts similarity index 100% rename from apps/web/utils/abTesting.ts rename to starters/shopify-algolia/utils/abTesting.ts diff --git a/apps/web/utils/authenticate-api-route.ts b/starters/shopify-algolia/utils/authenticate-api-route.ts similarity index 100% rename from apps/web/utils/authenticate-api-route.ts rename to starters/shopify-algolia/utils/authenticate-api-route.ts diff --git a/apps/web/utils/cn.ts b/starters/shopify-algolia/utils/cn.ts similarity index 100% rename from apps/web/utils/cn.ts rename to starters/shopify-algolia/utils/cn.ts diff --git a/apps/web/utils/compare-hmac.ts b/starters/shopify-algolia/utils/compare-hmac.ts similarity index 100% rename from apps/web/utils/compare-hmac.ts rename to starters/shopify-algolia/utils/compare-hmac.ts diff --git a/apps/web/utils/demoUtils.ts b/starters/shopify-algolia/utils/demoUtils.ts similarity index 100% rename from apps/web/utils/demoUtils.ts rename to starters/shopify-algolia/utils/demoUtils.ts diff --git a/apps/web/utils/enrich-product.ts b/starters/shopify-algolia/utils/enrich-product.ts similarity index 96% rename from apps/web/utils/enrich-product.ts rename to starters/shopify-algolia/utils/enrich-product.ts index 77ef9754..55fc4a11 100644 --- a/apps/web/utils/enrich-product.ts +++ b/starters/shopify-algolia/utils/enrich-product.ts @@ -1,4 +1,4 @@ -import { PlatformImage, PlatformMenu, PlatformProduct } from "@enterprise-commerce/core/platform/types" +import { PlatformImage, PlatformMenu, PlatformProduct } from "lib/shopify/types" import { replicate } from "clients/replicate" /* diff --git a/apps/web/utils/filterBuilder.test.ts b/starters/shopify-algolia/utils/filterBuilder.test.ts similarity index 100% rename from apps/web/utils/filterBuilder.test.ts rename to starters/shopify-algolia/utils/filterBuilder.test.ts diff --git a/apps/web/utils/filterBuilder.ts b/starters/shopify-algolia/utils/filterBuilder.ts similarity index 100% rename from apps/web/utils/filterBuilder.ts rename to starters/shopify-algolia/utils/filterBuilder.ts diff --git a/apps/web/utils/getCookie.ts b/starters/shopify-algolia/utils/getCookie.ts similarity index 100% rename from apps/web/utils/getCookie.ts rename to starters/shopify-algolia/utils/getCookie.ts diff --git a/apps/web/utils/getVercelFlagOverrides.ts b/starters/shopify-algolia/utils/getVercelFlagOverrides.ts similarity index 100% rename from apps/web/utils/getVercelFlagOverrides.ts rename to starters/shopify-algolia/utils/getVercelFlagOverrides.ts diff --git a/apps/web/utils/highlightedText.tsx b/starters/shopify-algolia/utils/highlightedText.tsx similarity index 100% rename from apps/web/utils/highlightedText.tsx rename to starters/shopify-algolia/utils/highlightedText.tsx diff --git a/apps/web/utils/makeKeywords.ts b/starters/shopify-algolia/utils/makeKeywords.ts similarity index 95% rename from apps/web/utils/makeKeywords.ts rename to starters/shopify-algolia/utils/makeKeywords.ts index 88c56f8f..4ad790d3 100644 --- a/apps/web/utils/makeKeywords.ts +++ b/starters/shopify-algolia/utils/makeKeywords.ts @@ -65,7 +65,7 @@ export function makeKeywords(content: string | null | undefined) { let words = content.toLowerCase().match(/\b(\w+)\b/g) as string[] words = words.filter((word) => !STOP_WORDS.includes(word)) - const frequency = {} + const frequency: Record = {} words.forEach((word) => { if (!frequency[word]) { frequency[word] = 0 diff --git a/apps/web/utils/mapCurrencyToSign.ts b/starters/shopify-algolia/utils/mapCurrencyToSign.ts similarity index 100% rename from apps/web/utils/mapCurrencyToSign.ts rename to starters/shopify-algolia/utils/mapCurrencyToSign.ts diff --git a/apps/web/utils/opt-in.ts b/starters/shopify-algolia/utils/opt-in.ts similarity index 84% rename from apps/web/utils/opt-in.ts rename to starters/shopify-algolia/utils/opt-in.ts index ddc54599..417cd122 100644 --- a/apps/web/utils/opt-in.ts +++ b/starters/shopify-algolia/utils/opt-in.ts @@ -13,7 +13,7 @@ const features: Record> = { }, } -const optInNotification = ({ message, source }) => { +const optInNotification = ({ message, source }: { message: string; source?: string }) => { console.warn({ message, source, @@ -25,7 +25,7 @@ export const isOptIn = (feature: Feature) => { } export const notifyOptIn = ({ feature, source }: { feature: Feature; source?: string }) => { - optInNotification({ message: features[feature].message, source }) + optInNotification({ message: features[feature].message as string, source }) return "This feature is not enabled, to enable set required keys" } diff --git a/apps/web/utils/productOptionsUtils.ts b/starters/shopify-algolia/utils/productOptionsUtils.ts similarity index 96% rename from apps/web/utils/productOptionsUtils.ts rename to starters/shopify-algolia/utils/productOptionsUtils.ts index abfb0f47..e4dead1d 100644 --- a/apps/web/utils/productOptionsUtils.ts +++ b/starters/shopify-algolia/utils/productOptionsUtils.ts @@ -1,4 +1,4 @@ -import { PlatformVariant } from "@enterprise-commerce/core/platform/types" +import { PlatformVariant } from "lib/shopify/types" import type { CommerceProduct } from "types" export interface Combination { diff --git a/apps/web/utils/slug-name.ts b/starters/shopify-algolia/utils/slug-name.ts similarity index 100% rename from apps/web/utils/slug-name.ts rename to starters/shopify-algolia/utils/slug-name.ts diff --git a/apps/web/utils/useAutocomplete.ts b/starters/shopify-algolia/utils/useAutocomplete.ts similarity index 100% rename from apps/web/utils/useAutocomplete.ts rename to starters/shopify-algolia/utils/useAutocomplete.ts diff --git a/apps/web/utils/useHierarchicalMenu.ts b/starters/shopify-algolia/utils/useHierarchicalMenu.ts similarity index 100% rename from apps/web/utils/useHierarchicalMenu.ts rename to starters/shopify-algolia/utils/useHierarchicalMenu.ts diff --git a/apps/web/utils/useReadMore.ts b/starters/shopify-algolia/utils/useReadMore.ts similarity index 100% rename from apps/web/utils/useReadMore.ts rename to starters/shopify-algolia/utils/useReadMore.ts diff --git a/apps/web/vercel.json b/starters/shopify-algolia/vercel.json similarity index 100% rename from apps/web/vercel.json rename to starters/shopify-algolia/vercel.json diff --git a/apps/web/views/Cart/CartItem.tsx b/starters/shopify-algolia/views/Cart/CartItem.tsx similarity index 96% rename from apps/web/views/Cart/CartItem.tsx rename to starters/shopify-algolia/views/Cart/CartItem.tsx index 56bd987a..6c6db1f5 100644 --- a/apps/web/views/Cart/CartItem.tsx +++ b/starters/shopify-algolia/views/Cart/CartItem.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/no-children-prop */ -import { PlatformCartItem } from "@enterprise-commerce/core/platform/types" +import { PlatformCartItem } from "lib/shopify/types" import Image from "next/image" import Link from "next/link" import { cn } from "utils/cn" diff --git a/apps/web/views/Cart/CartSheet.tsx b/starters/shopify-algolia/views/Cart/CartSheet.tsx similarity index 98% rename from apps/web/views/Cart/CartSheet.tsx rename to starters/shopify-algolia/views/Cart/CartSheet.tsx index 2c3539d1..1b3867e0 100644 --- a/apps/web/views/Cart/CartSheet.tsx +++ b/starters/shopify-algolia/views/Cart/CartSheet.tsx @@ -1,4 +1,4 @@ -import { PlatformCart } from "@enterprise-commerce/core/platform/types" +import { PlatformCart } from "lib/shopify/types" import { Button } from "components/Button/Button" import { CloseIcon } from "components/Icons/CloseIcon" import { Sheet, SheetClose, SheetContent, SheetFooter, SheetHeader, SheetTitle } from "components/Sheet/Sheet" diff --git a/apps/web/views/Cart/CartView.tsx b/starters/shopify-algolia/views/Cart/CartView.tsx similarity index 100% rename from apps/web/views/Cart/CartView.tsx rename to starters/shopify-algolia/views/Cart/CartView.tsx diff --git a/apps/web/views/Cart/ChangeQuantityButton.tsx b/starters/shopify-algolia/views/Cart/ChangeQuantityButton.tsx similarity index 100% rename from apps/web/views/Cart/ChangeQuantityButton.tsx rename to starters/shopify-algolia/views/Cart/ChangeQuantityButton.tsx diff --git a/apps/web/views/Cart/DeleteButton.tsx b/starters/shopify-algolia/views/Cart/DeleteButton.tsx similarity index 100% rename from apps/web/views/Cart/DeleteButton.tsx rename to starters/shopify-algolia/views/Cart/DeleteButton.tsx diff --git a/apps/web/views/Category/CategoryView.tsx b/starters/shopify-algolia/views/Category/CategoryView.tsx similarity index 100% rename from apps/web/views/Category/CategoryView.tsx rename to starters/shopify-algolia/views/Category/CategoryView.tsx diff --git a/apps/web/views/Category/PageSkeleton.tsx b/starters/shopify-algolia/views/Category/PageSkeleton.tsx similarity index 100% rename from apps/web/views/Category/PageSkeleton.tsx rename to starters/shopify-algolia/views/Category/PageSkeleton.tsx diff --git a/apps/web/views/DemoModeAlert.tsx b/starters/shopify-algolia/views/DemoModeAlert.tsx similarity index 100% rename from apps/web/views/DemoModeAlert.tsx rename to starters/shopify-algolia/views/DemoModeAlert.tsx diff --git a/apps/web/views/DraftToolbar.tsx b/starters/shopify-algolia/views/DraftToolbar.tsx similarity index 100% rename from apps/web/views/DraftToolbar.tsx rename to starters/shopify-algolia/views/DraftToolbar.tsx diff --git a/apps/web/views/FlagValues.tsx b/starters/shopify-algolia/views/FlagValues.tsx similarity index 100% rename from apps/web/views/FlagValues.tsx rename to starters/shopify-algolia/views/FlagValues.tsx diff --git a/apps/web/views/GithubBadge.tsx b/starters/shopify-algolia/views/GithubBadge.tsx similarity index 100% rename from apps/web/views/GithubBadge.tsx rename to starters/shopify-algolia/views/GithubBadge.tsx diff --git a/apps/web/views/Homepage/BestOffersSection.tsx b/starters/shopify-algolia/views/Homepage/BestOffersSection.tsx similarity index 100% rename from apps/web/views/Homepage/BestOffersSection.tsx rename to starters/shopify-algolia/views/Homepage/BestOffersSection.tsx diff --git a/apps/web/views/Homepage/CarouselSection.tsx b/starters/shopify-algolia/views/Homepage/CarouselSection.tsx similarity index 100% rename from apps/web/views/Homepage/CarouselSection.tsx rename to starters/shopify-algolia/views/Homepage/CarouselSection.tsx diff --git a/apps/web/views/Homepage/CategoriesSection.tsx b/starters/shopify-algolia/views/Homepage/CategoriesSection.tsx similarity index 100% rename from apps/web/views/Homepage/CategoriesSection.tsx rename to starters/shopify-algolia/views/Homepage/CategoriesSection.tsx diff --git a/apps/web/views/Homepage/EverythingUnderSection.tsx b/starters/shopify-algolia/views/Homepage/EverythingUnderSection.tsx similarity index 100% rename from apps/web/views/Homepage/EverythingUnderSection.tsx rename to starters/shopify-algolia/views/Homepage/EverythingUnderSection.tsx diff --git a/apps/web/views/Homepage/HeroSection.tsx b/starters/shopify-algolia/views/Homepage/HeroSection.tsx similarity index 100% rename from apps/web/views/Homepage/HeroSection.tsx rename to starters/shopify-algolia/views/Homepage/HeroSection.tsx diff --git a/apps/web/views/Homepage/ProductsWeekSection.tsx b/starters/shopify-algolia/views/Homepage/ProductsWeekSection.tsx similarity index 100% rename from apps/web/views/Homepage/ProductsWeekSection.tsx rename to starters/shopify-algolia/views/Homepage/ProductsWeekSection.tsx diff --git a/apps/web/views/Listing/CategoryFacet.tsx b/starters/shopify-algolia/views/Listing/CategoryFacet.tsx similarity index 100% rename from apps/web/views/Listing/CategoryFacet.tsx rename to starters/shopify-algolia/views/Listing/CategoryFacet.tsx diff --git a/apps/web/views/Listing/Controls.tsx b/starters/shopify-algolia/views/Listing/Controls.tsx similarity index 100% rename from apps/web/views/Listing/Controls.tsx rename to starters/shopify-algolia/views/Listing/Controls.tsx diff --git a/apps/web/views/Listing/Facet.tsx b/starters/shopify-algolia/views/Listing/Facet.tsx similarity index 100% rename from apps/web/views/Listing/Facet.tsx rename to starters/shopify-algolia/views/Listing/Facet.tsx diff --git a/apps/web/views/Listing/FacetsContent.tsx b/starters/shopify-algolia/views/Listing/FacetsContent.tsx similarity index 100% rename from apps/web/views/Listing/FacetsContent.tsx rename to starters/shopify-algolia/views/Listing/FacetsContent.tsx diff --git a/apps/web/views/Listing/FacetsDesktop.tsx b/starters/shopify-algolia/views/Listing/FacetsDesktop.tsx similarity index 100% rename from apps/web/views/Listing/FacetsDesktop.tsx rename to starters/shopify-algolia/views/Listing/FacetsDesktop.tsx diff --git a/apps/web/views/Listing/FacetsMobile.tsx b/starters/shopify-algolia/views/Listing/FacetsMobile.tsx similarity index 100% rename from apps/web/views/Listing/FacetsMobile.tsx rename to starters/shopify-algolia/views/Listing/FacetsMobile.tsx diff --git a/apps/web/views/Listing/HideFilters.tsx b/starters/shopify-algolia/views/Listing/HideFilters.tsx similarity index 100% rename from apps/web/views/Listing/HideFilters.tsx rename to starters/shopify-algolia/views/Listing/HideFilters.tsx diff --git a/apps/web/views/Listing/HitsSection.tsx b/starters/shopify-algolia/views/Listing/HitsSection.tsx similarity index 100% rename from apps/web/views/Listing/HitsSection.tsx rename to starters/shopify-algolia/views/Listing/HitsSection.tsx diff --git a/apps/web/views/Listing/PageSkeleton.tsx b/starters/shopify-algolia/views/Listing/PageSkeleton.tsx similarity index 100% rename from apps/web/views/Listing/PageSkeleton.tsx rename to starters/shopify-algolia/views/Listing/PageSkeleton.tsx diff --git a/apps/web/views/Listing/PaginationSection.tsx b/starters/shopify-algolia/views/Listing/PaginationSection.tsx similarity index 100% rename from apps/web/views/Listing/PaginationSection.tsx rename to starters/shopify-algolia/views/Listing/PaginationSection.tsx diff --git a/apps/web/views/Listing/PriceFacet.tsx b/starters/shopify-algolia/views/Listing/PriceFacet.tsx similarity index 100% rename from apps/web/views/Listing/PriceFacet.tsx rename to starters/shopify-algolia/views/Listing/PriceFacet.tsx diff --git a/apps/web/views/Listing/RatingFacet.tsx b/starters/shopify-algolia/views/Listing/RatingFacet.tsx similarity index 100% rename from apps/web/views/Listing/RatingFacet.tsx rename to starters/shopify-algolia/views/Listing/RatingFacet.tsx diff --git a/apps/web/views/Listing/SearchFacet.tsx b/starters/shopify-algolia/views/Listing/SearchFacet.tsx similarity index 100% rename from apps/web/views/Listing/SearchFacet.tsx rename to starters/shopify-algolia/views/Listing/SearchFacet.tsx diff --git a/apps/web/views/Listing/Sorter.tsx b/starters/shopify-algolia/views/Listing/Sorter.tsx similarity index 100% rename from apps/web/views/Listing/Sorter.tsx rename to starters/shopify-algolia/views/Listing/Sorter.tsx diff --git a/apps/web/views/Listing/composeFilters.test.ts b/starters/shopify-algolia/views/Listing/composeFilters.test.ts similarity index 100% rename from apps/web/views/Listing/composeFilters.test.ts rename to starters/shopify-algolia/views/Listing/composeFilters.test.ts diff --git a/apps/web/views/Listing/composeFilters.ts b/starters/shopify-algolia/views/Listing/composeFilters.ts similarity index 100% rename from apps/web/views/Listing/composeFilters.ts rename to starters/shopify-algolia/views/Listing/composeFilters.ts diff --git a/apps/web/views/Product/AddToCartButton.tsx b/starters/shopify-algolia/views/Product/AddToCartButton.tsx similarity index 96% rename from apps/web/views/Product/AddToCartButton.tsx rename to starters/shopify-algolia/views/Product/AddToCartButton.tsx index bcb1cbec..aba88850 100644 --- a/apps/web/views/Product/AddToCartButton.tsx +++ b/starters/shopify-algolia/views/Product/AddToCartButton.tsx @@ -1,6 +1,6 @@ "use client" -import type { PlatformVariant } from "@enterprise-commerce/core/platform/types" +import type { PlatformVariant } from "lib/shopify/types" import { addCartItem, getItemAvailability } from "app/actions/cart.actions" import { Button } from "components/Button/ButtonNew" import { useEffect, useState } from "react" diff --git a/apps/web/views/Product/BackButton.tsx b/starters/shopify-algolia/views/Product/BackButton.tsx similarity index 100% rename from apps/web/views/Product/BackButton.tsx rename to starters/shopify-algolia/views/Product/BackButton.tsx diff --git a/apps/web/views/Product/CenterImageSection.tsx b/starters/shopify-algolia/views/Product/CenterImageSection.tsx similarity index 100% rename from apps/web/views/Product/CenterImageSection.tsx rename to starters/shopify-algolia/views/Product/CenterImageSection.tsx diff --git a/apps/web/views/Product/FaqSection.tsx b/starters/shopify-algolia/views/Product/FaqSection.tsx similarity index 100% rename from apps/web/views/Product/FaqSection.tsx rename to starters/shopify-algolia/views/Product/FaqSection.tsx diff --git a/apps/web/views/Product/FavoriteMarker.tsx b/starters/shopify-algolia/views/Product/FavoriteMarker.tsx similarity index 100% rename from apps/web/views/Product/FavoriteMarker.tsx rename to starters/shopify-algolia/views/Product/FavoriteMarker.tsx diff --git a/apps/web/views/Product/PageSkeleton.tsx b/starters/shopify-algolia/views/Product/PageSkeleton.tsx similarity index 100% rename from apps/web/views/Product/PageSkeleton.tsx rename to starters/shopify-algolia/views/Product/PageSkeleton.tsx diff --git a/apps/web/views/Product/ProductAddedAlert.tsx b/starters/shopify-algolia/views/Product/ProductAddedAlert.tsx similarity index 100% rename from apps/web/views/Product/ProductAddedAlert.tsx rename to starters/shopify-algolia/views/Product/ProductAddedAlert.tsx diff --git a/apps/web/views/Product/ProductImages.tsx b/starters/shopify-algolia/views/Product/ProductImages.tsx similarity index 100% rename from apps/web/views/Product/ProductImages.tsx rename to starters/shopify-algolia/views/Product/ProductImages.tsx diff --git a/apps/web/views/Product/ProductTitle.tsx b/starters/shopify-algolia/views/Product/ProductTitle.tsx similarity index 100% rename from apps/web/views/Product/ProductTitle.tsx rename to starters/shopify-algolia/views/Product/ProductTitle.tsx diff --git a/apps/web/views/Product/ReviewButton.tsx b/starters/shopify-algolia/views/Product/ReviewButton.tsx similarity index 100% rename from apps/web/views/Product/ReviewButton.tsx rename to starters/shopify-algolia/views/Product/ReviewButton.tsx diff --git a/apps/web/views/Product/ReviewCard.tsx b/starters/shopify-algolia/views/Product/ReviewCard.tsx similarity index 100% rename from apps/web/views/Product/ReviewCard.tsx rename to starters/shopify-algolia/views/Product/ReviewCard.tsx diff --git a/apps/web/views/Product/ReviewsSection.tsx b/starters/shopify-algolia/views/Product/ReviewsSection.tsx similarity index 100% rename from apps/web/views/Product/ReviewsSection.tsx rename to starters/shopify-algolia/views/Product/ReviewsSection.tsx diff --git a/apps/web/views/Product/RightSection.tsx b/starters/shopify-algolia/views/Product/RightSection.tsx similarity index 100% rename from apps/web/views/Product/RightSection.tsx rename to starters/shopify-algolia/views/Product/RightSection.tsx diff --git a/apps/web/views/Product/SideImages.tsx b/starters/shopify-algolia/views/Product/SideImages.tsx similarity index 100% rename from apps/web/views/Product/SideImages.tsx rename to starters/shopify-algolia/views/Product/SideImages.tsx diff --git a/apps/web/views/Product/SimilarProductsSection.tsx b/starters/shopify-algolia/views/Product/SimilarProductsSection.tsx similarity index 100% rename from apps/web/views/Product/SimilarProductsSection.tsx rename to starters/shopify-algolia/views/Product/SimilarProductsSection.tsx diff --git a/apps/web/views/Product/SimilarProductsSectionSkeleton.tsx b/starters/shopify-algolia/views/Product/SimilarProductsSectionSkeleton.tsx similarity index 100% rename from apps/web/views/Product/SimilarProductsSectionSkeleton.tsx rename to starters/shopify-algolia/views/Product/SimilarProductsSectionSkeleton.tsx diff --git a/apps/web/views/Product/StarRating.tsx b/starters/shopify-algolia/views/Product/StarRating.tsx similarity index 100% rename from apps/web/views/Product/StarRating.tsx rename to starters/shopify-algolia/views/Product/StarRating.tsx diff --git a/apps/web/views/Product/Variant.tsx b/starters/shopify-algolia/views/Product/Variant.tsx similarity index 94% rename from apps/web/views/Product/Variant.tsx rename to starters/shopify-algolia/views/Product/Variant.tsx index 9e811661..2368d983 100644 --- a/apps/web/views/Product/Variant.tsx +++ b/starters/shopify-algolia/views/Product/Variant.tsx @@ -1,4 +1,4 @@ -import type { PlatformCartItem } from "@enterprise-commerce/core/platform/types" +import type { PlatformCartItem } from "lib/shopify/types" import Link from "next/link" import { cn } from "utils/cn" import type { Combination } from "utils/productOptionsUtils" diff --git a/apps/web/views/Product/VariantsSection.tsx b/starters/shopify-algolia/views/Product/VariantsSection.tsx similarity index 94% rename from apps/web/views/Product/VariantsSection.tsx rename to starters/shopify-algolia/views/Product/VariantsSection.tsx index 887c45c9..d038ae09 100644 --- a/apps/web/views/Product/VariantsSection.tsx +++ b/starters/shopify-algolia/views/Product/VariantsSection.tsx @@ -1,6 +1,6 @@ "use client" -import { PlatformVariant } from "@enterprise-commerce/core/platform/types" +import { PlatformVariant } from "lib/shopify/types" import { cn } from "utils/cn" import { Combination, createOptionfulUrl, getAllCombinations } from "utils/productOptionsUtils" import { Variant } from "./Variant" diff --git a/apps/web/views/Search/SearchView.tsx b/starters/shopify-algolia/views/Search/SearchView.tsx similarity index 98% rename from apps/web/views/Search/SearchView.tsx rename to starters/shopify-algolia/views/Search/SearchView.tsx index dd55860c..43d32b53 100644 --- a/apps/web/views/Search/SearchView.tsx +++ b/starters/shopify-algolia/views/Search/SearchView.tsx @@ -1,5 +1,5 @@ import { Suspense } from "react" -import type { PlatformCollection } from "@enterprise-commerce/core/platform/types" +import type { PlatformCollection } from "lib/shopify/types" import { unstable_cache } from "next/cache" import { createSearchParamsCache, parseAsArrayOf, parseAsInteger, parseAsString } from "nuqs/server" import { meilisearch } from "clients/search" diff --git a/apps/web/views/Settings/ProfileForm.tsx b/starters/shopify-algolia/views/Settings/ProfileForm.tsx similarity index 97% rename from apps/web/views/Settings/ProfileForm.tsx rename to starters/shopify-algolia/views/Settings/ProfileForm.tsx index 87f39610..84b17358 100644 --- a/apps/web/views/Settings/ProfileForm.tsx +++ b/starters/shopify-algolia/views/Settings/ProfileForm.tsx @@ -1,6 +1,6 @@ "use client" -import { PlatformUser } from "@enterprise-commerce/core/platform/types" +import { PlatformUser } from "lib/shopify/types" import { zodResolver } from "@hookform/resolvers/zod" import { getCurrentUser, updateUser } from "app/actions/user.actions" import { Button } from "components/Button/Button" diff --git a/apps/web/views/Settings/SettingsView.tsx b/starters/shopify-algolia/views/Settings/SettingsView.tsx similarity index 100% rename from apps/web/views/Settings/SettingsView.tsx rename to starters/shopify-algolia/views/Settings/SettingsView.tsx diff --git a/apps/web/views/ThirdParties.tsx b/starters/shopify-algolia/views/ThirdParties.tsx similarity index 100% rename from apps/web/views/ThirdParties.tsx rename to starters/shopify-algolia/views/ThirdParties.tsx diff --git a/starters/shopify-meilisearch/.eslintignore b/starters/shopify-meilisearch/.eslintignore new file mode 100644 index 00000000..8fc978f4 --- /dev/null +++ b/starters/shopify-meilisearch/.eslintignore @@ -0,0 +1,8 @@ +.next +node_modules +gql + +dist +/dist +dist/* +dist/**/* \ No newline at end of file diff --git a/starters/shopify-meilisearch/.eslintrc.js b/starters/shopify-meilisearch/.eslintrc.js new file mode 100644 index 00000000..44fd1243 --- /dev/null +++ b/starters/shopify-meilisearch/.eslintrc.js @@ -0,0 +1,39 @@ +/* eslint-env es6 */ +/* eslint-disable no-console */ + +module.exports = { + globals: { + React: true, + JSX: true, + }, + extends: ["next", "prettier", "react-app", "react-app/jest", "plugin:storybook/recommended", "plugin:tailwindcss/recommended"], + parserOptions: { + babelOptions: { + presets: [require.resolve("next/babel")], + }, + ecmaVersion: "latest", + }, + env: { + es6: true, + }, + rules: { + "tailwindcss/no-custom-classname": "off", + "testing-library/prefer-screen-queries": "off", + "@next/next/no-html-link-for-pages": "off", + "@typescript-eslint/no-unused-vars": [ + "warn", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + "sort-imports": [ + "error", + { + ignoreCase: true, + ignoreDeclarationSort: true, + }, + ], + "tailwindcss/classnames-order": "off", + }, +} diff --git a/starters/shopify-meilisearch/.gitignore b/starters/shopify-meilisearch/.gitignore new file mode 100644 index 00000000..fccde6d1 --- /dev/null +++ b/starters/shopify-meilisearch/.gitignore @@ -0,0 +1,22 @@ +.next/ +out/ +build + +build/** +dist/** +**/dist/** +.next/** + + +/.npm-only-allow + +storybook-static/ +playwright-report/ +playwright/.cache/ +test-results/ + +graph.svg + +# testing +coverage +.vercel diff --git a/starters/shopify-meilisearch/.graphqlrc.ts b/starters/shopify-meilisearch/.graphqlrc.ts new file mode 100644 index 00000000..38b7dc73 --- /dev/null +++ b/starters/shopify-meilisearch/.graphqlrc.ts @@ -0,0 +1,20 @@ +import { ApiType, shopifyApiProject } from "@shopify/api-codegen-preset" + +export default { + schema: ["https://shopify.dev/storefront-graphql-direct-proxy/2024-01", "https://shopify.dev/admin-graphql-direct-proxy/2024-01"], + documents: ["./**/*.{js,ts,jsx,tsx}"], + projects: { + default: shopifyApiProject({ + apiType: ApiType.Storefront, + apiVersion: "2024-01", + documents: ["./lib/shopify/**/*.storefront.{js,ts,jsx,tsx}", "./lib/shopify/**/fragments/*.{js,ts,jsx,tsx}"], + outputDir: "./lib/shopify/types", + }), + admin: shopifyApiProject({ + apiType: ApiType.Admin, + apiVersion: "2024-01", + documents: ["./lib/shopify/**/*.admin.{js,ts,jsx,tsx}"], + outputDir: "./lib/shopify/types/admin", + }), + }, +} diff --git a/.prettierignore b/starters/shopify-meilisearch/.prettierignore similarity index 100% rename from .prettierignore rename to starters/shopify-meilisearch/.prettierignore diff --git a/starters/shopify-meilisearch/.storybook/main.ts b/starters/shopify-meilisearch/.storybook/main.ts new file mode 100644 index 00000000..136f062f --- /dev/null +++ b/starters/shopify-meilisearch/.storybook/main.ts @@ -0,0 +1,30 @@ +import { dirname, join } from "path" +import type { StorybookConfig } from "@storybook/nextjs" +const config: StorybookConfig = { + stories: ["../components/**/*.mdx", "../components/**/*.stories.@(js|jsx|ts|tsx)"], + addons: [getAbsolutePath("@storybook/addon-links"), getAbsolutePath("@storybook/addon-essentials"), getAbsolutePath("@storybook/addon-interactions")], + framework: { + name: getAbsolutePath("@storybook/nextjs"), + options: {}, + }, + features: { + experimentalRSC: true, + }, + docs: { + autodocs: "tag", + }, + typescript: { + check: false, + checkOptions: {}, + reactDocgen: "react-docgen-typescript", + reactDocgenTypescriptOptions: { + shouldExtractLiteralValuesFromEnum: true, + propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true), + }, + }, +} +export default config + +function getAbsolutePath(value: string): any { + return dirname(require.resolve(join(value, "package.json"))) +} diff --git a/starters/shopify-meilisearch/.storybook/preview.ts b/starters/shopify-meilisearch/.storybook/preview.ts new file mode 100644 index 00000000..266989d5 --- /dev/null +++ b/starters/shopify-meilisearch/.storybook/preview.ts @@ -0,0 +1,17 @@ +import type { Preview } from "@storybook/react" + +import "../app/globals.css" + +const preview: Preview = { + parameters: { + actions: { argTypesRegex: "^on[A-Z].*" }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, + }, +} + +export default preview diff --git a/starters/shopify-meilisearch/app/.well-known/vercel/flags/route.ts b/starters/shopify-meilisearch/app/.well-known/vercel/flags/route.ts new file mode 100644 index 00000000..30903d4f --- /dev/null +++ b/starters/shopify-meilisearch/app/.well-known/vercel/flags/route.ts @@ -0,0 +1,35 @@ +import { NextRequest, NextResponse } from "next/server" +import { verifyAccess, type ApiData } from "@vercel/flags" + +export async function GET(request: NextRequest) { + const access = await verifyAccess(request.headers.get("Authorization")) + if (!access) return NextResponse.json(null, { status: 401 }) + + const apiData = { + definitions: { + isVercelAnalyticsEnabled: { + description: "Controls whether the new feature is visible", + options: [ + { value: false, label: "Off" }, + { value: true, label: "On" }, + ], + }, + isGoogleTagManagerEnabled: { + description: "Controls whether the new feature is visible", + options: [ + { value: false, label: "Off" }, + { value: true, label: "On" }, + ], + }, + isSpeedInsightsEnabled: { + description: "Controls whether the new feature is visible", + options: [ + { value: false, label: "Off" }, + { value: true, label: "On" }, + ], + }, + }, + } as ApiData + + return NextResponse.json(apiData) +} diff --git a/starters/shopify-meilisearch/app/access-denied/page.tsx b/starters/shopify-meilisearch/app/access-denied/page.tsx new file mode 100644 index 00000000..adb01d73 --- /dev/null +++ b/starters/shopify-meilisearch/app/access-denied/page.tsx @@ -0,0 +1,13 @@ +import Link from "next/link" + +export default function AccessDenied() { + return ( +
+

Looks like you don't have access to this page. If you were logged in before your session might've expired. Please log in again! 😊

+ + + Go Home + +
+ ) +} diff --git a/starters/shopify-meilisearch/app/actions/cart.actions.ts b/starters/shopify-meilisearch/app/actions/cart.actions.ts new file mode 100644 index 00000000..4459ef29 --- /dev/null +++ b/starters/shopify-meilisearch/app/actions/cart.actions.ts @@ -0,0 +1,86 @@ +"use server" + +import { revalidateTag, unstable_cache } from "next/cache" +import { cookies } from "next/headers" +import { storefrontClient } from "clients/storefrontClient" +import { COOKIE_CART_ID, TAGS } from "constants/index" +import { isDemoMode } from "utils/demoUtils" + +export const getCart = unstable_cache(async (cartId: string) => storefrontClient.getCart(cartId), [TAGS.CART], { revalidate: 60 * 15, tags: [TAGS.CART] }) + +export async function addCartItem(prevState: any, variantId: string) { + if (isDemoMode()) return { ok: false, message: "Demo mode active. Filtering, searching, and adding to cart disabled." } + if (!variantId) return { ok: false } + + let cartId = cookies().get(COOKIE_CART_ID)?.value + let cart + + if (cartId) cart = await storefrontClient.getCart(cartId) + + if (!cartId || !cart) { + cart = await storefrontClient.createCart([]) + cartId = cart?.id + cartId && cookies().set(COOKIE_CART_ID, cartId) + + revalidateTag(TAGS.CART) + } + + const itemAvailability = await getItemAvailability(cartId, variantId) + + if (!itemAvailability || itemAvailability.inCartQuantity >= itemAvailability.inStockQuantity) + return { + ok: false, + message: "This product is out of stock", + } + + await storefrontClient.createCartItem(cartId!, [{ merchandiseId: variantId, quantity: 1 }]) + revalidateTag(TAGS.CART) + + return { ok: true } +} + +export async function getItemAvailability(cartId: string | null | undefined, variantId: string | null | undefined) { + if (!cartId || !variantId) return { inCartQuantity: 0, inStockQuantity: Infinity } + + const cart = await storefrontClient.getCart(cartId) + const cartItem = cart?.items?.find((item) => item.merchandise.id === variantId) + + return { inCartQuantity: cartItem?.quantity ?? 0, inStockQuantity: cartItem?.merchandise.quantityAvailable ?? Infinity } +} + +export async function removeCartItem(prevState: any, itemId: string) { + const cartId = cookies().get(COOKIE_CART_ID)?.value + + if (!cartId) return { ok: false } + + await storefrontClient.deleteCartItem(cartId!, [itemId]) + revalidateTag(TAGS.CART) + + return { ok: true } +} + +export async function updateItemQuantity(prevState: any, payload: { itemId: string; variantId: string; quantity: number }) { + const cartId = cookies().get(COOKIE_CART_ID)?.value + + if (!cartId) return { ok: false } + + const { itemId, variantId, quantity } = payload + + if (quantity === 0) { + await storefrontClient.deleteCartItem(cartId, [itemId]) + revalidateTag(TAGS.CART) + return { ok: true } + } + + const itemAvailability = await getItemAvailability(cartId, variantId) + if (!itemAvailability || quantity > itemAvailability.inStockQuantity) + return { + ok: false, + message: "This product is out of stock", + } + + await storefrontClient.updateCartItem(cartId, [{ id: itemId, merchandiseId: variantId, quantity }]) + + revalidateTag(TAGS.CART) + return { ok: true } +} diff --git a/starters/shopify-meilisearch/app/actions/collection.actions.ts b/starters/shopify-meilisearch/app/actions/collection.actions.ts new file mode 100644 index 00000000..325f6430 --- /dev/null +++ b/starters/shopify-meilisearch/app/actions/collection.actions.ts @@ -0,0 +1,27 @@ +"use server" + +import { unstable_cache } from "next/cache" +import { meilisearch } from "clients/search" +import { ComparisonOperators, FilterBuilder } from "lib/meilisearch/filterBuilder" +import { getDemoSingleCategory, isDemoMode } from "utils/demoUtils" +import type { PlatformCollection } from "lib/shopify/types" +import { env } from "env.mjs" + +export const getCollection = unstable_cache( + async (slug: string) => { + if (isDemoMode()) return getDemoSingleCategory(slug) + + const results = await meilisearch.searchDocuments({ + indexName: env.MEILISEARCH_CATEGORIES_INDEX, + options: { + filter: new FilterBuilder().where("handle", ComparisonOperators.Equal, slug).build(), + limit: 1, + attributesToRetrieve: ["handle", "title", "seo"], + }, + }) + + return results.hits.find(Boolean) || null + }, + ["category-by-handle"], + { revalidate: 3600 } +) diff --git a/starters/shopify-meilisearch/app/actions/favorites.actions.ts b/starters/shopify-meilisearch/app/actions/favorites.actions.ts new file mode 100644 index 00000000..b4ec63d1 --- /dev/null +++ b/starters/shopify-meilisearch/app/actions/favorites.actions.ts @@ -0,0 +1,20 @@ +"use server" + +import { COOKIE_FAVORITES } from "constants/index" +import { cookies } from "next/headers" + +export async function toggleFavoriteProduct(prevState: any, handle: string) { + const handles = await getParsedFavoritesHandles() + const isFavorite = handles.includes(handle) + const newFavorites = handles.includes(handle) ? handles.filter((i) => i !== handle) : [...handles, handle] + + cookies().set(COOKIE_FAVORITES, JSON.stringify(newFavorites)) + + return !isFavorite +} + +export async function getParsedFavoritesHandles() { + const favoritesCookie = cookies().get(COOKIE_FAVORITES)?.value || "[]" + const favoritesHandles = JSON.parse(favoritesCookie) as string[] + return favoritesHandles +} diff --git a/starters/shopify-meilisearch/app/actions/page.actions.ts b/starters/shopify-meilisearch/app/actions/page.actions.ts new file mode 100644 index 00000000..74d98775 --- /dev/null +++ b/starters/shopify-meilisearch/app/actions/page.actions.ts @@ -0,0 +1,8 @@ +"use server" + +import { storefrontClient } from "clients/storefrontClient" +import { unstable_cache } from "next/cache" + +export const getPage = unstable_cache(async (handle: string) => await storefrontClient.getPage(handle), ["page"], { revalidate: 3600 }) + +export const getAllPages = unstable_cache(async () => await storefrontClient.getAllPages(), ["page"], { revalidate: 3600 }) diff --git a/starters/shopify-meilisearch/app/actions/product.actions.ts b/starters/shopify-meilisearch/app/actions/product.actions.ts new file mode 100644 index 00000000..17c267ce --- /dev/null +++ b/starters/shopify-meilisearch/app/actions/product.actions.ts @@ -0,0 +1,84 @@ +"use server" + +import { unstable_cache } from "next/cache" +import { env } from "env.mjs" + +import { meilisearch } from "clients/search" +import type { Review } from "lib/reviews/types" + +import { ComparisonOperators, FilterBuilder } from "lib/meilisearch/filterBuilder" +import { getDemoProductReviews, getDemoSingleProduct, isDemoMode } from "utils/demoUtils" +import type { CommerceProduct } from "types" +import { notifyOptIn } from "utils/opt-in" + +export const searchProducts = unstable_cache( + async (query: string, limit: number = 4) => { + if (isDemoMode()) + return { + hits: [], + hasMore: false, + } + + const { hits, estimatedTotalHits } = await meilisearch.searchDocuments({ + indexName: env.MEILISEARCH_PRODUCTS_INDEX, + query, + options: { + limit, + attributesToRetrieve: ["id", "handle", "title", "featuredImage", "images", "variants"], + }, + }) + + return { hits, hasMore: estimatedTotalHits > limit } + }, + ["autocomplete-search"], + { revalidate: 3600 } +) + +export const getProduct = unstable_cache( + async (handle: string) => { + if (isDemoMode()) return getDemoSingleProduct(handle) + + const { results } = await meilisearch.getDocuments({ + indexName: env.MEILISEARCH_PRODUCTS_INDEX, + options: { + filter: new FilterBuilder().where("handle", ComparisonOperators.Equal, handle).build(), + limit: 1, + }, + }) + + return results.find(Boolean) || null + }, + ["product-by-handle"], + { revalidate: 3600 } +) + +export const getProductReviews = unstable_cache( + async (handle: string, { page = 1, limit = 10 } = { page: 1, limit: 10 }) => { + if (isDemoMode()) return getDemoProductReviews() + + if (!env.MEILISEARCH_REVIEWS_INDEX) { + notifyOptIn({ feature: "reviews", source: "product.actions.ts" }) + return { reviews: [], total: 0 } + } + + const { results, total } = await meilisearch.getDocuments({ + indexName: env.MEILISEARCH_REVIEWS_INDEX, + options: { + filter: new FilterBuilder() + .where("product_handle", ComparisonOperators.Equal, handle) + .and() + .where("published", ComparisonOperators.Equal, "true") + .and() + .where("hidden", ComparisonOperators.Equal, "false") + .build(), + limit, + offset: (page - 1) * limit, + fields: ["body", "rating", "verified", "reviewer", "published", "created_at", "hidden", "featured"], + }, + }) + + return { reviews: results.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()), total } + }, + ["product-reviews-by-handle"], + { revalidate: 3600 } +) diff --git a/starters/shopify-meilisearch/app/actions/reviews.actions.ts b/starters/shopify-meilisearch/app/actions/reviews.actions.ts new file mode 100644 index 00000000..ac9c03e3 --- /dev/null +++ b/starters/shopify-meilisearch/app/actions/reviews.actions.ts @@ -0,0 +1,15 @@ +"use server" + +import { reviewsClient } from "clients/reviews" +import type { ProductReviewBody } from "lib/reviews/types" + +import { headers } from "next/headers" + +export const submitReview = async (payload: Omit) => { + try { + const ipAddress = headers().get("x-forwarded-for") || null + await reviewsClient.createProductReview({ ...payload, ip_addr: ipAddress }) + } catch (err) { + throw new Error(err as string) + } +} diff --git a/starters/shopify-meilisearch/app/actions/user.actions.ts b/starters/shopify-meilisearch/app/actions/user.actions.ts new file mode 100644 index 00000000..f79d8f5f --- /dev/null +++ b/starters/shopify-meilisearch/app/actions/user.actions.ts @@ -0,0 +1,34 @@ +"use server" + +import { PlatformUserCreateInput } from "lib/shopify/types" +import { cookies } from "next/headers" +import { storefrontClient } from "clients/storefrontClient" +import { COOKIE_ACCESS_TOKEN } from "constants/index" + +export async function signupUser({ email, password }: { email: string; password: string }) { + const user = await storefrontClient.createUser({ email, password }) + return user +} + +export async function loginUser({ email, password }: { email: string; password: string }) { + const user = await storefrontClient.createUserAccessToken({ email, password }) + cookies().set(COOKIE_ACCESS_TOKEN, user?.accessToken || "", { expires: new Date(user?.expiresAt || "") }) + return user +} + +export async function getCurrentUser() { + const accessToken = cookies().get(COOKIE_ACCESS_TOKEN)?.value + const user = await storefrontClient.getUser(accessToken || "") + return user +} + +export async function updateUser(input: Pick) { + const accessToken = cookies().get(COOKIE_ACCESS_TOKEN)?.value + + const user = await storefrontClient.updateUser(accessToken!, { ...input }) + return user +} + +export async function logoutUser() { + cookies().delete(COOKIE_ACCESS_TOKEN) +} diff --git a/starters/shopify-meilisearch/app/api/feed/sync/route.ts b/starters/shopify-meilisearch/app/api/feed/sync/route.ts new file mode 100644 index 00000000..d0512146 --- /dev/null +++ b/starters/shopify-meilisearch/app/api/feed/sync/route.ts @@ -0,0 +1,127 @@ +import type { PlatformProduct } from "lib/shopify/types" +import { meilisearch } from "clients/search" +import { storefrontClient } from "clients/storefrontClient" +import { env } from "env.mjs" +import { compareHmac } from "utils/compare-hmac" +import { enrichProduct } from "utils/enrich-product" + +type SupportedTopic = "products/update" | "products/delete" | "products/create" | "collections/update" | "collections/delete" | "collections/create" + +/* + * Callback Endpoint for Shopify Webhook product updates + */ +export async function POST(req: Request) { + const hmac = req.headers.get("X-Shopify-Hmac-Sha256") + const topic = req.headers.get("X-Shopify-Topic") + const secret = env.SHOPIFY_APP_API_SECRET_KEY + const rawPayload = await req.text() + + if (!secret || !hmac || !topic) { + return new Response(JSON.stringify({ message: "Not all credentials were provided for the deployment" }), { status: 500, headers: { "Content-Type": "application/json" } }) + } + + if ( + !compareHmac({ + body: rawPayload, + hmac, + secret, + }) + ) { + return new Response(JSON.stringify({ message: "Could not verify request." }), { status: 401, headers: { "Content-Type": "application/json" } }) + } + // there is no clear docs for what the payload looks like for different topics + const { id } = JSON.parse(rawPayload) as Record + + if (!id) { + return new Response(JSON.stringify({ message: "Invalid payload" }), { status: 400, headers: { "Content-Type": "application/json" } }) + } + + if (topic.startsWith("products")) { + return await handleProductTopics(topic as SupportedTopic, { id }) + } else if (topic.startsWith("collections")) { + return await handleCollectionTopics(topic as SupportedTopic, { id }) + } else { + return new Response(JSON.stringify({ message: "Unsupported topic" }), { status: 400, headers: { "Content-Type": "application/json" } }) + } +} + +async function handleCollectionTopics(topic: SupportedTopic, { id }: Record): Promise { + switch (topic) { + case "collections/update": + case "collections/create": + const collection = await storefrontClient.getCollectionById(makeShopifyId(`${id}`, "Collection")) + if (!collection) { + console.error(`Collection ${id} not found`) + return new Response(JSON.stringify({ message: "Collection not found" }), { status: 404, headers: { "Content-Type": "application/json" } }) + } + await meilisearch.updateDocuments({ + indexName: env.MEILISEARCH_CATEGORIES_INDEX, + documents: [{ ...collection, id: `${id}` }], + options: { + primaryKey: "id", + }, + }) + + break + + case "collections/delete": + await meilisearch.deleteDocuments({ + indexName: env.MEILISEARCH_CATEGORIES_INDEX, + params: [id], + }) + break + + default: + return new Response(JSON.stringify({ message: "Unsupported topic" }), { status: 400, headers: { "Content-Type": "application/json" } }) + } + + return new Response(JSON.stringify({ message: "Success" }), { status: 200, headers: { "Content-Type": "application/json" } }) +} + +async function handleProductTopics(topic: SupportedTopic, { id }: Record): Promise { + switch (topic) { + case "products/update": + case "products/create": + const product = await storefrontClient.getProduct(makeShopifyId(`${id}`, "Product")) + const items = env.SHOPIFY_HIERARCHICAL_NAV_HANDLE ? (await storefrontClient.getHierarchicalCollections(env.SHOPIFY_HIERARCHICAL_NAV_HANDLE)).items : [] + + if (!product) { + console.error(`Product ${id} not found`) + return new Response(JSON.stringify({ message: "Product not found" }), { status: 404, headers: { "Content-Type": "application/json" } }) + } + + const enrichedProduct = await enrichProduct(product, items) + await meilisearch.updateDocuments({ + indexName: env.MEILISEARCH_PRODUCTS_INDEX, + documents: [normalizeProduct(enrichedProduct, id)], + options: { + primaryKey: "id", + }, + }) + + break + case "products/delete": + await meilisearch.deleteDocuments({ + indexName: env.MEILISEARCH_PRODUCTS_INDEX, + params: [id], + }) + break + + default: + return new Response(JSON.stringify({ message: "Unsupported topic" }), { status: 400, headers: { "Content-Type": "application/json" } }) + } + + return new Response(JSON.stringify({ message: "Success" }), { status: 200, headers: { "Content-Type": "application/json" } }) +} + +/* Extract into utils */ +function normalizeProduct(product: PlatformProduct, originalId: string): PlatformProduct { + return { + ...product, + id: originalId, + } +} + +function makeShopifyId(id: string, type: "Product" | "Collection") { + return id.startsWith("gid://shopify/") ? id : `gid://shopify/${type}/${id}` +} diff --git a/starters/shopify-meilisearch/app/api/health/route.ts b/starters/shopify-meilisearch/app/api/health/route.ts new file mode 100644 index 00000000..e8fd8c53 --- /dev/null +++ b/starters/shopify-meilisearch/app/api/health/route.ts @@ -0,0 +1,3 @@ +export async function GET() { + return Response.json({ status: "ok" }) +} diff --git a/starters/shopify-meilisearch/app/api/redirects/route.ts b/starters/shopify-meilisearch/app/api/redirects/route.ts new file mode 100644 index 00000000..7b1fd799 --- /dev/null +++ b/starters/shopify-meilisearch/app/api/redirects/route.ts @@ -0,0 +1,25 @@ +import { NextRequest, NextResponse } from "next/server" +import redirects from "../../../redirects/new-redirects.json" + +type RedirectEntry = { + destination: string + permanent: boolean +} + +export const runtime = "edge" + +export function GET(request: NextRequest) { + const pathname = request.nextUrl.searchParams.get("pathname") + + if (!pathname) { + return new Response("Bad Request", { status: 400 }) + } + + const redirect = (redirects as Record)[pathname] + + if (!redirect) { + return new Response("No redirect", { status: 400 }) + } + + return NextResponse.json(redirect) +} diff --git a/starters/shopify-meilisearch/app/api/reviews/ai-summary/route.ts b/starters/shopify-meilisearch/app/api/reviews/ai-summary/route.ts new file mode 100644 index 00000000..0fb074b4 --- /dev/null +++ b/starters/shopify-meilisearch/app/api/reviews/ai-summary/route.ts @@ -0,0 +1,178 @@ +import { generateObject } from "ai" +import z from "zod" +import { openai } from "@ai-sdk/openai" +import type { Review } from "lib/reviews/types" +import type { CommerceProduct } from "types" +import { meilisearch } from "clients/search" +import { env } from "env.mjs" +import { authenticate } from "utils/authenticate-api-route" +import { isOptIn, notifyOptIn } from "utils/opt-in" +import { unstable_noStore } from "next/cache" +import { isDemoMode } from "utils/demoUtils" + +const summarySchema = z.object({ + products: z.array( + z.object({ + handle: z.string(), + id: z.string(), + reviewsSummary: z.string(), + }) + ), +}) + +export const maxDuration = 60 + +/* + * This API route will be used for cron job, running once a week to re-generate AI summary based on all user reviews, tweak to your needs + */ +export async function GET(req: Request) { + unstable_noStore() + if (!authenticate(req)) { + return new Response("Unauthorized", { + status: 401, + }) + } + + if (!isOptIn("ai-reviews")) { + const res = notifyOptIn({ feature: "ai-reviews", source: "api/reviews/ai-summary" }) + return new Response(JSON.stringify(res), { status: 200 }) + } + + if (isDemoMode() || !env.MEILISEARCH_REVIEWS_INDEX) { + console.error({ + message: "Lacking environment variables", + source: "api/reviews/ai-summary", + }) + return new Response(JSON.stringify({ message: "Sorry, something went wrong" }), { status: 500 }) + } + + const [allReviews, allProducts] = await Promise.all([ + meilisearch.getDocuments({ + indexName: env.MEILISEARCH_REVIEWS_INDEX, + options: { + limit: 10000, + fields: ["body", "title", "product_handle", "rating"], + filter: "published=true AND hidden=false", + }, + }), + meilisearch.getDocuments({ + indexName: env.MEILISEARCH_PRODUCTS_INDEX, + options: { + limit: 10000, + fields: ["handle", "title", "id", "totalReviews"], + }, + }), + ]) + + const mappedReviews: Record = allReviews?.results.reduce( + (acc, review) => { + const productHandle = review.product_handle + if (acc[productHandle]) { + acc[productHandle].push(review) + } else { + acc[productHandle] = [review] + } + + return acc + }, + {} as Record + ) + + const productsWithNewReviews = allProducts?.results.filter((product) => product.totalReviews !== (mappedReviews[product.handle]?.length || 0)) + + if (!productsWithNewReviews.length) { + return new Response(JSON.stringify({ message: "No new reviews to re-generate summary" }), { status: 200 }) + } + + const productsWithReviews = productsWithNewReviews + .map((product) => { + if (!mappedReviews[product.handle]) { + return null + } + return { + product_title: product.title, + id: product.id, + handle: product.handle, + reviews: mappedReviews[product.handle], + } + }) + .filter(Boolean) + + const batches: Batch[] = [] + const results: { handle: string; id: string; reviewsSummary: string }[] = [] + const batchSize = 25 + + for (let i = 0; i < productsWithReviews.length; i += batchSize) { + const batch = productsWithReviews.slice(i, i + batchSize) + + batches.push(batch) + } + + for (const batch of batches) { + const products = await generateBatchSummaries(batch) + results.push(...products) + } + + const updatedProducts = results + .map((result) => { + const id = productsWithReviews?.find(({ id }) => id === result.id)?.id + + if (!id) return null + + return { + id, + reviewsSummary: result.reviewsSummary, + } + }) + .filter(Boolean) + + await meilisearch.updateDocuments({ indexName: env.MEILISEARCH_PRODUCTS_INDEX, documents: updatedProducts, options: { primaryKey: "id" } }) + + return new Response(JSON.stringify({ message: "Reviews synced" }), { status: 200 }) +} + +type Batch = { + handle: string + id: string + reviews: Review[] +}[] + +const instructions = ` + You will be given a list of products and a list reviews for each of them. Your task is to generate a short summary (maximum up to 4 sentences) for each product based on the reviews provided highlighting best features and one or two areas of improvement if any are mentioned if not just don't mention it at all. Avoid repeating the same information in the summary whilst keeping casual tone. + + Example of its structure: + { + "products": [{ + "product_title": "Sleek Watch", + "id": "1", + "handle": "sleek-watch", + "reviews": [ + { + "title": "Great watch", + "body": "I love this watch, it's sleek and stylish. The only downside is that the battery life is not as long as I would like.", + "rating": 5 + }, + { + "title": "Very stylish", + "body": "I love the design of this watch, it's very stylish and goes with everything. The only downside is that the strap is a bit uncomfortable.", + "rating": 4 + }, + + ] + }] + } + + Here's the list of products and reviews: + ` + +async function generateBatchSummaries(batch: Batch) { + const { object } = await generateObject({ + model: openai("gpt-4o"), + system: instructions, + prompt: JSON.stringify(batch), + schema: summarySchema, + mode: "json", + }) + + return object.products +} diff --git a/starters/shopify-meilisearch/app/api/reviews/sync/route.ts b/starters/shopify-meilisearch/app/api/reviews/sync/route.ts new file mode 100644 index 00000000..51183e6f --- /dev/null +++ b/starters/shopify-meilisearch/app/api/reviews/sync/route.ts @@ -0,0 +1,97 @@ +import { unstable_noStore } from "next/cache" +import { meilisearch } from "clients/search" +import { reviewsClient } from "clients/reviews" +import { env } from "env.mjs" +import { authenticate } from "utils/authenticate-api-route" +import { isOptIn, notifyOptIn } from "utils/opt-in" +import type { Review } from "lib/reviews/types" +import type { CommerceProduct } from "types" +import { isDemoMode } from "utils/demoUtils" + +export const maxDuration = 60 + +export async function GET(req: Request) { + unstable_noStore() + if (!authenticate(req)) { + return new Response("Unauthorized", { + status: 401, + }) + } + + if (!isOptIn("reviews")) { + const res = notifyOptIn({ feature: "reviews", source: "api/reviews/sync" }) + return new Response(JSON.stringify(res), { status: 200 }) + } + + if (isDemoMode() || !env.MEILISEARCH_REVIEWS_INDEX) { + console.error({ + message: "Lacking environment variables", + source: "api/reviews/sync", + }) + return new Response(JSON.stringify({ message: "Sorry, something went wrong" }), { status: 500 }) + } + + const [allReviews, allProducts, allIndexReviews] = await Promise.all([ + reviewsClient.getAllProductReviews(), + meilisearch.getDocuments({ + indexName: env.MEILISEARCH_PRODUCTS_INDEX, + options: { + limit: 10000, + fields: ["handle", "totalReviews", "avgRating", "id"], + }, + }), + meilisearch.getDocuments({ + indexName: env.MEILISEARCH_REVIEWS_INDEX, + options: { + limit: 10000, + fields: ["updated_at", "id"], + }, + }), + ]) + + const reviewsDelta = allReviews.filter((review) => { + const indexReview = allIndexReviews?.results.find((r) => r.id === review.id) + return indexReview?.updated_at !== review.updated_at + }) + + const productTotalReviewsDelta = allProducts?.results + .map((product) => { + const productReviews = allReviews.filter((review) => review.product_handle === product.handle && review.published && !review.hidden) + if (!!productReviews.length && productReviews.length !== product.totalReviews) { + const avgRating = productReviews.reduce((acc, review) => acc + review.rating, 0) / productReviews.length || 0 + return { ...product, avgRating, totalReviews: productReviews.length } + } + + return null + }) + .filter(Boolean) + + if (!reviewsDelta.length && !productTotalReviewsDelta.length) { + return new Response(JSON.stringify({ message: "Nothing to sync" }), { status: 200 }) + } + + !!reviewsDelta.length && + (async () => { + meilisearch.updateDocuments({ + indexName: env.MEILISEARCH_REVIEWS_INDEX!, + documents: reviewsDelta, + options: { + primaryKey: "id", + }, + }) + console.log("API/sync: Reviews synced", reviewsDelta.length) + })() + !!productTotalReviewsDelta.length && + (async () => { + meilisearch.updateDocuments({ + indexName: env.MEILISEARCH_PRODUCTS_INDEX, + documents: productTotalReviewsDelta, + options: { + primaryKey: "id", + }, + }) + console.log("API/sync:Products synced", productTotalReviewsDelta.length) + })() + + return new Response(JSON.stringify({ message: "All synced" }), { status: 200 }) +} diff --git a/starters/shopify-meilisearch/app/category/clp/[slug]/[page]/page.tsx b/starters/shopify-meilisearch/app/category/clp/[slug]/[page]/page.tsx new file mode 100644 index 00000000..ba9b0dfb --- /dev/null +++ b/starters/shopify-meilisearch/app/category/clp/[slug]/[page]/page.tsx @@ -0,0 +1,24 @@ +import type { Metadata } from "next" +import { CategoryView } from "views/Category/CategoryView" + +export const revalidate = 86400 +export const dynamic = "force-static" + +interface CategoryPageProps { + params: { slug: string; page: string } +} + +export async function generateMetadata({ params }: CategoryPageProps): Promise { + return { + title: `${params.slug} | Enterprise Commerce`, + description: "In excepteur elit mollit in.", + } +} + +export async function generateStaticParams() { + return [] +} + +export default async function CategoryPage({ params }: CategoryPageProps) { + return +} diff --git a/starters/shopify-meilisearch/app/category/clp/[slug]/page.tsx b/starters/shopify-meilisearch/app/category/clp/[slug]/page.tsx new file mode 100644 index 00000000..6f7210a4 --- /dev/null +++ b/starters/shopify-meilisearch/app/category/clp/[slug]/page.tsx @@ -0,0 +1,38 @@ +import { PlatformCollection } from "lib/shopify/types" +import { meilisearch } from "clients/search" +import { env } from "env.mjs" +import type { Metadata } from "next" +import { isDemoMode } from "utils/demoUtils" +import { CategoryView } from "views/Category/CategoryView" + +export const revalidate = 86400 +export const dynamic = "force-static" + +interface CategoryPageProps { + params: { slug: string } +} + +export async function generateMetadata({ params }: CategoryPageProps): Promise { + return { + title: `${params.slug} | Enterprise Commerce`, + description: "In excepteur elit mollit in.", + } +} + +export async function generateStaticParams() { + if (isDemoMode()) return [] + + const { hits } = await meilisearch.searchDocuments({ + indexName: env.MEILISEARCH_CATEGORIES_INDEX, + options: { + limit: 50, + attributesToRetrieve: ["handle"], + }, + }) + + return hits.map(({ handle }) => ({ slug: handle })) +} + +export default async function CategoryPage({ params }: CategoryPageProps) { + return +} diff --git a/starters/shopify-meilisearch/app/category/plp/[slug]/page.tsx b/starters/shopify-meilisearch/app/category/plp/[slug]/page.tsx new file mode 100644 index 00000000..a1ca05ef --- /dev/null +++ b/starters/shopify-meilisearch/app/category/plp/[slug]/page.tsx @@ -0,0 +1,23 @@ +import type { Metadata } from "next" +import { SearchParamsType } from "types" +import { CategoryView } from "views/Category/CategoryView" + +export const runtime = "nodejs" + +export const revalidate = 86400 + +interface ProductListingPageProps { + searchParams: SearchParamsType + params: { slug: string } +} + +export async function generateMetadata({ params }: ProductListingPageProps): Promise { + return { + title: `${params.slug} | Enterprise Commerce`, + description: "In excepteur elit mollit in.", + } +} + +export default async function ProductListingPage({ searchParams, params }: ProductListingPageProps) { + return +} diff --git a/starters/shopify-meilisearch/app/error.tsx b/starters/shopify-meilisearch/app/error.tsx new file mode 100644 index 00000000..454e8dcf --- /dev/null +++ b/starters/shopify-meilisearch/app/error.tsx @@ -0,0 +1,33 @@ +"use client" + +import { Button } from "components/Button/Button" +import { isDemoMode } from "utils/demoUtils" + +export default function Error({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) { + return ( +
+
+ {isDemoMode() ? ( + <> +

Something went wrong!

+

+ This feature requires full functionality. Please exit Demo Mode by setting the required environment variables. +

+
{JSON.stringify(error, null, 2)}
+ + + ) : ( + <> +

Something went wrong!

+
{JSON.stringify(error, null, 2)}
+ + + )} +
+
+ ) +} diff --git a/starters/shopify-meilisearch/app/favorites/page.tsx b/starters/shopify-meilisearch/app/favorites/page.tsx new file mode 100644 index 00000000..432e1bce --- /dev/null +++ b/starters/shopify-meilisearch/app/favorites/page.tsx @@ -0,0 +1,61 @@ +import { cookies } from "next/headers" +import { Suspense } from "react" +import { getProduct } from "app/actions/product.actions" +import { ProductCard } from "components/ProductCard/ProductCard" +import { Skeleton } from "components/Skeleton/Skeleton" +import { COOKIE_FAVORITES } from "constants/index" + +export const revalidate = 86400 + +export const dynamicParams = true + +export default async function Favorites() { + return ( +
+
+

Favorite products

+
+ }> + + +
+ ) +} + +async function FavoritesView() { + let favoritesHandles: string[] = [] + const favoritesCookie = cookies().get(COOKIE_FAVORITES)?.value + + if (favoritesCookie) { + favoritesHandles = JSON.parse(favoritesCookie) as string[] + } + + const products = await Promise.all(favoritesHandles.map((handle) => getProduct(handle)).filter(Boolean)) + + return ( + <> + {products.length === 0 ?

No favorite products. You can add them by clicking on a heart icon on product page

: null} +
+ {products.map((singleResult, idx) => ( + + ))} +
+ + ) +} + +function FavoritesSkeleton() { + return ( +
+ {Array.from({ length: 8 }).map((_, index) => ( +
+ +
+ + +
+
+ ))} +
+ ) +} diff --git a/starters/shopify-meilisearch/app/global-error.tsx b/starters/shopify-meilisearch/app/global-error.tsx new file mode 100644 index 00000000..754630ea --- /dev/null +++ b/starters/shopify-meilisearch/app/global-error.tsx @@ -0,0 +1,19 @@ +"use client" + +import { Button } from "components/Button/Button" + +export default function GlobalError({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) { + return ( + + +
+

Something went wrong!

+
{JSON.stringify(error, null, 2)}
+ +
+ + + ) +} diff --git a/starters/shopify-meilisearch/app/globals.css b/starters/shopify-meilisearch/app/globals.css new file mode 100644 index 00000000..f8c4a02a --- /dev/null +++ b/starters/shopify-meilisearch/app/globals.css @@ -0,0 +1,22 @@ +@import "./styles/reset.css"; +@import "./styles/megamenu.css"; + +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; +} + +@layer utilities { + /* Hide scrollbar for Chrome, Safari and Opera */ + .no-scrollbar::-webkit-scrollbar { + display: none; + } + /* Hide scrollbar for IE, Edge and Firefox */ + .no-scrollbar { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + } +} diff --git a/starters/shopify-meilisearch/app/home/[bucket]/page.tsx b/starters/shopify-meilisearch/app/home/[bucket]/page.tsx new file mode 100644 index 00000000..9e78392c --- /dev/null +++ b/starters/shopify-meilisearch/app/home/[bucket]/page.tsx @@ -0,0 +1,44 @@ +import { Suspense } from "react" +import { BUCKETS } from "constants/index" +import { BestOffersSection } from "views/Homepage/BestOffersSection" +import { CarouselSectionSkeleton } from "views/Homepage/CarouselSection" +import { CategoriesSection, CategoriesSectionSkeleton } from "views/Homepage/CategoriesSection" +import { EverythingUnderSection } from "views/Homepage/EverythingUnderSection" +import { AnnouncementBar } from "components/AnnouncementBar/AnnouncementBar" +import { HeroSection } from "views/Homepage/HeroSection" + +export const revalidate = 86400 + +export const dynamic = "force-static" + +export const dynamicParams = true + +export default function Homepage({ params: { bucket } }: { params: { bucket: string } }) { + const heroTitles = { + a: "Your daily trendsetting deals", + b: "Spring into Savings! Up to 60% Off", + } + + return ( +
+ + + + }> + + + + }> + + + + }> + + +
+ ) +} + +export async function generateStaticParams() { + return BUCKETS.HOME.map((bucket) => ({ bucket })) +} diff --git a/starters/shopify-meilisearch/app/icon.png b/starters/shopify-meilisearch/app/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3fab1350884dba849a1a22fe43b086aa98c9f08b GIT binary patch literal 24936 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 IGbYCTA4l}JyZ`_I literal 0 HcmV?d00001 diff --git a/starters/shopify-meilisearch/app/layout.tsx b/starters/shopify-meilisearch/app/layout.tsx new file mode 100644 index 00000000..233d5c0a --- /dev/null +++ b/starters/shopify-meilisearch/app/layout.tsx @@ -0,0 +1,271 @@ +import "./globals.css" + +import nextDynamic from "next/dynamic" +import Script from "next/script" +import { Suspense } from "react" +import { Toaster } from "sonner" +import { CallToAction } from "components/CallToAction/CallToAction" +import { Footer } from "components/Footer/Footer" +import { Modals } from "components/Modals/Modals" +import { mobileInlineScript } from "components/NavigationBar/mobileInlineScript" +import { NavigationBar } from "components/NavigationBar/NavigationBar" +import { NavItem } from "components/NavigationBar/types" +import { FlagValues } from "views/FlagValues" +import { ThirdParties } from "views/ThirdParties" +import { env } from "env.mjs" +import { Metadata } from "next" +import { GithubBadge } from "views/GithubBadge" +import { DemoModeAlert } from "views/DemoModeAlert" +import { CartView } from "views/Cart/CartView" + +const DraftToolbar = nextDynamic(() => import("views/DraftToolbar"), { ssr: false }) + +export const revalidate = 86400 + +const navigationItems: NavItem[] = [ + { + text: "Fashion", + href: "/category/fashion", + submenu: { + variant: "text-grid", + items: [ + { + text: "Women", + href: "/category/women", + items: [ + { text: "Shirts & Blouses", href: "/category/shirts-and-blouses" }, + { text: "Blazers & Vests", href: "/category/blazers-and-vests" }, + { text: "Cardigans & Sweaters", href: "/category/cardigans-and-sweaters" }, + { text: "Dresses", href: "/category/dresses" }, + { text: "Skirts", href: "/category/skirts" }, + ], + }, + { + text: "Men", + href: "/category/men", + items: [ + { text: "T-shirts & Tanks", href: "/category/t-shirts-and-tanks" }, + { text: "Hoodies & Sweatshirts", href: "/category/hoodies-and-sweatshirts" }, + { text: "Blazers & Suits", href: "/category/blazers-and-suits" }, + { text: "Shorts", href: "/category/shorts" }, + { text: "Outerwear", href: "/category/outerwear" }, + ], + }, + { + text: "Kids", + href: "/category/kids", + items: [ + { text: "Clothing", href: "/category/clothing" }, + { text: "Activewear", href: "/category/activewear" }, + { text: "Accessories", href: "/category/kids-accessories" }, + { text: "Footwear", href: "/category/footwear" }, + ], + }, + ], + }, + }, + { + text: "Electronics", + href: "/category/electronics", + submenu: { + variant: "text-grid", + items: [ + { + text: "Audio Devices", + href: "/category/audio-devices", + items: [ + { text: "Headphones", href: "/category/headphones" }, + { text: "Speakers", href: "/category/speakers" }, + ], + }, + { + text: "Cameras", + href: "/category/cameras", + items: [ + { text: "Digital Cameras", href: "/category/digital-cameras" }, + { text: "Action Cameras", href: "/category/action-cameras" }, + ], + }, + { + text: "Smartphones", + href: "/category/smartphones", + }, + { + text: "Laptops", + href: "/category/laptops", + }, + { + text: "Screens", + href: "/category/screens", + }, + ], + }, + }, + { + text: "Sports & Outdoors", + href: "/category/sports-and-outdoors", + submenu: { + variant: "text-grid", + items: [ + { + href: "/category/exercise-equipment", + text: "Exercise Equipment", + }, + { + href: "/category/outdoor-gear", + text: "Outdoor Gear", + }, + { + href: "/category/sportswear", + text: "Sportswear", + }, + { + href: "/category/athletic-footwear", + text: "Athletic Footwear", + }, + ], + }, + }, + { + text: "Beauty", + href: "/category/beauty", + submenu: { + variant: "text-grid", + items: [ + { + text: "Skin Care", + href: "/category/skin-care", + items: [ + { text: "Cleansers", href: "/category/cleansers" }, + { text: "Moisturizers", href: "/category/moisturizers" }, + { text: "Treatments & Serums", href: "/category/treatments-and-serums" }, + ], + }, + { + text: "Makeup", + href: "/category/makeup", + items: [ + { text: "Face Makeup", href: "/category/face-makeup" }, + { text: "Eye Makeup", href: "/category/eye-makeup" }, + { text: "Lip Makeup", href: "/category/lip-makeup" }, + ], + }, + { + text: "Haircare", + href: "/category/haircare", + items: [ + { text: "Shampoos & Conditioners", href: "/category/shampoos-and-conditioners" }, + { text: "Styling Products", href: "/category/styling-products" }, + ], + }, + + { + text: "Fragrances", + href: "/category/fragrances", + items: [ + { text: "Perfumes", href: "/category/perfumes" }, + { text: "Body Sprays", href: "/category/body-sprays" }, + ], + }, + ], + }, + }, + { + text: "Furniture", + href: "/category/furniture", + submenu: { + variant: "text-grid", + items: [ + { + text: "Living Room", + href: "/category/living-room-furniture", + items: [ + { text: "Sofas & Sectionals", href: "/category/sofas-and-sectionals" }, + { text: "Coffee Tables", href: "/category/coffee-tables" }, + { text: "TV Stands", href: "/category/tv-stands" }, + ], + }, + + { + text: "Bedroom", + href: "/category/bedroom-furniture", + items: [ + { text: "Beds", href: "/category/beds" }, + { text: "Dressers", href: "/category/dressers" }, + { text: "Nightstands", href: "/category/nightstands" }, + ], + }, + + { + text: "Office", + href: "/category/office-furniture", + items: [ + { text: "Desks", href: "/category/desks" }, + { text: "Office Chairs", href: "/category/office-chairs" }, + { text: "Storage Solutions", href: "/category/storage-solutions" }, + ], + }, + ], + }, + }, +] + +export const metadata: Metadata = { + title: "Next.js Enterprise Commerce | Blazity", + description: "AI-FIRST NEXT.JS STOREFRONT FOR COMPOSABLE COMMERCE", + metadataBase: new URL(env.LIVE_URL!), + openGraph: { + title: "Next.js Enterprise Commerce | Blazity", + description: "AI-FIRST NEXT.JS STOREFRONT FOR COMPOSABLE COMMERCE", + images: ["/opengraph-image.jpg"], + }, + twitter: { + card: "summary_large_image", + title: "Next.js Enterprise Commerce | Blazity", + description: "AI-FIRST NEXT.JS STOREFRONT FOR COMPOSABLE COMMERCE", + creator: "@blazity", + images: ["/opengraph-image.jpg"], + }, + verification: { + google: "google", + yandex: "yandex", + yahoo: "yahoo", + }, + generator: "Next.js", + applicationName: "Next.js", +} + +export default async function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + {children} + + +
+ ) +} diff --git a/starters/shopify-meilisearch/components/Card/Card.stories.tsx b/starters/shopify-meilisearch/components/Card/Card.stories.tsx new file mode 100644 index 00000000..7ede5bd9 --- /dev/null +++ b/starters/shopify-meilisearch/components/Card/Card.stories.tsx @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from "@storybook/react" +import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "./Card" + +const meta: Meta = { + title: "Card", + component: Card, + args: {}, + argTypes: {}, +} + +type Story = StoryObj + +export const Default: Story = { + render: () => ( + + + Card title + + + Nulla occaecat est reprehenderit nostrud nulla sint tempor commodo excepteur ea. Proident aliquip non do adipisicing cillum enim non nulla aliquip. Adipisicing deserunt + dolor est cupidatat sint laboris cillum laborum reprehenderit do. Laboris labore qui exercitation ea eiusmod. Reprehenderit laborum quis labore nulla. Ex culpa esse + consequat aute ex non ad est cupidatat veniam. Nulla anim duis eu eiusmod sint nisi qui eu. + + Card footer + + ), +} + +export default meta diff --git a/starters/shopify-meilisearch/components/Card/Card.tsx b/starters/shopify-meilisearch/components/Card/Card.tsx new file mode 100644 index 00000000..deb20968 --- /dev/null +++ b/starters/shopify-meilisearch/components/Card/Card.tsx @@ -0,0 +1,35 @@ +/* eslint-disable jsx-a11y/heading-has-content */ +import * as React from "react" +import { cn } from "utils/cn" + +const Card = React.forwardRef>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef>(({ className, ...props }, ref) => ( +

+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef>(({ className, ...props }, ref) => ( +

+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef>(({ className, ...props }, ref) => ( +

+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/starters/shopify-meilisearch/components/Carousel/Carousel.stories.tsx b/starters/shopify-meilisearch/components/Carousel/Carousel.stories.tsx new file mode 100644 index 00000000..edbe862f --- /dev/null +++ b/starters/shopify-meilisearch/components/Carousel/Carousel.stories.tsx @@ -0,0 +1,27 @@ +/* eslint-disable @next/next/no-img-element */ +/* eslint-disable jsx-a11y/alt-text */ +import type { Meta, StoryObj } from "@storybook/react" +import { Carousel, CarouselContent } from "./Carousel" + +const meta: Meta = { + title: "Carousel", + component: Carousel, + args: {}, + argTypes: {}, +} + +type Story = StoryObj + +export const Default: Story = { + render: () => ( + + + {Array.from({ length: 8 }, (product, idx) => ( + + ))} + + + ), +} + +export default meta diff --git a/starters/shopify-meilisearch/components/Carousel/Carousel.tsx b/starters/shopify-meilisearch/components/Carousel/Carousel.tsx new file mode 100644 index 00000000..b88b5298 --- /dev/null +++ b/starters/shopify-meilisearch/components/Carousel/Carousel.tsx @@ -0,0 +1,198 @@ +"use client" + +import useEmblaCarousel, { type UseEmblaCarouselType } from "embla-carousel-react" + +import { createContext, forwardRef, useCallback, useContext, useEffect, useState } from "react" +import { cn } from "utils/cn" +import { Button } from "../Button/Button" +import { ChevronIcon } from "../Icons/ChevronIcon" + +type CarouselApi = UseEmblaCarouselType[1] +type UseCarouselParameters = Parameters +type CarouselOptions = UseCarouselParameters[0] +type CarouselPlugin = UseCarouselParameters[1] + +interface CarouselProps { + opts?: CarouselOptions + plugins?: CarouselPlugin + orientation?: "horizontal" | "vertical" + setApi?: (api: CarouselApi) => void +} + +interface CarouselContextProps extends CarouselProps { + carouselRef: ReturnType[0] + api: ReturnType[1] + scrollPrev: () => void + scrollNext: () => void + canScrollPrev: boolean + canScrollNext: boolean +} + +const CarouselContext = createContext(null) + +export function useCarousel() { + const context = useContext(CarouselContext) + + if (!context) { + throw new Error("useCarousel must be used within a ") + } + + return context +} + +const Carousel = forwardRef & CarouselProps>( + ({ orientation = "horizontal", opts, setApi, plugins, className, children, ...props }, ref) => { + const [carouselRef, api] = useEmblaCarousel( + { + ...opts, + axis: orientation === "horizontal" ? "x" : "y", + }, + plugins + ) + + const [canScrollPrev, setCanScrollPrev] = useState(false) + const [canScrollNext, setCanScrollNext] = useState(false) + + const onSelect = useCallback((api: CarouselApi) => { + if (!api) { + return + } + + setCanScrollPrev(api.canScrollPrev()) + setCanScrollNext(api.canScrollNext()) + }, []) + + const scrollPrev = useCallback(() => { + api?.scrollPrev() + }, [api]) + + const scrollNext = useCallback(() => { + api?.scrollNext() + }, [api]) + + const handleKeyDown = useCallback( + (event: React.KeyboardEvent) => { + if (event.key === "ArrowLeft") { + event.preventDefault() + scrollPrev() + } else if (event.key === "ArrowRight") { + event.preventDefault() + scrollNext() + } + }, + [scrollPrev, scrollNext] + ) + + useEffect(() => { + if (!api || !setApi) { + return + } + + setApi(api) + }, [api, setApi]) + + useEffect(() => { + if (!api) { + return + } + + onSelect(api) + api.on("reInit", onSelect) + api.on("select", onSelect) + + return () => { + api?.off("select", onSelect) + } + }, [api, onSelect]) + + return ( + +
+ {children} +
+
+ ) + } +) +Carousel.displayName = "Carousel" + +const CarouselContent = forwardRef>(({ className, ...props }, ref) => { + const { carouselRef, orientation } = useCarousel() + + return ( +
+
+
+ ) +}) +CarouselContent.displayName = "CarouselContent" + +const CarouselItem = forwardRef>(({ className, ...props }, ref) => { + const { orientation } = useCarousel() + + return ( +
+ ) +}) +CarouselItem.displayName = "CarouselItem" + +const CarouselPrevious = forwardRef>(({ className, ...props }, ref) => { + const { scrollPrev, canScrollPrev } = useCarousel() + + return ( + + ) +}) +CarouselPrevious.displayName = "CarouselPrevious" + +const CarouselNext = forwardRef>(({ className, ...props }, ref) => { + const { scrollNext, canScrollNext } = useCarousel() + + return ( + + ) +}) +CarouselNext.displayName = "CarouselNext" + +export { type CarouselApi, Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext } diff --git a/starters/shopify-meilisearch/components/Checkbox/Checkbox.stories.tsx b/starters/shopify-meilisearch/components/Checkbox/Checkbox.stories.tsx new file mode 100644 index 00000000..b63d1da6 --- /dev/null +++ b/starters/shopify-meilisearch/components/Checkbox/Checkbox.stories.tsx @@ -0,0 +1,23 @@ +import type { Meta, StoryObj } from "@storybook/react" +import { Label } from "components/Label/Label" +import { Checkbox } from "./Checkbox" + +const meta: Meta = { + title: "Checkbox", + component: Checkbox, + args: {}, + argTypes: {}, +} + +type Story = StoryObj + +export const Default: Story = { + render: () => ( + + ), +} + +export default meta diff --git a/starters/shopify-meilisearch/components/Checkbox/Checkbox.tsx b/starters/shopify-meilisearch/components/Checkbox/Checkbox.tsx new file mode 100644 index 00000000..cd582bd5 --- /dev/null +++ b/starters/shopify-meilisearch/components/Checkbox/Checkbox.tsx @@ -0,0 +1,26 @@ +"use client" + +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import * as React from "react" +import { cn } from "utils/cn" +import { CheckIcon } from "../Icons/CheckIcon" + +const Checkbox = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, ...props }, ref) => ( + + + + + + ) +) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export { Checkbox } diff --git a/starters/shopify-meilisearch/components/Dialog/Dialog.stories.tsx b/starters/shopify-meilisearch/components/Dialog/Dialog.stories.tsx new file mode 100644 index 00000000..0b52e828 --- /dev/null +++ b/starters/shopify-meilisearch/components/Dialog/Dialog.stories.tsx @@ -0,0 +1,26 @@ +import type { Meta, StoryObj } from "@storybook/react" +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "./Dialog" + +const meta: Meta = { + title: "Dialog", + component: Dialog, + args: {}, + argTypes: {}, +} + +type Story = StoryObj + +export const Default: Story = { + render: () => ( + + + + Dialog title + + Hello world + + + ), +} + +export default meta diff --git a/starters/shopify-meilisearch/components/Dialog/Dialog.tsx b/starters/shopify-meilisearch/components/Dialog/Dialog.tsx new file mode 100644 index 00000000..a62d88cd --- /dev/null +++ b/starters/shopify-meilisearch/components/Dialog/Dialog.tsx @@ -0,0 +1,68 @@ +"use client" + +import * as DialogPrimitive from "@radix-ui/react-dialog" +import * as React from "react" +import { cn } from "utils/cn" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, ...props }, ref) => ( + + ) +) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, children, ...props }, ref) => ( + + + + {children} + + + ) +) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, ...props }, ref) => +) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, ...props }, ref) => +) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { Dialog, DialogPortal, DialogOverlay, DialogTrigger, DialogClose, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription } diff --git a/starters/shopify-meilisearch/components/DropdownMenu/DropdownMenu.stories.tsx b/starters/shopify-meilisearch/components/DropdownMenu/DropdownMenu.stories.tsx new file mode 100644 index 00000000..a93cecd1 --- /dev/null +++ b/starters/shopify-meilisearch/components/DropdownMenu/DropdownMenu.stories.tsx @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from "@storybook/react" +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "./DropdownMenu" + +const meta: Meta = { + title: "DropdownMenu", + component: DropdownMenu, + args: {}, + argTypes: {}, +} + +type Story = StoryObj + +export const Default: Story = { + render: () => ( + + Dropdown menu + + Settings + Item 1 + Item 2 + Item 3 + Item 4 + Item 5 + + + ), +} + +export default meta diff --git a/starters/shopify-meilisearch/components/DropdownMenu/DropdownMenu.tsx b/starters/shopify-meilisearch/components/DropdownMenu/DropdownMenu.tsx new file mode 100644 index 00000000..a446e2fb --- /dev/null +++ b/starters/shopify-meilisearch/components/DropdownMenu/DropdownMenu.tsx @@ -0,0 +1,162 @@ +"use client" + +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import * as React from "react" +import { cn } from "utils/cn" + +const DropdownMenu = DropdownMenuPrimitive.Root + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger + +const DropdownMenuGroup = DropdownMenuPrimitive.Group + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal + +const DropdownMenuSub = DropdownMenuPrimitive.Sub + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + +)) +DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName + +const DropdownMenuSubContent = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, ...props }, ref) => ( + + ) +) +DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName + +const DropdownMenuContent = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, sideOffset = 4, ...props }, ref) => ( + + + + ) +) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + {children} + +)) +DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName + +const DropdownMenuRadioItem = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, children, ...props }, ref) => ( + + + + + {children} + + ) +) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +const DropdownMenuSeparator = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, ...props }, ref) => +) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName + +const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { + return +} +DropdownMenuShortcut.displayName = "DropdownMenuShortcut" + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +} diff --git a/starters/shopify-meilisearch/components/ExpandableContent/ExpandableContent.tsx b/starters/shopify-meilisearch/components/ExpandableContent/ExpandableContent.tsx new file mode 100644 index 00000000..96e461f4 --- /dev/null +++ b/starters/shopify-meilisearch/components/ExpandableContent/ExpandableContent.tsx @@ -0,0 +1,52 @@ +"use client" + +import { ChevronIcon } from "components/Icons/ChevronIcon" +import { type ReactNode, useEffect, useRef, useState } from "react" +import { cn } from "utils/cn" + +type ExpandableContentProps = { + children: ReactNode + className?: string + lines: 1 | 2 | 3 | 4 | 5 | 6 +} + +export const ExpandableContent = ({ children, className, lines = 2 }: ExpandableContentProps) => { + const [isExpanded, setIsExpanded] = useState(false) + const [isClamped, setIsClamped] = useState(false) + const contentRef = useRef(null) + + useEffect(() => { + if (!contentRef?.current) return + + const checkClamp = () => { + if (!contentRef.current) return + setIsClamped(contentRef.current.scrollHeight > contentRef.current.clientHeight) + } + + checkClamp() + window.addEventListener("resize", checkClamp) + return () => window.removeEventListener("resize", checkClamp) + }, []) + + return ( +
+
+ {children} +
+ {isClamped && ( + + )} +
+ ) +} diff --git a/starters/shopify-meilisearch/components/Footer/Footer.stories.tsx b/starters/shopify-meilisearch/components/Footer/Footer.stories.tsx new file mode 100644 index 00000000..40e325eb --- /dev/null +++ b/starters/shopify-meilisearch/components/Footer/Footer.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from "@storybook/react" +import { Footer } from "./Footer" + +const meta: Meta = { + title: "Footer", + component: Footer, + args: {}, + argTypes: {}, +} + +type Story = StoryObj + +export const Default: Story = { + render: () =>