diff --git a/package.json b/package.json index 91a529d52..57df2ec3b 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,8 @@ "classnames": "^2.3.1", "cookie": "^0.4.1", "email-validator": "^2.0.4", + "eslint": "^7.32.0", + "eslint-config-next": "^11.1.2", "immutability-helper": "^3.1.1", "js-cookie": "^2.2.1", "keen-slider": "^5.5.1", @@ -66,6 +68,7 @@ "@types/node": "^15.12.4", "@types/react": "^17.0.8", "deepmerge": "^4.2.2", + "eslint-config-prettier": "^8.3.0", "graphql": "^15.5.1", "husky": "^6.0.0", "lint-staged": "^11.0.0", diff --git a/pages/blog/[slug].tsx b/pages/blog/[slug].tsx new file mode 100644 index 000000000..773634c26 --- /dev/null +++ b/pages/blog/[slug].tsx @@ -0,0 +1,17 @@ +import { Layout, RelevantBlogPosts } from 'src/components/common'; +import BlogContent from 'src/components/modules/blog-detail/BlogContent/BlogContent'; +import BlogDetailImg from 'src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg'; +import { RECIPE_DATA_TEST } from 'src/utils/demo-data' + + +export default function BlogDetailPage() { + return ( + <> + + + + + ) +} + +BlogDetailPage.Layout = Layout diff --git a/pages/index.tsx b/pages/index.tsx index 158b1dc60..7d23ebadd 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -19,4 +19,4 @@ export default function Home() { ) } -// Home.Layout = Layout +Home.Layout = Layout diff --git a/pages/recipes.tsx b/pages/recipes.tsx new file mode 100644 index 000000000..a4acece13 --- /dev/null +++ b/pages/recipes.tsx @@ -0,0 +1,15 @@ +import { Layout } from 'src/components/common'; +import RecipeListBanner from 'src/components/modules/recipes-list/RecipeListBanner/RecipeListBanner'; +import RecipesList from 'src/components/modules/recipes-list/RecipesList/RecipesList'; + + +export default function RecipeListPage() { + return ( + <> + + + + ) +} + +RecipeListPage.Layout = Layout diff --git a/pages/test.tsx b/pages/test.tsx index f46bd55fe..262886faa 100644 --- a/pages/test.tsx +++ b/pages/test.tsx @@ -1,39 +1,81 @@ -import { useState } from 'react' import { - Layout, -} from 'src/components/common' -import { CardItemCheckoutProps } from 'src/components/common/CardItemCheckout/CardItemCheckout' -import TabPane from 'src/components/common/TabCommon/components/TabPane/TabPane' -import TabCommon from 'src/components/common/TabCommon/TabCommon' -import { CheckoutInfo } from 'src/components/modules/checkout' -import image7 from '../public/assets/images/image7.png' -import image8 from '../public/assets/images/image8.png' + Layout, RecipeDetail +} from 'src/components/common'; +import MenuNavigation from 'src/components/common/MenuNavigation/MenuNavigation'; +import MenuNavigationProductList from 'src/components/common/MenuNavigationProductList/MenuNavigationProductList'; +// import { RecipeListPage } from 'src/components/modules/recipes'; +import { OPTION_ALL, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'; +const CATEGORY = [ + { + name: 'All', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=${OPTION_ALL}`, + }, + { + name: 'Veggie', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=veggie`, + }, + { + name: 'Seafood', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=seafood`, + }, + { + name: 'Frozen', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=frozen`, + }, + { + name: 'Coffee Bean', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=coffee-bean`, + }, + { + name: 'Sauce', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=sauce`, + }, +] +const BRAND = [ + { + name: 'Maggi', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=veggie`, + }, + { + name: 'Cholimes', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=seafood`, + }, + { + name: 'Chinsu', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=frozen`, + } +]; + +const FEATURED = [ + + { + name: 'Best Sellers', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=veggie`, + }, + { + name: 'Sales', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=seafood`, + }, + { + name: 'New Item', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=frozen`, + }, + { + name: 'Viewed', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=viewed`, + } + ]; export default function Test() { + return ( <> + {/* */} - - -
- datdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdat -
-
- -
- Lorem ipsum dolor sit, amet consectetur adipisicing elit. Suscipit harum sint maiores optio? Perspiciatis, necessitatibus pariatur, ut sed aperiam minus reiciendis alias deleniti eligendi obcaecati illum id maxime accusantium beatae. -
-
- -
- 11111111111111111111111111111111111111111111111111111111111 -
-
-
+ {/* */} + {/**/} + ) } diff --git a/public/bg-products.svg b/public/bg-products.svg index 2118c3277..1eaa1df8b 100644 --- a/public/bg-products.svg +++ b/public/bg-products.svg @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/report.20210908.160959.14332.0.001.json b/report.20210908.160959.14332.0.001.json new file mode 100644 index 000000000..dc9027da1 --- /dev/null +++ b/report.20210908.160959.14332.0.001.json @@ -0,0 +1,646 @@ + +{ + "header": { + "reportVersion": 1, + "event": "Allocation failed - JavaScript heap out of memory", + "trigger": "FatalError", + "filename": "report.20210908.160959.14332.0.001.json", + "dumpEventTime": "2021-09-08T16:09:59Z", + "dumpEventTimeStamp": "1631092199677", + "processId": 14332, + "cwd": "G:\\hoc-fpt-2\\làm việc\\kie\\work\\grocery-vercel-commerce", + "commandLine": [ + "node", + "G:\\hoc-fpt-2\\làm việc\\kie\\work\\grocery-vercel-commerce\\node_modules\\.bin\\\\..\\next\\dist\\bin\\next", + "dev" + ], + "nodejsVersion": "v12.15.0", + "wordSize": 64, + "arch": "x64", + "platform": "win32", + "componentVersions": { + "node": "12.15.0", + "v8": "7.7.299.13-node.16", + "uv": "1.33.1", + "zlib": "1.2.11", + "brotli": "1.0.7", + "ares": "1.15.0", + "modules": "72", + "nghttp2": "1.40.0", + "napi": "5", + "llhttp": "2.0.4", + "http_parser": "2.9.3", + "openssl": "1.1.1d", + "cldr": "35.1", + "icu": "64.2", + "tz": "2019c", + "unicode": "12.1" + }, + "release": { + "name": "node", + "lts": "Erbium", + "headersUrl": "https://nodejs.org/download/release/v12.15.0/node-v12.15.0-headers.tar.gz", + "sourceUrl": "https://nodejs.org/download/release/v12.15.0/node-v12.15.0.tar.gz", + "libUrl": "https://nodejs.org/download/release/v12.15.0/win-x64/node.lib" + }, + "osName": "Windows_NT", + "osRelease": "10.0.19043", + "osVersion": "Windows 10 Pro", + "osMachine": "x86_64", + "cpus": [ + { + "model": "Intel(R) Core(TM) i3-3110M CPU @ 2.40GHz", + "speed": 2395, + "user": 67605265, + "nice": 0, + "sys": 33647953, + "idle": 255172281, + "irq": 3598359 + }, + { + "model": "Intel(R) Core(TM) i3-3110M CPU @ 2.40GHz", + "speed": 2395, + "user": 68803843, + "nice": 0, + "sys": 25225015, + "idle": 262396453, + "irq": 602640 + }, + { + "model": "Intel(R) Core(TM) i3-3110M CPU @ 2.40GHz", + "speed": 2395, + "user": 76698718, + "nice": 0, + "sys": 25995390, + "idle": 253731187, + "irq": 321484 + }, + { + "model": "Intel(R) Core(TM) i3-3110M CPU @ 2.40GHz", + "speed": 2395, + "user": 77662531, + "nice": 0, + "sys": 24450312, + "idle": 254312468, + "irq": 266531 + } + ], + "networkInterfaces": [ + { + "name": "Wi-Fi", + "internal": false, + "mac": "a4:17:31:1d:cc:e5", + "address": "2402:800:6318:9d24:f937:34a5:8214:a074", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "Wi-Fi", + "internal": false, + "mac": "a4:17:31:1d:cc:e5", + "address": "2402:800:6318:9d24:69cf:fc3d:74:1b08", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "Wi-Fi", + "internal": false, + "mac": "a4:17:31:1d:cc:e5", + "address": "fe80::f937:34a5:8214:a074", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 21 + }, + { + "name": "Wi-Fi", + "internal": false, + "mac": "a4:17:31:1d:cc:e5", + "address": "192.168.1.10", + "netmask": "255.255.255.0", + "family": "IPv4" + }, + { + "name": "Loopback Pseudo-Interface 1", + "internal": true, + "mac": "00:00:00:00:00:00", + "address": "::1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "Loopback Pseudo-Interface 1", + "internal": true, + "mac": "00:00:00:00:00:00", + "address": "127.0.0.1", + "netmask": "255.0.0.0", + "family": "IPv4" + } + ], + "host": "DESKTOP-TILU55O" + }, + "javascriptStack": { + "message": "No stack.", + "stack": [ + "Unavailable." + ] + }, + "nativeStack": [ + { + "pc": "0x00007ff77aa01759", + "symbol": "std::basic_ostream >::operator<<+10873" + }, + { + "pc": "0x00007ff77aa05b7c", + "symbol": "std::basic_ostream >::operator<<+28316" + }, + { + "pc": "0x00007ff77aa04b38", + "symbol": "std::basic_ostream >::operator<<+24152" + }, + { + "pc": "0x00007ff77aaf446b", + "symbol": "v8::base::CPU::has_sse+37723" + }, + { + "pc": "0x00007ff77b2f8d9e", + "symbol": "v8::Isolate::ReportExternalAllocationLimitReached+94" + }, + { + "pc": "0x00007ff77b2e0de1", + "symbol": "v8::SharedArrayBuffer::Externalize+833" + }, + { + "pc": "0x00007ff77b1ae6ac", + "symbol": "v8::internal::Heap::EphemeronKeyWriteBarrierFromCode+1436" + }, + { + "pc": "0x00007ff77b1b9a50", + "symbol": "v8::internal::Heap::ProtectUnprotectedMemoryChunks+1312" + }, + { + "pc": "0x00007ff77b1b6584", + "symbol": "v8::internal::Heap::PageFlagsAreConsistent+3204" + }, + { + "pc": "0x00007ff77b1abe13", + "symbol": "v8::internal::Heap::CollectGarbage+1283" + }, + { + "pc": "0x00007ff77b1aa5e4", + "symbol": "v8::internal::Heap::AddRetainedMap+2356" + }, + { + "pc": "0x00007ff77b1c46ee", + "symbol": "v8::internal::Factory::AllocateRawFixedArray+94" + }, + { + "pc": "0x00007ff77b1cba84", + "symbol": "v8::internal::Factory::NewFixedArrayWithFiller+52" + }, + { + "pc": "0x00007ff77b1cba41", + "symbol": "v8::internal::Factory::NewUninitializedFixedArray+65" + }, + { + "pc": "0x00007ff77b0ac86f", + "symbol": "v8::Object::GetIsolate+6767" + }, + { + "pc": "0x00007ff77af5feaa", + "symbol": "v8::internal::OrderedHashMap::ValueAt+61274" + }, + { + "pc": "0x00007ff77b724d3d", + "symbol": "v8::internal::SetupIsolateDelegate::SetupHeap+567949" + }, + { + "pc": "0x0000004163e2d61e", + "symbol": "" + } + ], + "javascriptHeap": { + "totalMemory": 2197684224, + "totalCommittedMemory": 2197684224, + "usedMemory": 2099361840, + "availableMemory": 89682992, + "memoryLimit": 2197815296, + "heapSpaces": { + "read_only_space": { + "memorySize": 262144, + "committedMemory": 262144, + "capacity": 261872, + "used": 32296, + "available": 229576 + }, + "new_space": { + "memorySize": 33554432, + "committedMemory": 33554432, + "capacity": 16759808, + "used": 9024016, + "available": 7735792 + }, + "old_space": { + "memorySize": 1753329664, + "committedMemory": 1753329664, + "capacity": 1750360832, + "used": 1685534088, + "available": 64826744 + }, + "code_space": { + "memorySize": 5144576, + "committedMemory": 5144576, + "capacity": 4347712, + "used": 4347712, + "available": 0 + }, + "map_space": { + "memorySize": 8916992, + "committedMemory": 8916992, + "capacity": 4381920, + "used": 4381920, + "available": 0 + }, + "large_object_space": { + "memorySize": 395280384, + "committedMemory": 395280384, + "capacity": 394944560, + "used": 394944560, + "available": 0 + }, + "code_large_object_space": { + "memorySize": 1196032, + "committedMemory": 1196032, + "capacity": 1097248, + "used": 1097248, + "available": 0 + }, + "new_large_object_space": { + "memorySize": 0, + "committedMemory": 0, + "capacity": 16759808, + "used": 0, + "available": 16759808 + } + } + }, + "resourceUsage": { + "userCpuSeconds": 2420.01, + "kernelCpuSeconds": 114.859, + "cpuConsumptionPercent": 11.0361, + "maxRss": 2818129920, + "pageFaults": { + "IORequired": 14395451, + "IONotRequired": 0 + }, + "fsActivity": { + "reads": 46029, + "writes": 640054 + } + }, + "libuv": [ + ], + "environmentVariables": { + "=G:": "G:\\hoc-fpt-2\\làm việc\\kie\\work\\grocery-vercel-commerce", + "ALLUSERSPROFILE": "C:\\ProgramData", + "ANDROID_HOME": "G:\\ASDK", + "ANDROID_SDK_ROOT": "G:\\ASDK", + "APPDATA": "C:\\Users\\nhan\\AppData\\Roaming", + "ChocolateyInstall": "C:\\ProgramData\\chocolatey", + "ChocolateyLastPathUpdate": "132608575831335062", + "CHROME_CRASHPAD_PIPE_NAME": "\\\\.\\pipe\\crashpad_17244_MSJZWZVAYBLFIPJS", + "CLASSPATH": "C:\\Program Files\\Java\\jdk1.8.0_231\\bin", + "COLORTERM": "truecolor", + "COMMERCE_CUSTOMERAUTH_ENABLED": "true", + "COMMERCE_PROVIDER": "vendure", + "CommonProgramFiles": "C:\\Program Files\\Common Files", + "CommonProgramFiles(x86)": "C:\\Program Files (x86)\\Common Files", + "CommonProgramW6432": "C:\\Program Files\\Common Files", + "COMPUTERNAME": "DESKTOP-TILU55O", + "ComSpec": "C:\\WINDOWS\\system32\\cmd.exe", + "dp0": "G:\\hoc-fpt-2\\làm việc\\kie\\work\\grocery-vercel-commerce\\node_modules\\.bin\\", + "DriverData": "C:\\Windows\\System32\\Drivers\\DriverData", + "FPS_BROWSER_APP_PROFILE_STRING": "Internet Explorer", + "FPS_BROWSER_USER_PROFILE_STRING": "Default", + "GIT_ASKPASS": "c:\\Users\\nhan\\AppData\\Local\\Programs\\Microsoft VS Code\\resources\\app\\extensions\\git\\dist\\askpass.sh", + "GIT_LFS_PATH": "C:\\Program Files\\Git LFS", + "HOME": "C:\\Users\\nhan", + "HOMEDRIVE": "C:", + "HOMEPATH": "\\Users\\nhan", + "INIT_CWD": "G:\\hoc-fpt-2\\làm việc\\kie\\work\\grocery-vercel-commerce", + "JAVA_HOME": "C:\\Program Files\\Java\\jdk1.8.0_281", + "LANG": "en_US.UTF-8", + "LOCALAPPDATA": "C:\\Users\\nhan\\AppData\\Local", + "LOGONSERVER": "\\\\DESKTOP-TILU55O", + "NEXT_PUBLIC_VENDURE_LOCAL_URL": "/vendure-shop-api", + "NEXT_PUBLIC_VENDURE_SHOP_API_URL": "https://demo.vendure.io/shop-api", + "NODE": "C:\\Program Files\\nodejs\\node.exe", + "NODE_ENV": "development", + "NODE_EXE": "C:\\Program Files\\nodejs\\\\node.exe", + "NODE_OPTIONS": "'--inspect' ", + "NPM_CLI_JS": "C:\\Program Files\\nodejs\\\\node_modules\\npm\\bin\\npm-cli.js", + "npm_config_access": "", + "npm_config_allow_same_version": "", + "npm_config_also": "", + "npm_config_always_auth": "", + "npm_config_argv": "{\"remain\":[],\"cooked\":[\"run\",\"dev-windows\"],\"original\":[\"run\",\"dev-windows\"]}", + "npm_config_audit": "true", + "npm_config_audit_level": "low", + "npm_config_auth_type": "legacy", + "npm_config_before": "", + "npm_config_bin_links": "true", + "npm_config_browser": "", + "npm_config_ca": "", + "npm_config_cache": "C:\\Users\\nhan\\AppData\\Roaming\\npm-cache", + "npm_config_cache_lock_retries": "10", + "npm_config_cache_lock_stale": "60000", + "npm_config_cache_lock_wait": "10000", + "npm_config_cache_max": "Infinity", + "npm_config_cache_min": "10", + "npm_config_cafile": "", + "npm_config_cert": "", + "npm_config_cidr": "", + "npm_config_color": "true", + "npm_config_commit_hooks": "true", + "npm_config_depth": "Infinity", + "npm_config_description": "true", + "npm_config_dev": "", + "npm_config_dry_run": "", + "npm_config_editor": "notepad.exe", + "npm_config_engine_strict": "", + "npm_config_fetch_retries": "2", + "npm_config_fetch_retry_factor": "10", + "npm_config_fetch_retry_maxtimeout": "60000", + "npm_config_fetch_retry_mintimeout": "10000", + "npm_config_force": "", + "npm_config_format_package_lock": "true", + "npm_config_fund": "true", + "npm_config_git": "git", + "npm_config_git_tag_version": "true", + "npm_config_global": "", + "npm_config_globalconfig": "C:\\Users\\nhan\\AppData\\Roaming\\npm\\etc\\npmrc", + "npm_config_globalignorefile": "C:\\Users\\nhan\\AppData\\Roaming\\npm\\etc\\npmignore", + "npm_config_global_style": "", + "npm_config_group": "", + "npm_config_ham_it_up": "", + "npm_config_heading": "npm", + "npm_config_https_proxy": "", + "npm_config_if_present": "", + "npm_config_ignore_prepublish": "", + "npm_config_ignore_scripts": "", + "npm_config_init_author_email": "", + "npm_config_init_author_name": "", + "npm_config_init_author_url": "", + "npm_config_init_license": "ISC", + "npm_config_init_module": "C:\\Users\\nhan\\.npm-init.js", + "npm_config_init_version": "1.0.0", + "npm_config_json": "", + "npm_config_key": "", + "npm_config_legacy_bundling": "", + "npm_config_link": "", + "npm_config_local_address": "", + "npm_config_loglevel": "notice", + "npm_config_logs_max": "10", + "npm_config_long": "", + "npm_config_maxsockets": "50", + "npm_config_message": "%s", + "npm_config_metrics_registry": "https://registry.npmjs.org/", + "npm_config_node_gyp": "C:\\Program Files\\nodejs\\node_modules\\npm\\node_modules\\node-gyp\\bin\\node-gyp.js", + "npm_config_node_options": "", + "npm_config_node_version": "12.15.0", + "npm_config_noproxy": "", + "npm_config_offline": "", + "npm_config_onload_script": "", + "npm_config_only": "", + "npm_config_optional": "true", + "npm_config_otp": "", + "npm_config_package_lock": "true", + "npm_config_package_lock_only": "", + "npm_config_parseable": "", + "npm_config_prefer_offline": "", + "npm_config_prefer_online": "", + "npm_config_prefix": "C:\\Users\\nhan\\AppData\\Roaming\\npm", + "npm_config_preid": "", + "npm_config_production": "", + "npm_config_progress": "true", + "npm_config_proxy": "", + "npm_config_read_only": "", + "npm_config_rebuild_bundle": "true", + "npm_config_registry": "https://registry.npmjs.org/", + "npm_config_rollback": "true", + "npm_config_save": "true", + "npm_config_save_bundle": "", + "npm_config_save_dev": "", + "npm_config_save_exact": "", + "npm_config_save_optional": "", + "npm_config_save_prefix": "^", + "npm_config_save_prod": "", + "npm_config_scope": "", + "npm_config_scripts_prepend_node_path": "warn-only", + "npm_config_script_shell": "", + "npm_config_searchexclude": "", + "npm_config_searchlimit": "20", + "npm_config_searchopts": "", + "npm_config_searchstaleness": "900", + "npm_config_send_metrics": "", + "npm_config_shell": "C:\\WINDOWS\\system32\\cmd.exe", + "npm_config_shrinkwrap": "true", + "npm_config_sign_git_commit": "", + "npm_config_sign_git_tag": "", + "npm_config_sso_poll_frequency": "500", + "npm_config_sso_type": "oauth", + "npm_config_strict_ssl": "true", + "npm_config_tag": "latest", + "npm_config_tag_version_prefix": "v", + "npm_config_timing": "", + "npm_config_tmp": "C:\\Users\\nhan\\AppData\\Local\\Temp", + "npm_config_umask": "0000", + "npm_config_unicode": "", + "npm_config_unsafe_perm": "true", + "npm_config_update_notifier": "true", + "npm_config_usage": "", + "npm_config_user": "", + "npm_config_userconfig": "C:\\Users\\nhan\\.npmrc", + "npm_config_user_agent": "npm/6.13.4 node/v12.15.0 win32 x64", + "npm_config_version": "", + "npm_config_versions": "", + "npm_config_viewer": "browser", + "npm_execpath": "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js", + "npm_lifecycle_event": "dev-windows", + "npm_lifecycle_script": "set NODE_OPTIONS='--inspect' && set PORT=3005 && next dev", + "npm_node_execpath": "C:\\Program Files\\nodejs\\node.exe", + "npm_package_dependencies_autoprefixer": "^10.2.6", + "npm_package_dependencies_body_scroll_lock": "^3.1.5", + "npm_package_dependencies_classnames": "^2.3.1", + "npm_package_dependencies_cookie": "^0.4.1", + "npm_package_dependencies_email_validator": "^2.0.4", + "npm_package_dependencies_eslint": "^7.32.0", + "npm_package_dependencies_eslint_config_next": "^11.1.2", + "npm_package_dependencies_immutability_helper": "^3.1.1", + "npm_package_dependencies_js_cookie": "^2.2.1", + "npm_package_dependencies_keen_slider": "^5.5.1", + "npm_package_dependencies_lodash_debounce": "^4.0.8", + "npm_package_dependencies_lodash_random": "^3.2.0", + "npm_package_dependencies_lodash_throttle": "^4.1.1", + "npm_package_dependencies_next": "^11.0.0", + "npm_package_dependencies_next_seo": "^4.26.0", + "npm_package_dependencies_next_themes": "^0.0.14", + "npm_package_dependencies_postcss": "^8.3.5", + "npm_package_dependencies_postcss_nesting": "^8.0.1", + "npm_package_dependencies_react": "^17.0.2", + "npm_package_dependencies_react_dom": "^17.0.2", + "npm_package_dependencies_react_fast_marquee": "^1.1.4", + "npm_package_dependencies_react_merge_refs": "^1.1.0", + "npm_package_dependencies_react_player": "^2.9.0", + "npm_package_dependencies_react_use_measure": "^2.0.4", + "npm_package_dependencies_sass": "^1.38.0", + "npm_package_dependencies_swell_js": "^4.0.0-next.0", + "npm_package_dependencies_swr": "^0.5.6", + "npm_package_dependencies_tabbable": "^5.2.0", + "npm_package_dependencies_tailwindcss": "^2.2.2", + "npm_package_dependencies_uuidv4": "^6.2.10", + "npm_package_dependencies__react_spring_web": "^9.2.1", + "npm_package_dependencies__vercel_fetch": "^6.1.0", + "npm_package_description": "[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fcommerce&project-name=commerce&repo-name=commerce&demo-title=Next.js%20Commerce&demo-description=An%20all-in-one%20starter%20kit%20for%20high-performance%20e-commerce%20sites.&demo-url=https%3A%2F%2Fdemo.vercel.store&demo-image=https%3A%2F%2Fbigcommerce-demo-asset-ksvtgfvnd.vercel.app%2Fbigcommerce.png&integration-ids=oac_MuWZiE4jtmQ2ejZQaQ7ncuDT)", + "npm_package_devDependencies_deepmerge": "^4.2.2", + "npm_package_devDependencies_eslint_config_prettier": "^8.3.0", + "npm_package_devDependencies_graphql": "^15.5.1", + "npm_package_devDependencies_husky": "^6.0.0", + "npm_package_devDependencies_lint_staged": "^11.0.0", + "npm_package_devDependencies_postcss_flexbugs_fixes": "^5.0.2", + "npm_package_devDependencies_postcss_import": "^14.0.2", + "npm_package_devDependencies_postcss_preset_env": "^6.7.0", + "npm_package_devDependencies_prettier": "^2.3.0", + "npm_package_devDependencies_typescript": "4.3.4", + "npm_package_devDependencies__graphql_codegen_cli": "^1.21.5", + "npm_package_devDependencies__graphql_codegen_schema_ast": "^1.18.3", + "npm_package_devDependencies__graphql_codegen_typescript": "^1.22.2", + "npm_package_devDependencies__graphql_codegen_typescript_operations": "^1.18.1", + "npm_package_devDependencies__next_bundle_analyzer": "^10.2.3", + "npm_package_devDependencies__types_body_scroll_lock": "^2.6.1", + "npm_package_devDependencies__types_cookie": "^0.4.0", + "npm_package_devDependencies__types_js_cookie": "^2.2.6", + "npm_package_devDependencies__types_lodash_debounce": "^4.0.6", + "npm_package_devDependencies__types_lodash_random": "^3.2.6", + "npm_package_devDependencies__types_lodash_throttle": "^4.1.6", + "npm_package_devDependencies__types_node": "^15.12.4", + "npm_package_devDependencies__types_react": "^17.0.8", + "npm_package_engines_node": ">=14.x", + "npm_package_gitHead": "16ca52162bc58204b405a3732a141f014a9573e2", + "npm_package_license": "MIT", + "npm_package_lint_staged_______js_jsx_ts_tsx__0": "prettier --write", + "npm_package_lint_staged_______js_jsx_ts_tsx__1": "git add", + "npm_package_lint_staged_______md_mdx_json__0": "prettier --write", + "npm_package_lint_staged_______md_mdx_json__1": "git add", + "npm_package_name": "nextjs-commerce", + "npm_package_next_unused_alias__assets___0": "assets/*", + "npm_package_next_unused_alias__components___0": "components/*", + "npm_package_next_unused_alias__config___0": "config/*", + "npm_package_next_unused_alias__lib___0": "lib/*", + "npm_package_next_unused_alias__utils___0": "utils/*", + "npm_package_next_unused_debug": "true", + "npm_package_next_unused_entrypoints_0": "pages", + "npm_package_next_unused_include_0": "components", + "npm_package_next_unused_include_1": "lib", + "npm_package_next_unused_include_2": "pages", + "npm_package_readmeFilename": "README.md", + "npm_package_scripts_analyze": "BUNDLE_ANALYZE=both yarn build", + "npm_package_scripts_build": "next build", + "npm_package_scripts_dev": "NODE_OPTIONS='--inspect' PORT=3005 next dev", + "npm_package_scripts_dev_windows": "set NODE_OPTIONS='--inspect' && set PORT=3005 && next dev", + "npm_package_scripts_find_unused": "npx next-unused", + "npm_package_scripts_generate": "graphql-codegen", + "npm_package_scripts_generate_definitions": "node framework/bigcommerce/scripts/generate-definitions.js", + "npm_package_scripts_generate_shopify": "DOTENV_CONFIG_PATH=./.env.local graphql-codegen -r dotenv/config --config framework/shopify/codegen.json", + "npm_package_scripts_generate_vendure": "graphql-codegen --config framework/vendure/codegen.json", + "npm_package_scripts_prettier_fix": "prettier --write .", + "npm_package_scripts_start": "next start", + "npm_package_sideEffects": "false", + "npm_package_version": "1.0.0", + "NPM_PREFIX_NPM_CLI_JS": "C:\\Users\\nhan\\AppData\\Roaming\\npm\\node_modules\\npm\\bin\\npm-cli.js", + "NUMBER_OF_PROCESSORS": "4", + "OneDrive": "C:\\Users\\nhan\\OneDrive", + "OneDriveConsumer": "C:\\Users\\nhan\\OneDrive", + "OPENSSL_CONF": "C:\\Program Files\\PostgreSQL\\psqlODBC\\etc\\openssl.cnf", + "ORIGINAL_XDG_CURRENT_DESKTOP": "undefined", + "OS": "Windows_NT", + "Path": "C:\\Program Files\\nodejs\\node_modules\\npm\\node_modules\\npm-lifecycle\\node-gyp-bin;G:\\hoc-fpt-2\\làm việc\\kie\\work\\grocery-vercel-commerce\\node_modules\\.bin;C:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\Java\\jdk1.8.0_231\\bin;C:\\Program Files\\nodejs\\;C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin;C:\\Program Files\\Git\\cmd;C:\\Program Files\\MongoDB\\Server\\4.2\\bin;;C:\\Program Files\\Git LFS;D:\\hoc-fpt\\code-tren-lop\\php\\xampp3\\php;C:\\ProgramData\\ComposerSetup\\bin;C:\\ProgramData\\chocolatey\\bin;C:\\Program Files\\AdoptOpenJDK\\jdk8u192-b12\\bin;C:\\Program Files\\Java\\jdk1.8.0_211\\bin;C:\\Android\\android-sdk\\tools;C:\\Android\\android-sdk\\platform-tools;C:\\Android\\android-sdk\\tools\\bin;C:\\Program Files\\MySQL\\MySQL Shell 8.0\\bin\\;C:\\Program Files\\Java\\jdk1.8.0_231\\bin;C:\\Users\\nhan\\AppData\\Local\\Programs\\Microsoft VS Code\\bin;C:\\Users\\nhan\\AppData\\Roaming\\npm;C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin;C:\\Program Files\\heroku\\bin;C:\\Users\\nhan\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Users\\nhan\\AppData\\Roaming\\Composer\\vendor\\bin", + "PATHEXT": ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JSE;.WSF;.WSH;.MSC;.CPL", + "PORT": "3005 ", + "PROCESSOR_ARCHITECTURE": "AMD64", + "PROCESSOR_IDENTIFIER": "Intel64 Family 6 Model 58 Stepping 9, GenuineIntel", + "PROCESSOR_LEVEL": "6", + "PROCESSOR_REVISION": "3a09", + "ProgramData": "C:\\ProgramData", + "ProgramFiles": "C:\\Program Files", + "ProgramFiles(x86)": "C:\\Program Files (x86)", + "ProgramW6432": "C:\\Program Files", + "PROMPT": "$P$G", + "PSModulePath": "C:\\Users\\nhan\\Documents\\WindowsPowerShell\\Modules;C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules", + "PUBLIC": "C:\\Users\\Public", + "SESSIONNAME": "Console", + "SystemDrive": "C:", + "SystemRoot": "C:\\WINDOWS", + "TEMP": "C:\\Users\\nhan\\AppData\\Local\\Temp", + "TERM_PROGRAM": "vscode", + "TERM_PROGRAM_VERSION": "1.60.0", + "TMP": "C:\\Users\\nhan\\AppData\\Local\\Temp", + "TRACE_ID": "69c5adcb5945384d", + "USERDOMAIN": "DESKTOP-TILU55O", + "USERDOMAIN_ROAMINGPROFILE": "DESKTOP-TILU55O", + "USERNAME": "nhan", + "USERPROFILE": "C:\\Users\\nhan", + "VSCODE_GIT_ASKPASS_MAIN": "c:\\Users\\nhan\\AppData\\Local\\Programs\\Microsoft VS Code\\resources\\app\\extensions\\git\\dist\\askpass-main.js", + "VSCODE_GIT_ASKPASS_NODE": "C:\\Users\\nhan\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe", + "VSCODE_GIT_IPC_HANDLE": "\\\\.\\pipe\\vscode-git-d5d8071aa9-sock", + "windir": "C:\\WINDOWS", + "_prog": "node", + "__NEXT_PROCESSED_ENV": "true" + }, + "sharedObjects": [ + "C:\\Program Files\\nodejs\\node.exe", + "C:\\WINDOWS\\SYSTEM32\\ntdll.dll", + "C:\\WINDOWS\\System32\\KERNEL32.DLL", + "C:\\WINDOWS\\System32\\KERNELBASE.dll", + "C:\\WINDOWS\\System32\\WS2_32.dll", + "C:\\WINDOWS\\System32\\RPCRT4.dll", + "C:\\WINDOWS\\System32\\ADVAPI32.dll", + "C:\\WINDOWS\\System32\\msvcrt.dll", + "C:\\WINDOWS\\System32\\sechost.dll", + "C:\\WINDOWS\\System32\\USER32.dll", + "C:\\WINDOWS\\System32\\win32u.dll", + "C:\\WINDOWS\\System32\\GDI32.dll", + "C:\\WINDOWS\\System32\\gdi32full.dll", + "C:\\WINDOWS\\System32\\msvcp_win.dll", + "C:\\WINDOWS\\System32\\ucrtbase.dll", + "C:\\WINDOWS\\System32\\PSAPI.DLL", + "C:\\WINDOWS\\System32\\CRYPT32.dll", + "C:\\WINDOWS\\System32\\bcrypt.dll", + "C:\\WINDOWS\\SYSTEM32\\dbghelp.dll", + "C:\\WINDOWS\\SYSTEM32\\IPHLPAPI.DLL", + "C:\\WINDOWS\\SYSTEM32\\USERENV.dll", + "C:\\WINDOWS\\SYSTEM32\\WINMM.dll", + "C:\\WINDOWS\\System32\\IMM32.DLL", + "C:\\WINDOWS\\SYSTEM32\\powrprof.dll", + "C:\\WINDOWS\\SYSTEM32\\UMPDC.dll", + "C:\\WINDOWS\\SYSTEM32\\CRYPTBASE.DLL", + "C:\\WINDOWS\\system32\\uxtheme.dll", + "C:\\WINDOWS\\System32\\combase.dll", + "C:\\WINDOWS\\system32\\mswsock.dll", + "C:\\WINDOWS\\SYSTEM32\\kernel.appcore.dll", + "C:\\WINDOWS\\System32\\bcryptprimitives.dll", + "C:\\WINDOWS\\System32\\NSI.dll", + "C:\\WINDOWS\\SYSTEM32\\dhcpcsvc6.DLL", + "C:\\WINDOWS\\SYSTEM32\\dhcpcsvc.DLL", + "C:\\WINDOWS\\SYSTEM32\\DNSAPI.dll", + "C:\\WINDOWS\\system32\\napinsp.dll", + "C:\\WINDOWS\\system32\\pnrpnsp.dll", + "C:\\WINDOWS\\system32\\wshbth.dll", + "C:\\WINDOWS\\system32\\NLAapi.dll", + "C:\\WINDOWS\\System32\\winrnr.dll", + "C:\\Windows\\System32\\rasadhlp.dll", + "C:\\WINDOWS\\System32\\fwpuclnt.dll" + ] +} \ No newline at end of file diff --git a/src/components/common/Author/Author.module.scss b/src/components/common/Author/Author.module.scss index 0459a9fbb..8d903546f 100644 --- a/src/components/common/Author/Author.module.scss +++ b/src/components/common/Author/Author.module.scss @@ -1,3 +1,4 @@ +@import '../../../styles/utilities'; .authorWarper{ @apply flex flex-row items-center; diff --git a/src/components/common/Author/Author.tsx b/src/components/common/Author/Author.tsx index bbb389fbd..1cf8e52af 100644 --- a/src/components/common/Author/Author.tsx +++ b/src/components/common/Author/Author.tsx @@ -2,9 +2,8 @@ import React from 'react'; import s from './Author.module.scss'; import classNames from 'classnames'; -import Image from "next/image"; interface Props { - image:any, + image:string, name: string } @@ -12,7 +11,7 @@ const Author = ({image,name}:Props) =>{ return (
- +
{name}
) diff --git a/src/components/common/CardBlog/CardBlog.module.scss b/src/components/common/CardBlog/CardBlog.module.scss index 8f18e5753..f0dc00b3a 100644 --- a/src/components/common/CardBlog/CardBlog.module.scss +++ b/src/components/common/CardBlog/CardBlog.module.scss @@ -1,29 +1,29 @@ @import "../../../styles/utilities"; -.cardBlogWarpper{ +.cardBlogWarpper { + @apply inline-flex flex-col justify-start; max-width: 39.2rem; min-height: 34.4rem; - @apply inline-flex flex-col justify-start; - .image{ + .image { width: 100%; max-height: 22rem; border-radius: 2.4rem; - &:hover{ + &:hover { cursor: pointer; } } - .title{ + .title { padding: 1.6rem 0.8rem 0.4rem 0.8rem; @apply font-bold; font-size: 2rem; line-height: 2.8rem; letter-spacing: -0.01em; color: var(--text-active); - &:hover{ + &:hover { cursor: pointer; } } - .description{ + .description { padding: 0 0.8rem; @apply overflow-hidden overflow-ellipsis ; color: var(--text-label); diff --git a/src/components/common/CardBlog/CardBlog.tsx b/src/components/common/CardBlog/CardBlog.tsx index 17a796bc4..314a6a1fd 100644 --- a/src/components/common/CardBlog/CardBlog.tsx +++ b/src/components/common/CardBlog/CardBlog.tsx @@ -1,21 +1,27 @@ import Link from 'next/link' import React from 'react' -import { RecipeProps } from 'src/utils/types.utils' +import { ROUTE } from 'src/utils/constanst.utils' +import { BlogProps } from 'src/utils/types.utils' import s from './CardBlog.module.scss' -export interface BlogCardProps extends RecipeProps { - link: string, +export interface BlogCardProps extends BlogProps { + // todo: edit when intergrate API + } -const CardBlog = ({ imageSrc, title, description, link }: BlogCardProps) => { +const CardBlog = ({ imageSrc, title, description, slug }: BlogCardProps) => { return (
- -
- image cardblog -
+ + +
+ image cardblog +
+
- -
{title}
+ + +
{title}
+
{description}
diff --git a/src/components/common/CollapseCommon/CollapseCommon.module.scss b/src/components/common/CollapseCommon/CollapseChild/CollapseChild.module.scss similarity index 68% rename from src/components/common/CollapseCommon/CollapseCommon.module.scss rename to src/components/common/CollapseCommon/CollapseChild/CollapseChild.module.scss index 4686a886a..e6a71e44e 100644 --- a/src/components/common/CollapseCommon/CollapseCommon.module.scss +++ b/src/components/common/CollapseCommon/CollapseChild/CollapseChild.module.scss @@ -1,18 +1,19 @@ -@import "../../../styles/utilities"; +@import "../../../../styles/utilities"; -.collapseWrapper{ +.collapseWrapper { @apply border-t border-b; border-color: var(--border-line); max-width: 80.4rem; min-height: 4rem; - &.isActive{ - .title{ + &.isActive { + .title { @apply pb-0; } - .contentContainer{ + .contentContainer { @apply block; + animation: ContentAnimationIn 0.5s ease-out; } - .toggle{ + .toggle { &:before { transform: rotate(180deg); } @@ -21,21 +22,21 @@ } } } - svg:hover{ + &:hover { cursor: pointer; } } -.title{ +.title { @apply outline-none flex justify-between font-heading items-center pt-16 pb-16; font-size: 3.2rem; line-height: 4rem; letter-spacing: -0.01em; - .toggle{ + .toggle { height: 2.2rem; width: 2.2rem; position: relative; &:before, - &:after{ + &:after { @apply absolute h-2; content: ""; border-radius: 0.8rem; @@ -44,12 +45,22 @@ width: 2.2rem; transition: transform 500ms ease; } - &:before{ + &:before { transform-origin: center; transform: rotate(90deg); } } } -.contentContainer{ +.contentContainer { @apply hidden pb-16; } +@keyframes ContentAnimationIn { + 0% { + opacity: 0; + transform: translateY(-1.6rem); + } + 100% { + opacity: 1; + transform: none; + } +} \ No newline at end of file diff --git a/src/components/common/CollapseCommon/CollapseChild/CollapseChild.tsx b/src/components/common/CollapseCommon/CollapseChild/CollapseChild.tsx new file mode 100644 index 000000000..53cd70cf3 --- /dev/null +++ b/src/components/common/CollapseCommon/CollapseChild/CollapseChild.tsx @@ -0,0 +1,37 @@ +import s from './CollapseChild.module.scss' +import { useState } from 'react' +import classNames from 'classnames' +import CollapseContent from './CollapseContent/CollapseContent' + +interface CollapseProps{ + title?: string, + content: Array, + isToggle?: boolean, +} +const CollapseChild = ({title, content, isToggle=false}: CollapseProps) => { + const [isActive, changeActive] = useState(isToggle) + + const handleToggle = () => { + changeActive(!isActive) + } + return( +
+
+

{title}

+
+
+
+ { + content.map(item => ) + } +
+
+ ) +} + +export default CollapseChild \ No newline at end of file diff --git a/src/components/common/CollapseCommon/CollapseContent/CollapseContent.module.scss b/src/components/common/CollapseCommon/CollapseChild/CollapseContent/CollapseContent.module.scss similarity index 66% rename from src/components/common/CollapseCommon/CollapseContent/CollapseContent.module.scss rename to src/components/common/CollapseCommon/CollapseChild/CollapseContent/CollapseContent.module.scss index 2d29c4b51..9e5cfba30 100644 --- a/src/components/common/CollapseCommon/CollapseContent/CollapseContent.module.scss +++ b/src/components/common/CollapseCommon/CollapseChild/CollapseContent/CollapseContent.module.scss @@ -1,3 +1,3 @@ -.content{ +.content { margin-top: 1.6rem; } \ No newline at end of file diff --git a/src/components/common/CollapseCommon/CollapseContent/CollapseContent.tsx b/src/components/common/CollapseCommon/CollapseChild/CollapseContent/CollapseContent.tsx similarity index 79% rename from src/components/common/CollapseCommon/CollapseContent/CollapseContent.tsx rename to src/components/common/CollapseCommon/CollapseChild/CollapseContent/CollapseContent.tsx index 44a5624f3..e18e19c0a 100644 --- a/src/components/common/CollapseCommon/CollapseContent/CollapseContent.tsx +++ b/src/components/common/CollapseCommon/CollapseChild/CollapseContent/CollapseContent.tsx @@ -1,4 +1,3 @@ -import classNames from 'classnames' import s from './CollapseContent.module.scss' interface CollapseContentProps{ diff --git a/src/components/common/CollapseCommon/CollapseCommon.tsx b/src/components/common/CollapseCommon/CollapseCommon.tsx index 1fdce09da..e695a6576 100644 --- a/src/components/common/CollapseCommon/CollapseCommon.tsx +++ b/src/components/common/CollapseCommon/CollapseCommon.tsx @@ -1,37 +1,19 @@ -import s from './CollapseCommon.module.scss' -import { useState } from 'react' -import classNames from 'classnames' -import CollapseContent from './CollapseContent/CollapseContent' +import CollapseChild from './CollapseChild/CollapseChild' -interface CollapseProps{ - title?: string, - content: Array, - isToggle?: boolean, +interface CollapseCommonProps{ + data: {title: string, content: Array}[], } -const CollapseCommon = ({title, content, isToggle}: CollapseProps) => { - const [isActive, changeActive] = useState(isToggle) - const handleToggle = () => { - changeActive(!isActive) - } - return( -
-
- {title} -
-
-
- { - content.map(item => ) - } -
-
+const CollapseCommon = ({data}: CollapseCommonProps) => { + return ( +
+ { + data.map(item => + + ) + } +
) } -export default CollapseCommon \ No newline at end of file +export default CollapseCommon diff --git a/src/components/common/DrawerCommon/DrawerCommon.module.scss b/src/components/common/DrawerCommon/DrawerCommon.module.scss index 3253eac50..d118d45e8 100644 --- a/src/components/common/DrawerCommon/DrawerCommon.module.scss +++ b/src/components/common/DrawerCommon/DrawerCommon.module.scss @@ -17,7 +17,7 @@ width: 100%; margin-right: 0; @screen md { - max-width: 55rem; + max-width: 52rem; } .top { @apply flex justify-between items-center; diff --git a/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss b/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss index 2832211c1..eaaabca70 100644 --- a/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss +++ b/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss @@ -42,7 +42,7 @@ @apply hidden; @screen md { @apply flex items-center list-none; - li { + > li { @apply flex justify-center items-center w-full; &:not(:last-child) { margin-right: 4.8rem; @@ -53,7 +53,7 @@ a { @appy no-underline; &:hover { - opacity: .8; + opacity: 0.8; } &.iconFavourite { svg path { @@ -61,7 +61,14 @@ } } } - + .btnCart { + &:hover { + svg path { + fill: var(--primary); + opacity: 0.8; + } + } + } } } } diff --git a/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx b/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx index aa962605d..05e0b38fa 100644 --- a/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx +++ b/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx @@ -68,7 +68,7 @@ const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo }: Props) => {
  • -
  • diff --git a/src/components/common/Layout/Layout.tsx b/src/components/common/Layout/Layout.tsx index c510e4e14..17f520185 100644 --- a/src/components/common/Layout/Layout.tsx +++ b/src/components/common/Layout/Layout.tsx @@ -27,7 +27,7 @@ const Layout: FC = ({ children }) => { return (
    - {/*
    */} +
    {children}
    li { @apply block w-full transition-all duration-200 cursor-pointer text-active; - word-wrap: break-word; - -webkit-hyphens: auto; - -ms-hyphens: auto; - -moz-hyphens: auto; - hyphens: auto; - overflow-x: hidden; - position: relative; - max-width: 15rem; white-space: nowrap; - text-overflow: ellipsis; button { all: unset; color: currentColor; diff --git a/src/components/common/MenuFilter/MenuFilter.module.scss b/src/components/common/MenuFilter/MenuFilter.module.scss new file mode 100644 index 000000000..ecea2e119 --- /dev/null +++ b/src/components/common/MenuFilter/MenuFilter.module.scss @@ -0,0 +1,40 @@ +@import "../../../styles/utilities"; +.menuFilterWrapper{ + + @screen md { + @apply hidden; + } + .menuFilterHeading{ + @apply sub-headline font-bold ; + color: var(--text-active); + font-feature-settings: 'salt' on; + margin: 0.8rem 0; + } + .menuFilterList{ + @apply flex flex-wrap justify-start relative; + margin-bottom: 3rem; + box-sizing: border-box; + &::after{ + @apply absolute; + top: 110%; + content: ""; + width: 100%; + border-bottom: 1px solid var(--border-line); + } + + li{ + margin: 1rem 0; + padding:0; + div{ + padding: 0.8rem 1.6rem; + margin-right: 0.8rem; + background-color: var(--gray); + border-radius: 0.8rem; + &.active { + color:white; + background-color: var(--primary); + } + } + } + } +} diff --git a/src/components/common/MenuFilter/MenuFilter.tsx b/src/components/common/MenuFilter/MenuFilter.tsx new file mode 100644 index 000000000..454942734 --- /dev/null +++ b/src/components/common/MenuFilter/MenuFilter.tsx @@ -0,0 +1,48 @@ +import classNames from 'classnames' +import { useEffect, useState } from 'react'; + +import s from './MenuFilter.module.scss' +interface Props { + children?: any, + heading?:string, + categories:{name:string,link:string}[], + type:string, + onChangeValue?: (value: Object) => void +} + +const MenuFilter = ({heading,categories,type,onChangeValue}:Props)=> { + const [active, setActive] = useState(''); + + function handleClick(link:string){ + setActive(link); + + if(active === link){ + setActive(''); + } + } + + useEffect(()=>{ + + let href = active?.split("="); + const linkValue = href[1]; + + onChangeValue && onChangeValue({[type]:linkValue}); + },[active]) + + return ( +
    +

    {heading}

    +
      + { + categories.map(item =>
    • +
      handleClick(item.link)} className={classNames({ [s.active]: item.link === active? true: false })}> + {item.name} +
      +
    • ) + } +
    +
    + ) +} + +export default MenuFilter diff --git a/src/components/common/MenuNavigation/MenuNavigation.module.scss b/src/components/common/MenuNavigation/MenuNavigation.module.scss new file mode 100644 index 000000000..7535df707 --- /dev/null +++ b/src/components/common/MenuNavigation/MenuNavigation.module.scss @@ -0,0 +1,29 @@ +@import "../../../styles/utilities"; +.menuNavigationWrapper{ + .menuNavigationHeading{ + @screen md { + @apply sub-headline font-bold ; + color: var(--text-active); + font-feature-settings: 'salt' on; + margin: 1.6rem 0; + } + } + .menuNavigationList{ + @screen md { + li{ + margin: 0.8rem 0; + a{ + display:block; + width:100%; + color:var(--text-base); + &:hover { + @apply text-primary; + } + &.active { + @apply text-primary; + } + } + } + } + } +} diff --git a/src/components/common/MenuNavigation/MenuNavigation.tsx b/src/components/common/MenuNavigation/MenuNavigation.tsx new file mode 100644 index 000000000..4a8943051 --- /dev/null +++ b/src/components/common/MenuNavigation/MenuNavigation.tsx @@ -0,0 +1,34 @@ +import classNames from 'classnames' +import Link from 'next/link' +import { useRouter } from 'next/router' +import s from './MenuNavigation.module.scss' + +interface Props { + children?: any, + heading:string, + categories:{name:string,link:string}[] +} + +const MenuNavigation = ({heading,categories}:Props)=> { + const router = useRouter() + + return ( +
    +

    {heading}({categories.length})

    + +
    + ) +} + +export default MenuNavigation diff --git a/src/components/common/MenuNavigationProductList/MenuNavigationProductList.module.scss b/src/components/common/MenuNavigationProductList/MenuNavigationProductList.module.scss new file mode 100644 index 000000000..aa3f5e6c3 --- /dev/null +++ b/src/components/common/MenuNavigationProductList/MenuNavigationProductList.module.scss @@ -0,0 +1,45 @@ +@import "../../../styles/utilities"; +.menuNavigationProductListDesktop{ + @screen sm-only { + @apply hidden; + } +} +.menuNavigationProductListMobile{ + @apply hidden; + &.isShow{ + @apply block; + @screen md { + @apply hidden; + } + } + .menuNavigationProductModal{ + background: rgba(0, 0, 0, 0.5); + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; + z-index: 10000; + .content{ + @apply spacing-horizontal; + margin-top: 3rem; + padding-top: 2rem ; + padding-bottom: 5rem; + background-color: white; + overflow: auto; + height: 100%; + border-radius: 2.4rem 2.4rem 0 0; + .head{ + @apply flex justify-between; + h3{ + @apply heading-3 font-bold; + color:var(--text-base); + } + } + button{ + margin-top: 2rem; + width: 100%; + } + } + } +} \ No newline at end of file diff --git a/src/components/common/MenuNavigationProductList/MenuNavigationProductList.tsx b/src/components/common/MenuNavigationProductList/MenuNavigationProductList.tsx new file mode 100644 index 000000000..d9ac2aa26 --- /dev/null +++ b/src/components/common/MenuNavigationProductList/MenuNavigationProductList.tsx @@ -0,0 +1,60 @@ +import React, { useState } from 'react'; +import {ButtonCommon} from 'src/components/common'; +import s from './MenuNavigationProductList.module.scss'; +import MenuSort from './MenuSort/MenuSort'; +import {LANGUAGE} from 'src/utils/language.utils'; +import classNames from 'classnames' +import MenuFilter from '../MenuFilter/MenuFilter'; +import MenuNavigation from '../MenuNavigation/MenuNavigation'; +import IconHide from 'src/components/icons/IconHide'; + +interface Props{ + categories:{name:string,link:string}[], + brands:{name:string,link:string}[], + featured:{name:string,link:string}[], +} + +const MenuNavigationProductList = ({categories,brands,featured}:Props)=>{ + + const [dataSort,setDataSort] = useState({}); + const [isShow,setIsShow] = useState(true); + + function handleValue(value:Object){ + setDataSort({...dataSort,...value}); + } + function filter(){ + console.log(dataSort) + } + + function hideMenu(){ + if(isShow === true){ + setIsShow(false); + } + } + return( + <> +
    + + + +
    +
    +
    +
    +
    +

    FILTER

    +
    +
    + + + + + {LANGUAGE.BUTTON_LABEL.CONFIRM} +
    +
    +
    + + ) +} + +export default MenuNavigationProductList \ No newline at end of file diff --git a/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.module.scss b/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.module.scss new file mode 100644 index 000000000..a25752901 --- /dev/null +++ b/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.module.scss @@ -0,0 +1,46 @@ +@import "../../../../styles/utilities"; +.menuSortWrapper{ + + @screen md { + @apply hidden; + } + .menuSortHeading{ + @apply sub-headline font-bold ; + color: var(--text-active); + font-feature-settings: 'salt' on; + margin: 0.8rem 0; + } + .menuSortList{ + box-sizing: border-box; + &::after{ + @apply absolute; + top: 110%; + content: ""; + width: 100%; + border-bottom: 1px solid var(--border-line); + } + li{ + div{ + height: 4.8rem; + line-height: 4.8rem; + padding: 0 1.6rem; + margin-right: 0.8rem; + border-radius: 0.8rem; + &.active { + @apply font-bold relative; + color:var(--text-active); + background-color: var(--primary-lightest); + &::after{ + @apply absolute; + content:""; + background-image: url('/assets/svg/check.svg'); + right: 1.6rem; + top: calc(50% - 24px/2); + width: 2.4rem; + height: 2.4rem; + } + } + } + } + } +} diff --git a/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.tsx b/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.tsx new file mode 100644 index 000000000..2e66dfc83 --- /dev/null +++ b/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.tsx @@ -0,0 +1,67 @@ +import classNames from 'classnames'; +import { useEffect, useState } from 'react'; +import { QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'; +import s from './MenuSort.module.scss'; + +interface Props { + children?: any, + heading:string, + type:string, + onChangeValue?: (value: Object) => void +} +const SORT = [ + { + name: 'By Name', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.SORTBY}=by-name`, + }, + { + name: 'Price(High to Low)', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.SORTBY}=high-to-low`, + }, + { + name: 'Price (Low to High)', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.SORTBY}=low-to-high`, + }, + { + name: 'On Sale', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.SORTBY}=on-sale`, + }, + ]; + + +const MenuSort = ({heading,type,onChangeValue}:Props)=> { + const [active, setActive] = useState(''); + + function handleClick(link:string){ + setActive(link); + + if(active === link){ + setActive(''); + } + } + + useEffect(()=>{ + + let href = active?.split("="); + const linkValue = href[1]; + + onChangeValue && onChangeValue({[type]:linkValue}); + },[active]) + + return ( +
    +

    {heading}

    +
      + { + SORT.map(item =>
    • +
      handleClick(item.link)} className={classNames({ [s.active]: item.link === active? true: false })}> + {item.name} +
      +
    • ) + } +
    +
    + ) +} + +export default MenuSort diff --git a/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx b/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx index bedb993f4..b1059a441 100644 --- a/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx +++ b/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx @@ -1,7 +1,6 @@ import Link from 'next/link' import React, { useEffect, useRef } from 'react' -import { ButtonCommon, Inputcommon } from 'src/components/common' -import InputPassword from 'src/components/common/InputPassword/InputPassword' +import { ButtonCommon, Inputcommon, InputPassword } from 'src/components/common' import { ROUTE } from 'src/utils/constanst.utils' import { CustomInputCommon } from 'src/utils/type.utils' import s from '../FormAuthen.module.scss' diff --git a/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx b/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx index d03dbc39e..66ec1f8a4 100644 --- a/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx +++ b/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef } from 'react' -import { ButtonCommon, Inputcommon } from 'src/components/common' +import { ButtonCommon, Inputcommon, InputPassword } from 'src/components/common' import s from '../FormAuthen.module.scss' import styles from './FormRegister.module.scss' import SocialAuthen from '../SocialAuthen/SocialAuthen' diff --git a/src/components/common/PaginationCommon/PaginationCommon.tsx b/src/components/common/PaginationCommon/PaginationCommon.tsx index d0df5efe7..aed2473f3 100644 --- a/src/components/common/PaginationCommon/PaginationCommon.tsx +++ b/src/components/common/PaginationCommon/PaginationCommon.tsx @@ -1,18 +1,19 @@ import classNames from 'classnames' import React, { useEffect, useState } from 'react' import { ArrowLeftSmall, ArrowRightSmall } from 'src/components/icons' +import { DEFAULT_PAGE_SIZE } from 'src/utils/constanst.utils' import PaginationItem from './components/PaginationItem' import s from './PaginationCommon.module.scss' interface PaginationCommonProps { defaultCurrent?: number - pageSize: number + pageSize?: number total: number onChange?: (page: number, pageSize: number) => void } const PaginationCommon = ({ total, - pageSize, + pageSize=DEFAULT_PAGE_SIZE, defaultCurrent, onChange, }: PaginationCommonProps) => { @@ -54,14 +55,14 @@ const PaginationCommon = ({ ) })}
    = pageNum - 1, + [s.disable]: currentPage >= pageNum - 1, })} onClick={onNextClick} > diff --git a/src/components/common/RelevantBlogPosts/RelevantBlogPosts.module.scss b/src/components/common/RelevantBlogPosts/RelevantBlogPosts.module.scss index d5a13299d..ed232830f 100644 --- a/src/components/common/RelevantBlogPosts/RelevantBlogPosts.module.scss +++ b/src/components/common/RelevantBlogPosts/RelevantBlogPosts.module.scss @@ -1,6 +1,9 @@ @import '../../../styles/utilities'; .blogPostWarpper { + &.cream{ + background-color: #F5F4F2; + } padding-top: 5.6rem; padding-bottom: 5.2rem; @apply flex flex-col; diff --git a/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx b/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx index 01e19bb25..1d71a6ca1 100644 --- a/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx +++ b/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx @@ -1,6 +1,7 @@ import image15 from '../../../../public/assets/images/image15.png' import image16 from '../../../../public/assets/images/image16.png' import image17 from '../../../../public/assets/images/image17.png' +import classNames from 'classnames' import React from 'react' import { HeadingCommon, ViewAllItem } from 'src/components/common' import { BlogCardProps } from 'src/components/common/CardBlog/CardBlog' @@ -9,54 +10,59 @@ import s from './RelevantBlogPosts.module.scss' import { ROUTE } from 'src/utils/constanst.utils'; interface RelevantProps { - data?: BlogCardProps[] - itemKey?: string - title?: string - viewAllLink?: string + data?: BlogCardProps[], + itemKey?: string, + title?: string, + viewAllLink?: string, + bgcolor?: "default" | "cream" } const recipe:BlogCardProps[] = [ { title: "Want to Lose Weight? Here are 10 DEBM Diet Guidelines for Beginners", + slug: 'have-a-nice-lunch', description:"The DEBM diet stands for "+'"Delicious Happy Fun Diet"'+". This diet was popularized by Robert...", imageSrc: image15.src, - link: `${ROUTE.BLOG_DETAIL}` },{ title: "9 Ways to Make an Aloe Vera Mask at Home", + slug: 'have-a-nice-lunch', description:"Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...", imageSrc: image16.src, - link: `${ROUTE.BLOG_DETAIL}` },{ title: "Don't Buy Wrong, Here Are 7 Ways to Choose a Ripe Dragon Fruit", + slug: 'have-a-nice-lunch', description:"Dragon fruit is a type of fruit that is a favorite for many people because of its delicious and fresh...", imageSrc: image17.src, - link: `${ROUTE.BLOG_DETAIL}` },{ title: "Want to Lose Weight? Here are 10 DEBM Diet Guidelines for Beginners", + slug: 'have-a-nice-lunch', description:"The DEBM diet stands for "+'"Delicious Happy Fun Diet"'+". This diet was popularized by Robert...", imageSrc: image15.src, - link: `${ROUTE.BLOG_DETAIL}` },{ title: "9 Ways to Make an Aloe Vera Mask at Home", + slug: 'have-a-nice-lunch', description:"Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...", imageSrc: image16.src, - link: `${ROUTE.BLOG_DETAIL}` },{ title: "Don't Buy Wrong, Here Are 7 Ways to Choose a Ripe Dragon Fruit", + slug: 'have-a-nice-lunch', description:"Dragon fruit is a type of fruit that is a favorite for many people because of its delicious and fresh...", imageSrc: image17.src, - link: `${ROUTE.BLOG_DETAIL}` }] - const RelevantBlogPosts = ({ data = recipe, itemKey="detail-relevant", title="Relevant Blog Posts" }: RelevantProps) => { + const RelevantBlogPosts = ({ data = recipe, itemKey="detail-relevant", title="Relevant Blog Posts", bgcolor = "default" }: RelevantProps) => { return ( -
    +
    {title}
    - +
    diff --git a/src/components/common/SelectCommon/SelectCommon.module.scss b/src/components/common/SelectCommon/SelectCommon.module.scss index d91b1831e..4809a46bb 100644 --- a/src/components/common/SelectCommon/SelectCommon.module.scss +++ b/src/components/common/SelectCommon/SelectCommon.module.scss @@ -1,69 +1,90 @@ @import "../../../styles/utilities"; -.select{ +.select { background-color: var(--white); - &.base{ + .selectTrigger { + svg { + @apply transition-all duration-200; + } + } + &.base { width: 20.6rem; - .selectTrigger{ + .selectTrigger { width: 20.6rem; padding: 1.2rem 1.6rem; } } - &.large{ + &.large { width: 34.25rem; - .selectTrigger{ + .selectTrigger { width: 34.25rem; padding: 1.6rem 1.6rem; } } - &.default{ - .selectTrigger{ + &.default { + .selectTrigger { @apply border-solid border border-current; - } + } } - &.custom{ - .selectTrigger{ + &.custom { + .selectTrigger { @apply border-2; border-color: var(--border-line); color: var(--text-label); } } - &.isActive{ - .selectOptionWrapper{ + &:hover { + cursor: pointer; + .hoverWrapper { @apply block; + animation: SelectAnimation 0.2s ease-out; + } + .selectTrigger { + svg { + transform: rotate(180deg); + } } } } -.selectTrigger{ +.selectTrigger { @apply outline-none flex justify-between; color: var(--text-active); border-radius: 0.8rem; - } -.selectOptionWrapper{ - @apply outline-none hidden z-10 absolute; - border-radius: 0.8rem; - background-color: var(--white); - padding: 0.4rem 0rem 0.4rem 0rem; - margin-top: 0.6rem; - &.base{ - width: 20.6rem; +.hoverWrapper { + @apply hidden outline-none absolute z-10; + padding-top: 0.6rem; + .selectOptionWrapper { + border-radius: 0.8rem; + background-color: var(--white); + padding: 0.4rem 0rem 0.4rem 0rem; + &.base { + width: 20.6rem; + } + &.large { + width: 34.25rem; + } + &.default { + @apply border-solid border border-current; + } + &.custom { + @apply border-2; + border-color: var(--border-line); + color: var(--text-label); + } } - &.large{ - width: 34.25rem; - } - &.default{ - @apply border-solid border border-current; - } - &.custom{ - @apply border-2; - border-color: var(--border-line); - color: var(--text-label); - } - &.active{ - @apply hidden; + &:hover { + @apply block; } } - - +@keyframes SelectAnimation { + 0% { + opacity: 0; + transform: translateY(1.6rem); + } + 100% { + opacity: 1; + transform: none; + } +} diff --git a/src/components/common/SelectCommon/SelectCommon.tsx b/src/components/common/SelectCommon/SelectCommon.tsx index 5bb3d15d6..9b8c88e24 100644 --- a/src/components/common/SelectCommon/SelectCommon.tsx +++ b/src/components/common/SelectCommon/SelectCommon.tsx @@ -1,43 +1,25 @@ import s from './SelectCommon.module.scss' import classNames from 'classnames' -import { useState, useRef, useEffect } from 'react' +import { useState } from 'react' import { IconVectorDown } from 'src/components/icons' import SelectOption from './SelectOption/SelectOption' interface Props { - children? : React.ReactNode, + placeholder? : string, size?: 'base' | 'large', type?: 'default' | 'custom', - option: {name: string}[], + option: {name: string, value: string}[], + onChange?: (value: string) => void, } -const SelectCommon = ({ type = 'default', size = 'base', option, children }: Props) => { - const [isActive, setActive] = useState(false) - const [selectedName, setSelectedName] = useState(children) - const ref = useRef(null) - - useEffect(() => { - const handleClick = (event: MouseEvent) => { - const { target } = event; - if (!ref?.current || ref?.current.contains(target as Node)) { - return - } - else{ - setActive(false) - } - } - document.addEventListener('click', handleClick) - return () => { - document.removeEventListener('click', handleClick) - } - }, [ref]) +const SelectCommon = ({ type = 'default', size = 'base', option, placeholder, onChange}: Props) => { + const [selectedName, setSelectedName] = useState(placeholder) + const [selectedValue, setSelectedValue] = useState('') - const changeActiveStatus = () => { - setActive(!isActive) - } - - const changeSelectedName = (item:string) => { + const changeSelectedName = (item:string, value: string) => { + setSelectedValue(value) setSelectedName(item) + onChange && onChange(value) } return( <> @@ -45,29 +27,29 @@ const SelectCommon = ({ type = 'default', size = 'base', option, children }: Pro [s.select] : true, [s[size]] : !!size, [s[type]] : !!type, - [s.isActive] : isActive, })} - onClick = { changeActiveStatus } - ref = {ref} >
    {selectedName}
    - -
    - { - option.map(item => - - ) - } + +
    +
    + { + option.map(item => + + ) + } +
    +
    ) diff --git a/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss b/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss index 5448f9879..ef504c112 100644 --- a/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss +++ b/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss @@ -13,5 +13,9 @@ } &:hover{ background-color: var(--gray); + color: var(--primary); + } + &.isChoose{ + background-color: var(--gray); } } \ No newline at end of file diff --git a/src/components/common/SelectCommon/SelectOption/SelectOption.tsx b/src/components/common/SelectCommon/SelectOption/SelectOption.tsx index 54877d5fe..7e1968f9e 100644 --- a/src/components/common/SelectCommon/SelectOption/SelectOption.tsx +++ b/src/components/common/SelectCommon/SelectOption/SelectOption.tsx @@ -2,20 +2,22 @@ import s from './SelectOption.module.scss' import classNames from 'classnames' interface Props{ - onClick: (value: string) => void, + onClick: (name: string, value: string) => void, itemName: string, size: 'base' | 'large', + value: string, + selected?: boolean, } -const SelectOption = ({onClick, itemName, size}: Props) => { - +const SelectOption = ({onClick, itemName, size, value, selected} : Props) => { const changeName = () => { - onClick(itemName) + onClick(itemName, value) } return(
    {itemName}
    diff --git a/src/components/icons/IconArrowUp.tsx b/src/components/icons/IconArrowUp.tsx index 3eac6391b..1f518d612 100644 --- a/src/components/icons/IconArrowUp.tsx +++ b/src/components/icons/IconArrowUp.tsx @@ -2,7 +2,7 @@ const ArrowUp = () => { return ( - + ) } diff --git a/src/components/icons/IconHide.tsx b/src/components/icons/IconHide.tsx new file mode 100644 index 000000000..a977aff84 --- /dev/null +++ b/src/components/icons/IconHide.tsx @@ -0,0 +1,12 @@ +import React from 'react' + +const IconHide = () => { + return ( + + + + + ) +} + +export default IconHide diff --git a/src/components/icons/IconVectorDown.tsx b/src/components/icons/IconVectorDown.tsx index 019fc2806..0bb1cb8c1 100644 --- a/src/components/icons/IconVectorDown.tsx +++ b/src/components/icons/IconVectorDown.tsx @@ -1,5 +1,3 @@ - - const IconVectorDown = ({ ...props }) => { return ( { + return ( + <> +
    + +

    The Best Sesame Soy Broccoli Salad

    +
    + +
    +
    + +

    When you’re trying to eat healthier but want something more substantial than a leafy green salad, broccoli salad is there for you. I love the crunch and heft of broccoli, especially when it’s cut up into bite size spoonable pieces. +
    +
    + + Some people aren’t into raw broccoli, but I love it! I always go for the raw broccoli on those vegetable platters that seem to be at every potluck/party you go to. +
    +
    + This is a simple broccoli salad: you have the bulk of it, raw broccoli; crunchy red onions for a bit of acidity and raw crunch, craisins for sweetness, almonds for a nutty counter point; and a sweet and tangy soy-rice vinegar-sesame dressing. +

    + +
    +
    + +

    What is broccoli salad

    +
    +

    When you’re trying to eat healthier but want something more substantial than a leafy green salad, broccoli salad is there for you. I love the crunch and heft of broccoli, especially when it’s cut up into bite size spoonable pieces. +
    +
    + + Some people aren’t into raw broccoli, but I love it! I always go for the raw broccoli on those vegetable platters that seem to be at every potluck/party you go to. +
    +
    + This is a simple broccoli salad: you have the bulk of it, raw broccoli; crunchy red onions for a bit of acidity and raw crunch, craisins for sweetness, almonds for a nutty counter point; and a sweet and tangy soy-rice vinegar-sesame dressing. +

    + +
    +
    + +

    What about broccoli stems?

    +
    +

    + You can eat broccoli stems. In fact, they are delicious. Just use a peeler to peel off the outsides and then trim the stalks into small 1/4”-1/2” cubes. +

    +
    + blog-detail + +
    + +
    +
    + Share to: +
    +
    + +
    +
    +
    + + + ) +} + +export default BlogContent diff --git a/src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg.module.scss b/src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg.module.scss new file mode 100644 index 000000000..98206b439 --- /dev/null +++ b/src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg.module.scss @@ -0,0 +1,21 @@ +.beadcrumb{ + padding-left: 3.2rem; + padding-bottom: 3.2rem; +} +.image{ + width: 100%; + padding: 0 2rem; + margin-bottom: 2rem; + border-radius: 2.4rem; + @screen md { + width: 90%; + margin:0 auto; + margin-bottom: 4rem; + } + @screen xl{ + width: 63%; + margin:0 auto; + margin-bottom: 4rem; + } + +} \ No newline at end of file diff --git a/src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg.tsx b/src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg.tsx new file mode 100644 index 000000000..b7eb6aaef --- /dev/null +++ b/src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg.tsx @@ -0,0 +1,27 @@ + +import React from 'react'; +import BreadcrumbCommon from 'src/components/common/BreadcrumbCommon/BreadcrumbCommon'; +import s from './BlogDetailImg.module.scss'; +interface Props { + className?: string + children?: any +} + +const CRUMBS =[ + { + name:"Blog", + link:"/blog" + } +] +const BlogDetailImg = ({}:Props ) => { + return ( + <> +
    + +
    + Ảnh đại diện + + ) +} + +export default BlogDetailImg diff --git a/src/components/modules/blog-detail/BlogDetailImg/img/blogdetail.png b/src/components/modules/blog-detail/BlogDetailImg/img/blogdetail.png new file mode 100644 index 000000000..ad200ac46 Binary files /dev/null and b/src/components/modules/blog-detail/BlogDetailImg/img/blogdetail.png differ diff --git a/src/components/modules/blog-detail/index.ts b/src/components/modules/blog-detail/index.ts new file mode 100644 index 000000000..45d532145 --- /dev/null +++ b/src/components/modules/blog-detail/index.ts @@ -0,0 +1,2 @@ +export { default as BlogContent } from './BlogContent/BlogContent'; +export { default as BlogDetailImg } from './BlogDetailImg/BlogDetailImg'; \ No newline at end of file diff --git a/src/components/modules/home/HomeBanner/HomeBanner.module.scss b/src/components/modules/home/HomeBanner/HomeBanner.module.scss index 507558cad..fdba411c0 100644 --- a/src/components/modules/home/HomeBanner/HomeBanner.module.scss +++ b/src/components/modules/home/HomeBanner/HomeBanner.module.scss @@ -11,11 +11,19 @@ @apply grid; grid-template-columns: 1fr 1.8fr; .left { - @apply flex items-end justify-center custom-border-radius-lg; + @apply relative flex items-end justify-center custom-border-radius-lg; margin-right: 1.6rem; - background-image: url('./assets/home_banner.png'); - background-repeat: no-repeat; - background-size: cover; + .imgWrap { + @apply absolute w-full h-full; + top: 0; + left: 0; + > div { + @apply w-full h-full custom-border-radius-lg; + } + img { + object-fit: cover; + } + } .text { @apply relative font-heading text-center; diff --git a/src/components/modules/home/HomeBanner/HomeBanner.tsx b/src/components/modules/home/HomeBanner/HomeBanner.tsx index 2a3a632fb..18432ec82 100644 --- a/src/components/modules/home/HomeBanner/HomeBanner.tsx +++ b/src/components/modules/home/HomeBanner/HomeBanner.tsx @@ -1,8 +1,9 @@ import React from 'react' import { Banner } from 'src/components/common' -import s from './HomeBanner.module.scss' import BannerImgRight from './assets/banner_full.png' -import BannerImgRight2 from './assets/banner_product.png' +import HomeBannerImg from './assets/home_banner.png' +import s from './HomeBanner.module.scss' +import Image from 'next/image' interface Props { className?: string @@ -13,6 +14,9 @@ const HomeBanner = ({ }: Props) => { return (
    +
    + +
    Freshness
    guaranteed
    @@ -28,10 +32,10 @@ const HomeBanner = ({ }: Props) => { { title: "Save 15% on your first order 2", subtitle: "Last call! Shop deep deals on 100+ bulk picks while you can.", - imgLink: BannerImgRight2.src, + imgLink: BannerImgRight.src, size: "small", } - ] + ] } />
    diff --git a/src/components/modules/home/HomeBanner/assets/banner_product.png b/src/components/modules/home/HomeBanner/assets/banner_product.png deleted file mode 100644 index 82f1b7fee..000000000 Binary files a/src/components/modules/home/HomeBanner/assets/banner_product.png and /dev/null differ diff --git a/src/components/modules/home/HomeVideo/assets/bg_left.svg b/src/components/modules/home/HomeVideo/assets/bg_left.svg index d730f777d..74b215ae0 100644 --- a/src/components/modules/home/HomeVideo/assets/bg_left.svg +++ b/src/components/modules/home/HomeVideo/assets/bg_left.svg @@ -1,19 +1,19 @@ - - + + - - + + - - + + diff --git a/src/components/modules/home/HomeVideo/assets/bg_right.svg b/src/components/modules/home/HomeVideo/assets/bg_right.svg index e89652a3a..346d14e31 100644 --- a/src/components/modules/home/HomeVideo/assets/bg_right.svg +++ b/src/components/modules/home/HomeVideo/assets/bg_right.svg @@ -1,21 +1,21 @@ - - + + - - + + - - + + diff --git a/src/components/modules/recipes-list/RecipeListBanner/RecipeListBanner.module.scss b/src/components/modules/recipes-list/RecipeListBanner/RecipeListBanner.module.scss new file mode 100644 index 000000000..2e5f65a1c --- /dev/null +++ b/src/components/modules/recipes-list/RecipeListBanner/RecipeListBanner.module.scss @@ -0,0 +1,8 @@ +@import "../../../../styles/_utilities"; + +.recipeListBanner{ + @apply spacing-horizontal; + @screen md { + padding:0 3.2rem; + } +} \ No newline at end of file diff --git a/src/components/modules/recipes-list/RecipeListBanner/RecipeListBanner.tsx b/src/components/modules/recipes-list/RecipeListBanner/RecipeListBanner.tsx new file mode 100644 index 000000000..0db63d2e3 --- /dev/null +++ b/src/components/modules/recipes-list/RecipeListBanner/RecipeListBanner.tsx @@ -0,0 +1,27 @@ +import React from 'react' +import { Banner } from 'src/components/common' +import BannerRight from './assets/bannerrecipes.png' +import s from './RecipeListBanner.module.scss' + +interface Props { +} + +const RecipeListBanner = ({ }: Props) => { + return ( +
    + +
    + ) +} + +export default RecipeListBanner diff --git a/src/components/modules/recipes-list/RecipeListBanner/assets/bannerrecipes.png b/src/components/modules/recipes-list/RecipeListBanner/assets/bannerrecipes.png new file mode 100644 index 000000000..91271cbd2 Binary files /dev/null and b/src/components/modules/recipes-list/RecipeListBanner/assets/bannerrecipes.png differ diff --git a/src/components/modules/recipes-list/RecipesList/RecipesItem/RecipesItem.module.scss b/src/components/modules/recipes-list/RecipesList/RecipesItem/RecipesItem.module.scss new file mode 100644 index 000000000..2f70eb3ca --- /dev/null +++ b/src/components/modules/recipes-list/RecipesList/RecipesItem/RecipesItem.module.scss @@ -0,0 +1,60 @@ +@import "../../../../../styles/_utilities"; + +.recipesItem { + @apply flex justify-between; + margin: 1.5rem 0; + + @screen md{ + @apply block; + } + + .recipesItemImage { + @apply transition-all duration-200; + width: 31%; + img { + @apply block object-cover; + width: 100%; + min-height: 12.5rem; + border-radius: 1.5rem; + } + + @screen md { + @apply object-cover cursor-pointer; + width: 100%; + margin: 0 auto; + img{ + height:100%; + border-radius: 2.4rem; + } + } + } + .recipesItemText { + width: 65%; + .recipesItemName{ + @apply topline font-bold cursor-pointer; + + display: -webkit-box; + -webkit-line-clamp: 1; + overflow: hidden; + -webkit-box-orient: vertical; + font-feature-settings: "salt" on; + color:var(--text-active); + margin-top: 1.6rem; + &:hover { + color: var(--primary); + } + } + @screen md { + width: 100%; + } + } + + .recipesItemDescription{ + color:var(--text-label); + display: -webkit-box; + -webkit-line-clamp: 2; + overflow: hidden; + -webkit-box-orient: vertical; + } + +} diff --git a/src/components/modules/recipes-list/RecipesList/RecipesItem/RecipesItem.tsx b/src/components/modules/recipes-list/RecipesList/RecipesItem/RecipesItem.tsx new file mode 100644 index 000000000..f43227d5a --- /dev/null +++ b/src/components/modules/recipes-list/RecipesList/RecipesItem/RecipesItem.tsx @@ -0,0 +1,31 @@ +import Link from 'next/link'; +import React from 'react'; +import s from './RecipesItem.module.scss'; +interface RecipesItem { + image:string, + name: string, + description:string, + link: string +} + +const RecipesItem = ({ image, name,description, link }: RecipesItem) => { + return ( + + ) +} + +export default RecipesItem diff --git a/src/components/modules/recipes-list/RecipesList/RecipesList.module.scss b/src/components/modules/recipes-list/RecipesList/RecipesList.module.scss new file mode 100644 index 000000000..5f9ded191 --- /dev/null +++ b/src/components/modules/recipes-list/RecipesList/RecipesList.module.scss @@ -0,0 +1,94 @@ +@import "../../../../styles/_utilities"; + +.recipesListWrapper { + @apply spacing-horizontal; + @screen md{ + padding:0 3.2rem; + padding-bottom:5.6rem; + } + .breadcrumb{ + padding:1rem 0; + } + .recipesListPageMain{ + @screen md { + @apply flex; + } + .categories{ + @apply hidden; + @screen md { + @apply hidden; + } + @screen xl{ + @apply block; + width:25%; + } + } + .recipesList{ + @screen md { + @apply flex justify-between flex-wrap w-full; + margin: 1rem 0; + } + @screen xl { + width:75%; + } + .inner{ + @screen md { + @apply flex flex-col items-center justify-center; + } + .boxItem { + @screen md { + @apply flex justify-between flex-wrap; + margin: 1rem 0; + } + .item { + @screen md { + width: calc(97% / 2); + margin-top:1rem; + } + @screen lg{ + width: calc(97% / 3); + margin-top:1rem; + } + } + } + } + .recipesPagination{ + @apply flex justify-center w-full; + margin: 3rem 0; + @screen md { + @apply flex justify-center ; + margin:2rem 0; + } + } + .boxSelect{ + @apply flex justify-between w-full; + padding: 2.5rem 0; + + @screen xl { + @apply block; + width: auto; + padding:0; + } + .categorySelectCate{ + @screen xl { + @apply hidden; + } + } + label{ + @apply font-bold topline ; + color:var(--text-active); + @screen xl { + @apply hidden; + } + } + .select{ + margin-top: 1rem; + } + } + + } + + } + + +} diff --git a/src/components/modules/recipes-list/RecipesList/RecipesList.tsx b/src/components/modules/recipes-list/RecipesList/RecipesList.tsx new file mode 100644 index 000000000..0788e1a47 --- /dev/null +++ b/src/components/modules/recipes-list/RecipesList/RecipesList.tsx @@ -0,0 +1,217 @@ +import React from 'react'; +import BreadcrumbCommon from 'src/components/common/BreadcrumbCommon/BreadcrumbCommon'; +import MenuNavigation from 'src/components/common/MenuNavigation/MenuNavigation'; +import PaginationCommon from 'src/components/common/PaginationCommon/PaginationCommon'; +import { RecipeCardProps } from 'src/components/common/RecipeCard/RecipeCard'; +import image12 from "../../../../../public/assets/images/image12.png"; +import image13 from "../../../../../public/assets/images/image13.png"; +import image14 from "../../../../../public/assets/images/image14.png"; +import RecipesItem from './RecipesItem/RecipesItem'; +import HeadingCommon from "../../../common/HeadingCommon/HeadingCommon"; +import s from './RecipesList.module.scss'; +import { OPTION_ALL, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'; +import { SelectCommon } from 'src/components/common'; + +const recipe:RecipeCardProps[] = [{ + title: "Special Recipe of Vietnamese Phở", + description:"Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:", + imageSrc: image12.src + },{ + title: "Original Recipe of Curry", + description:"Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...", + imageSrc: image13.src + },{ + title: "The Best Recipe of Beef Noodle Soup", + description:"The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...", + imageSrc: image14.src + },{ + title: "Special Recipe of Vietnamese Phở", + description:"Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:", + imageSrc: image12.src + },{ + title: "Original Recipe of Curry", + description:"Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...", + imageSrc: image13.src + },{ + title: "The Best Recipe of Beef Noodle Soup", + description:"The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...", + imageSrc: image14.src +}]; +const BREADCRUMB = [ + { + name: 'Special Recipes', + link: `#`, + }, +]; + +const CATEGORY = [ + { + name: 'All', + link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=${OPTION_ALL}`, + }, + { + name: 'Malaysian', + link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=malaysia`, + }, + { + name: 'Vietnamese', + link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=vietnamese`, + }, + { + name: 'Thailand', + link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=thailand`, + }, + { + name: 'Indian', + link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=indian`, + }, + { + name: 'Lao', + link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=lao`, + }, + { + name: 'Chinese', + link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=chinese`, + }, + { + name: 'Korean', + link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=korean`, + }, + { + name: 'Japanese', + link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=japanese`, + }, + { + name: 'Western', + link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=western`, + }, + ]; + +const CATEGORYSELECT = [ +{ + name: 'All', + value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=${OPTION_ALL}`, +}, +{ + name: 'Malaysian', + value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=malaysia`, +}, +{ + name: 'Vietnamese', + value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=vietnamese`, +}, +{ + name: 'Thailand', + value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=thailand`, +}, +{ + name: 'Indian', + value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=indian`, +}, +{ + name: 'Lao', + value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=lao`, +}, +{ + name: 'Chinese', + value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=chinese`, +}, +{ + name: 'Korean', + value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=korean`, +}, +{ + name: 'Japanese', + value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=japanese`, +}, +{ + name: 'Western', + value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=western`, +}, +]; + +const OPTIONSLECT=[ + { + name:"Most Viewed", + value:"most-viewed" + }, + { + name:"Lastest Blogs", + value:"lastest-blogs" + }, + { + name:"Recent Blogs", + value:"recent-blogs" + }, +]; + +interface Props{ + data?: RecipeCardProps[], + recipes?:{ + id:string, + title:string, + image:string, + description:string, + link:string + }[], +} + + +const RecipesList = ({ data =recipe}:Props) => { + return ( + <> +
    +
    + +
    +
    + +
    + +
    + +
    + SPECIAL RECIPES + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + {data?.map((item,index) => ( +
    + +
    + ))} +
    +
    +
    + +
    +
    + +
    + +
    + + ) +} + +export default RecipesList diff --git a/src/components/modules/recipes-list/index.ts b/src/components/modules/recipes-list/index.ts new file mode 100644 index 000000000..dc665674c --- /dev/null +++ b/src/components/modules/recipes-list/index.ts @@ -0,0 +1,2 @@ +export { default as RecipeListBanner } from './RecipeListBanner/RecipeListBanner' +export { default as RecipesList} from './RecipesList/RecipesList' diff --git a/src/styles/_utilities.scss b/src/styles/_utilities.scss index cc13ea3cf..6b919de76 100644 --- a/src/styles/_utilities.scss +++ b/src/styles/_utilities.scss @@ -149,6 +149,7 @@ .line { @apply flex justify-between items-center; > div { + flex: 1; &:not(:last-child) { margin-right: 1.6rem; } diff --git a/src/utils/constanst.utils.ts b/src/utils/constanst.utils.ts index e5966ad7e..1522e477f 100644 --- a/src/utils/constanst.utils.ts +++ b/src/utils/constanst.utils.ts @@ -10,10 +10,9 @@ export const ROUTE = { PRODUCTS: '/products', PRODUCT_DETAIL: '/product', ABOUT: '/about', - BLOG_DETAIL: '/blogdetail', + BLOG_DETAIL: '/blog', ACCOUNT: '/account', RECIPES: '/recipes', - BUSSINESS: '/bussiness', CONTACT: '/contact', FAQ: '/faq', @@ -34,7 +33,9 @@ export const QUERY_KEY = { TAB: 'tab', CATEGORY: 'category', BRAND: 'brand', - FEATURED: 'feature' + FEATURED: 'feature', + SORTBY:'sortby', + RECIPES:'recipes' } export enum ProductFeature { @@ -48,3 +49,5 @@ export const KEY = { ENTER: 'Enter', } +export const OPTION_ALL = 'all'; +export const DEFAULT_PAGE_SIZE=20 \ No newline at end of file diff --git a/src/utils/demo-data.ts b/src/utils/demo-data.ts index a4ebee5dc..ff4ddaab5 100644 --- a/src/utils/demo-data.ts +++ b/src/utils/demo-data.ts @@ -186,32 +186,38 @@ export const RECIPE_DATA_TEST: RecipeCardProps[] = [ { title: "Special Recipe of Vietnamese Phở", description: "Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:", - imageSrc: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png' + imageSrc: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png', + slug: "special-recipe-of-vietnamese-pho" }, { title: "Original Recipe of Curry", description: "Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...", - imageSrc: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png' + imageSrc: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png', + slug:"original-recipe-of-curry" }, { title: "The Best Recipe of Beef Noodle Soup", description: "The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...", - imageSrc: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png' + imageSrc: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png', + slug:"the-best-recipe-of-beef-noodle-soup" }, { title: "Special Recipe of Vietnamese Phở", description: "Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:", - imageSrc: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png' + imageSrc: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png', + slug: "special-recipe-of-vietnamese-pho" }, { title: "Original Recipe of Curry", description: "Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...", - imageSrc: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png' + imageSrc: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png', + slug:"original-recipe-of-curry" }, { title: "The Best Recipe of Beef Noodle Soup", description: "The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...", - imageSrc: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png' + imageSrc: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png', + slug:"the-best-recipe-of-beef-noodle-soup" }, ] diff --git a/src/utils/language.utils.ts b/src/utils/language.utils.ts index 191215aaa..8b3d8f8d5 100644 --- a/src/utils/language.utils.ts +++ b/src/utils/language.utils.ts @@ -2,6 +2,7 @@ export const LANGUAGE = { BUTTON_LABEL: { BUY_NOW: 'Buy now', SHOP_NOW: 'Shop now', + CONFIRM:'Confirm', ADD_TO_CARD: 'Add to Cart', PREORDER: 'Pre-Order Now', }, diff --git a/src/utils/types.utils.ts b/src/utils/types.utils.ts index c927f977e..532e1ae4c 100644 --- a/src/utils/types.utils.ts +++ b/src/utils/types.utils.ts @@ -20,6 +20,14 @@ export interface FeaturedProductProps { export interface RecipeProps { title: string + slug: string + description: string + imageSrc: string +} + +export interface BlogProps { + title: string + slug: string description: string imageSrc: string }