Eva v1 #1
134
.gitignore
vendored
@ -4,21 +4,129 @@ logs
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
node_modules
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional stylelint cache
|
||||||
|
.stylelintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
dist
|
dist
|
||||||
dist-ssr
|
|
||||||
*.local
|
|
||||||
|
|
||||||
# Editor directories and files
|
# Gatsby files
|
||||||
.vscode/*
|
.cache/
|
||||||
!.vscode/extensions.json
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
.idea
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# vuepress v2.x temp and cache directory
|
||||||
|
.temp
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# Docusaurus cache and generated files
|
||||||
|
.docusaurus
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
|
2126
.pnp.loader.mjs
generated
35
.prettierrc.mjs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */
|
||||||
|
const config = {
|
||||||
|
printWidth: 100,
|
||||||
|
singleQuote: true,
|
||||||
|
trailingComma: 'es5',
|
||||||
|
plugins: ['@ianvs/prettier-plugin-sort-imports'],
|
||||||
|
importOrder: [
|
||||||
|
'.*styles.css$',
|
||||||
|
'',
|
||||||
|
'dayjs',
|
||||||
|
'^react$',
|
||||||
|
'^next$',
|
||||||
|
'^next/.*$',
|
||||||
|
'<BUILTIN_MODULES>',
|
||||||
|
'<THIRD_PARTY_MODULES>',
|
||||||
|
'^@mantine/(.*)$',
|
||||||
|
'^@mantinex/(.*)$',
|
||||||
|
'^@mantine-tests/(.*)$',
|
||||||
|
'^@docs/(.*)$',
|
||||||
|
'^@/.*$',
|
||||||
|
'^../(?!.*.css$).*$',
|
||||||
|
'^./(?!.*.css$).*$',
|
||||||
|
'\\.css$',
|
||||||
|
],
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: '*.mdx',
|
||||||
|
options: {
|
||||||
|
printWidth: 70,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
17
.storybook/main.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import type { StorybookConfig } from '@storybook/react-vite';
|
||||||
|
|
||||||
|
const config: StorybookConfig = {
|
||||||
|
core: {
|
||||||
|
disableWhatsNewNotifications: true,
|
||||||
|
disableTelemetry: true,
|
||||||
|
enableCrashReports: false,
|
||||||
|
},
|
||||||
|
stories: ['../src/**/*.mdx', '../src/**/*.story.@(js|jsx|ts|tsx)'],
|
||||||
|
addons: ['storybook-dark-mode'],
|
||||||
|
framework: {
|
||||||
|
name: '@storybook/react-vite',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
36
.storybook/preview.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import '@mantine/core/styles.css';
|
||||||
|
|
||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { addons } from '@storybook/preview-api';
|
||||||
|
import { DARK_MODE_EVENT_NAME } from 'storybook-dark-mode';
|
||||||
|
import { MantineProvider, useMantineColorScheme } from '@mantine/core';
|
||||||
|
import { theme } from '../src/theme';
|
||||||
|
|
||||||
|
const channel = addons.getChannel();
|
||||||
|
|
||||||
|
export const parameters = {
|
||||||
|
layout: 'fullscreen',
|
||||||
|
options: {
|
||||||
|
showPanel: false,
|
||||||
|
storySort: (a, b) => {
|
||||||
|
return a.title.localeCompare(b.title, undefined, { numeric: true });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function ColorSchemeWrapper({ children }: { children: React.ReactNode }) {
|
||||||
|
const { setColorScheme } = useMantineColorScheme();
|
||||||
|
const handleColorScheme = (value: boolean) => setColorScheme(value ? 'dark' : 'light');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
channel.on(DARK_MODE_EVENT_NAME, handleColorScheme);
|
||||||
|
return () => channel.off(DARK_MODE_EVENT_NAME, handleColorScheme);
|
||||||
|
}, [channel]);
|
||||||
|
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const decorators = [
|
||||||
|
(renderStory: any) => <ColorSchemeWrapper>{renderStory()}</ColorSchemeWrapper>,
|
||||||
|
(renderStory: any) => <MantineProvider theme={theme}>{renderStory()}</MantineProvider>,
|
||||||
|
];
|
1
.stylelintignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
dist
|
28
.stylelintrc.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"extends": ["stylelint-config-standard-scss"],
|
||||||
|
"rules": {
|
||||||
|
"custom-property-pattern": null,
|
||||||
|
"selector-class-pattern": null,
|
||||||
|
"scss/no-duplicate-mixins": null,
|
||||||
|
"declaration-empty-line-before": null,
|
||||||
|
"declaration-block-no-redundant-longhand-properties": null,
|
||||||
|
"alpha-value-notation": null,
|
||||||
|
"custom-property-empty-line-before": null,
|
||||||
|
"property-no-vendor-prefix": null,
|
||||||
|
"color-function-notation": null,
|
||||||
|
"length-zero-no-unit": null,
|
||||||
|
"selector-not-notation": null,
|
||||||
|
"no-descending-specificity": null,
|
||||||
|
"comment-empty-line-before": null,
|
||||||
|
"scss/at-mixin-pattern": null,
|
||||||
|
"scss/at-rule-no-unknown": null,
|
||||||
|
"value-keyword-case": null,
|
||||||
|
"media-feature-range-notation": null,
|
||||||
|
"selector-pseudo-class-no-unknown": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"ignorePseudoClasses": ["global"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
942
.yarn/releases/yarn-4.9.3.cjs
vendored
Executable file
3
.yarnrc.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
nodeLinker: node-modules
|
||||||
|
|
||||||
|
yarnPath: .yarn/releases/yarn-4.9.3.cjs
|
BIN
Images/Products/BiodermaWater.png
Normal file
After Width: | Height: | Size: 132 KiB |
BIN
Images/Products/BobbiBrownEyeCream.png
Normal file
After Width: | Height: | Size: 320 KiB |
BIN
Images/Products/BrowLamination.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
Images/Products/CliniqueCleansingBalm.png
Normal file
After Width: | Height: | Size: 348 KiB |
BIN
Images/Products/DoubleWear.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
Images/Products/EsteeLauderEssence.png
Normal file
After Width: | Height: | Size: 116 KiB |
BIN
Images/Products/EyelashCurler.png
Normal file
After Width: | Height: | Size: 233 KiB |
BIN
Images/Products/FitMe.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
Images/Products/InfaillibleFoundation.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
Images/Products/InfaillibleSpray.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
Images/Products/LaitCreme.png
Normal file
After Width: | Height: | Size: 209 KiB |
BIN
Images/Products/LancomeCreamCleanser.png
Normal file
After Width: | Height: | Size: 178 KiB |
BIN
Images/Products/LaquerGloss.png
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
Images/Products/LipDefine.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
Images/Products/MakeupPrimer.png
Normal file
After Width: | Height: | Size: 97 KiB |
BIN
Images/Products/Morphe.png
Normal file
After Width: | Height: | Size: 146 KiB |
BIN
Images/Products/No7EyeMask.png
Normal file
After Width: | Height: | Size: 293 KiB |
BIN
Images/Products/RevolutionHighlight.png
Normal file
After Width: | Height: | Size: 227 KiB |
BIN
Images/Products/RimmelBlush.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
Images/Products/SettingPowder.png
Normal file
After Width: | Height: | Size: 123 KiB |
BIN
Images/Products/VolumisingMascara.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
Images/Products/W7Primer.png
Normal file
After Width: | Height: | Size: 150 KiB |
BIN
Images/Products/dalbaSerum.png
Normal file
After Width: | Height: | Size: 292 KiB |
BIN
Images/VJB-Banner.jpg
Normal file
After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 7.6 MiB After Width: | Height: | Size: 7.6 MiB |
36
README.md
@ -1,12 +1,34 @@
|
|||||||
# React + Vite
|
# Mantine Vite template
|
||||||
|
|
||||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
## Features
|
||||||
|
|
||||||
Currently, two official plugins are available:
|
This template comes with the following features:
|
||||||
|
|
||||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
- [PostCSS](https://postcss.org/) with [mantine-postcss-preset](https://mantine.dev/styles/postcss-preset)
|
||||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
- [TypeScript](https://www.typescriptlang.org/)
|
||||||
|
- [Storybook](https://storybook.js.org/)
|
||||||
|
- [Vitest](https://vitest.dev/) setup with [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)
|
||||||
|
- ESLint setup with [eslint-config-mantine](https://github.com/mantinedev/eslint-config-mantine)
|
||||||
|
|
||||||
## Expanding the ESLint configuration
|
## npm scripts
|
||||||
|
|
||||||
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
## Build and dev scripts
|
||||||
|
|
||||||
|
- `dev` – start development server
|
||||||
|
- `build` – build production version of the app
|
||||||
|
- `preview` – locally preview production build
|
||||||
|
|
||||||
|
### Testing scripts
|
||||||
|
|
||||||
|
- `typecheck` – checks TypeScript types
|
||||||
|
- `lint` – runs ESLint
|
||||||
|
- `prettier:check` – checks files with Prettier
|
||||||
|
- `vitest` – runs vitest tests
|
||||||
|
- `vitest:watch` – starts vitest watch
|
||||||
|
- `test` – runs `vitest`, `prettier:check`, `lint` and `typecheck` scripts
|
||||||
|
|
||||||
|
### Other scripts
|
||||||
|
|
||||||
|
- `storybook` – starts storybook dev server
|
||||||
|
- `storybook:build` – build production storybook bundle to `storybook-static`
|
||||||
|
- `prettier:write` – formats all files with Prettier
|
||||||
|
@ -1,29 +1,11 @@
|
|||||||
import js from '@eslint/js'
|
import mantine from 'eslint-config-mantine';
|
||||||
import globals from 'globals'
|
import tseslint from 'typescript-eslint';
|
||||||
import reactHooks from 'eslint-plugin-react-hooks'
|
|
||||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
||||||
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
||||||
|
|
||||||
export default defineConfig([
|
export default tseslint.config(
|
||||||
globalIgnores(['dist']),
|
...mantine,
|
||||||
|
{ ignores: ['**/*.{mjs,cjs,js,d.ts,d.mts}', './.storybook/main.ts'] },
|
||||||
{
|
{
|
||||||
files: ['**/*.{js,jsx}'],
|
files: ['**/*.story.tsx'],
|
||||||
extends: [
|
rules: { 'no-console': 'off' },
|
||||||
js.configs.recommended,
|
}
|
||||||
reactHooks.configs['recommended-latest'],
|
);
|
||||||
reactRefresh.configs.vite,
|
|
||||||
],
|
|
||||||
languageOptions: {
|
|
||||||
ecmaVersion: 2020,
|
|
||||||
globals: globals.browser,
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 'latest',
|
|
||||||
ecmaFeatures: { jsx: true },
|
|
||||||
sourceType: 'module',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
13
index.html
@ -1,13 +1,12 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<meta
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
name="viewport"
|
||||||
<link
|
content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
|
||||||
href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp"
|
/>
|
||||||
rel="stylesheet" />
|
<title>What's In Your Bag</title>
|
||||||
<title>Whats In Your Bag Demo</title>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
1012
package-lock.json
generated
79
package.json
@ -1,43 +1,64 @@
|
|||||||
{
|
{
|
||||||
"name": "whatsinyourbag",
|
"name": "mantine-vite-template",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"version": "0.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "tsc && vite build",
|
||||||
"lint": "eslint .",
|
"preview": "vite preview",
|
||||||
"preview": "vite preview"
|
"typecheck": "tsc --noEmit",
|
||||||
|
"lint": "npm run eslint && npm run stylelint",
|
||||||
|
"eslint": "eslint . --cache",
|
||||||
|
"stylelint": "stylelint '**/*.css' --cache",
|
||||||
|
"prettier": "prettier --check \"**/*.{ts,tsx}\"",
|
||||||
|
"prettier:write": "prettier --write \"**/*.{ts,tsx}\"",
|
||||||
|
"vitest": "vitest run",
|
||||||
|
"vitest:watch": "vitest",
|
||||||
|
"test": "npm run typecheck && npm run prettier && npm run lint && npm run vitest && npm run build",
|
||||||
|
"storybook": "storybook dev -p 6006",
|
||||||
|
"storybook:build": "storybook build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.14.0",
|
"@mantine/core": "8.2.5",
|
||||||
"@emotion/styled": "^11.14.1",
|
"@mantine/hooks": "8.2.5",
|
||||||
"@fontsource/roboto": "^5.2.6",
|
|
||||||
"@mantine/core": "^8.2.8",
|
|
||||||
"@mantine/hooks": "^8.2.8",
|
|
||||||
"@mui/icons-material": "^7.3.1",
|
|
||||||
"@mui/material": "^7.3.1",
|
|
||||||
"@mui/styled-engine-sc": "^7.3.1",
|
|
||||||
"@types/mui-image": "^1.0.5",
|
|
||||||
"mui-image": "^1.0.9",
|
|
||||||
"prop-types": "^15.8.1",
|
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.1.1",
|
"react-dom": "^19.1.1",
|
||||||
"react-image-hotspot-viewer": "^0.3.0",
|
"react-router-dom": "^7.8.2"
|
||||||
"styled-components": "^6.1.19"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.33.0",
|
"@eslint/js": "^9.34.0",
|
||||||
"@types/react": "^19.1.10",
|
"@ianvs/prettier-plugin-sort-imports": "^4.7.0",
|
||||||
"@types/react-dom": "^19.1.7",
|
"@storybook/react": "^8.6.12",
|
||||||
"@vitejs/plugin-react": "^5.0.0",
|
"@storybook/react-vite": "^8.6.12",
|
||||||
"eslint": "^9.33.0",
|
"@testing-library/dom": "^10.4.1",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"@testing-library/jest-dom": "^6.8.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
"@testing-library/react": "^16.3.0",
|
||||||
"globals": "^16.3.0",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
|
"@types/node": "^24.3.0",
|
||||||
|
"@types/react": "^19.1.12",
|
||||||
|
"@types/react-dom": "^19.1.9",
|
||||||
|
"@vitejs/plugin-react": "^5.0.2",
|
||||||
|
"eslint": "^9.34.0",
|
||||||
|
"eslint-config-mantine": "^4.0.3",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
|
"eslint-plugin-react": "^7.37.5",
|
||||||
|
"identity-obj-proxy": "^3.0.0",
|
||||||
|
"jsdom": "^26.1.0",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"postcss-preset-mantine": "^1.18.0",
|
"postcss-preset-mantine": "1.18.0",
|
||||||
"postcss-simple-vars": "^7.0.1",
|
"postcss-simple-vars": "^7.0.1",
|
||||||
"vite": "^7.1.2"
|
"prettier": "^3.6.2",
|
||||||
}
|
"prop-types": "^15.8.1",
|
||||||
|
"storybook": "^8.6.12",
|
||||||
|
"storybook-dark-mode": "^4.0.2",
|
||||||
|
"stylelint": "^16.23.1",
|
||||||
|
"stylelint-config-standard-scss": "^15.0.1",
|
||||||
|
"typescript": "^5.9.2",
|
||||||
|
"typescript-eslint": "^8.41.0",
|
||||||
|
"vite": "^7.1.3",
|
||||||
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
|
"vitest": "^3.2.4"
|
||||||
|
},
|
||||||
|
"packageManager": "yarn@4.9.3"
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
Before Width: | Height: | Size: 1.5 KiB |
141
src/App.css
@ -1,141 +0,0 @@
|
|||||||
|
|
||||||
.hotspotimage-section {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
/* enable this to center align the image */
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: hidden;
|
|
||||||
/* background-color: red; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-section-mobile {
|
|
||||||
/* height: 100vh; */
|
|
||||||
/* width: 100vw; */
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
/* enable this to center align the image */
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: hidden;
|
|
||||||
/* background-color: red; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-container {
|
|
||||||
max-width: 80vw;
|
|
||||||
max-height: 90vh ;
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-container img {
|
|
||||||
height: 80vh;
|
|
||||||
width: 90vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-container-mobile {
|
|
||||||
width: 100vw;
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-container-mobile img {
|
|
||||||
height: 80vh;
|
|
||||||
width: 90vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-tooltips {
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-tooltips-mobile {
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-pin-mobile {
|
|
||||||
position: absolute;
|
|
||||||
content: "";
|
|
||||||
top: 50%;
|
|
||||||
left: 80%;
|
|
||||||
height: 20px;
|
|
||||||
width: 20px;
|
|
||||||
background-color: rgb(198, 54, 189);
|
|
||||||
border-radius: 50%;
|
|
||||||
cursor: pointer;
|
|
||||||
display: block;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-pin-mobile:after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
background-color: rgb(244, 187, 248);
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: puls-effect 0.8s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-pin {
|
|
||||||
position: absolute;
|
|
||||||
content: "";
|
|
||||||
top: 50%;
|
|
||||||
left: 80%;
|
|
||||||
height: 25px;
|
|
||||||
width: 25px;
|
|
||||||
background-color: rgb(198, 54, 189);
|
|
||||||
border-radius: 50%;
|
|
||||||
cursor: pointer;
|
|
||||||
/* hide by default */
|
|
||||||
display: block;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotspotimage-pin:after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
background-color: rgb(244, 187, 248);
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: puls-effect 0.8s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* .hotspotimage-tooltip {
|
|
||||||
position: r;
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* Animate pin only when image is hovered */
|
|
||||||
.hotspotimage-container:hover .hotspotimage-pin {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Puls Effect For Pins */
|
|
||||||
|
|
||||||
@keyframes puls-effect {
|
|
||||||
0% {
|
|
||||||
transform: scale(0.5);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: scale(2);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
110
src/App.jsx
@ -1,77 +1,45 @@
|
|||||||
import Box from '@mui/material/Box';
|
import '@mantine/core/styles.css';
|
||||||
import {Center, MantineProvider, Image, Text} from '@mantine/core';
|
|
||||||
import { ImageHotspotViewer } from 'react-image-hotspot-viewer';
|
import { Box, Center, Image, MantineProvider, Overlay, em } from '@mantine/core';
|
||||||
import testEva from '../Images/testEva.jpg';
|
import { theme } from './theme';
|
||||||
import './App.css'
|
import HotspotPicture from './components/HotspotPicture';
|
||||||
|
import BannerImage from '../Images/VJB-Banner.jpg';
|
||||||
|
import { useMediaQuery } from '@mantine/hooks';
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import CosmeticProductCard from './components/CosmeticProductCard';
|
||||||
|
|
||||||
|
import clientPhoto from '../Images/client/eva.jpg';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const testlink = <Image src='https://hips.hearstapps.com/hmg-prod/images/gh-best-skincare-products-6557978b58b57.png?crop=1.00xw:1.00xh;0,0&resize=1200:*' height={"100px"} />
|
const isMobile = useMediaQuery(`(max-width: ${em(750)})`);
|
||||||
const hotspots = [{
|
const imageRef = useRef(null);
|
||||||
id: 1,
|
const [imageHeight, setImageHeight] = useState(null);
|
||||||
title: 'Cheeks',
|
|
||||||
description: <>{testlink}<Text size="md" fw="bold">ABC</Text></>,
|
useEffect(() => {
|
||||||
image:'https://hips.hearstapps.com/hmg-prod/images/gh-best-skincare-products-6557978b58b57.png?crop=1.00xw:1.00xh;0,0&resize=1200:*',
|
const img = imageRef.current;
|
||||||
position: {
|
if (!img) return;
|
||||||
top: `45%`,
|
|
||||||
left: `42%`,
|
const updateHeight = () => setImageHeight(img.offsetHeight);
|
||||||
},
|
|
||||||
action: {
|
if (img.complete) {
|
||||||
hasAction: true,
|
updateHeight(); // already loaded
|
||||||
type: 'link',
|
} else {
|
||||||
url: 'https://www.google.com',
|
img.addEventListener('load', updateHeight);
|
||||||
label: 'View Product Details',
|
return () => img.removeEventListener('load', updateHeight);
|
||||||
icon: 'open_in_new',
|
}
|
||||||
}
|
}, []);
|
||||||
}, {
|
|
||||||
id: 2,
|
|
||||||
title: 'Nose',
|
|
||||||
description: 'Nose Product',
|
|
||||||
position: {
|
|
||||||
top: `45%`,
|
|
||||||
left: `51%`
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
hasAction: false,
|
|
||||||
}
|
|
||||||
},{id:3,
|
|
||||||
title:'Eyes',
|
|
||||||
description:'Eyes Product',
|
|
||||||
position:
|
|
||||||
{
|
|
||||||
top: `40%`,
|
|
||||||
left: `43.5%`
|
|
||||||
},
|
|
||||||
action:{
|
|
||||||
hasAction:true,
|
|
||||||
type:'link',
|
|
||||||
url:'https://www.google.com',
|
|
||||||
label:'testimagesetes',
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
id: 4,
|
|
||||||
title: 'Lips',
|
|
||||||
description: 'Lips Product',
|
|
||||||
position: {
|
|
||||||
top: `50%`,
|
|
||||||
left: `51%`
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
hasAction: false,
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MantineProvider>
|
<MantineProvider theme={theme}>
|
||||||
<ImageHotspotViewer
|
<Box bg={"black"} p={0} m={0} style={{borderBottom : "gold 2px solid"}}>
|
||||||
image={testEva}
|
|
||||||
hotspots={hotspots}
|
<Image src={BannerImage} ref={imageRef} fit='contain' h={"5vh"} m={0} p={0}/>
|
||||||
imageStyles={{
|
</Box>
|
||||||
// width:"50vw",
|
<Overlay p={10} m={0} top={imageHeight} gradient="linear-gradient(145deg, rgba(198, 78, 178, 1) 0%, rgba(170, 78, 171, 0.2) 100%)">
|
||||||
// height:"50vh",
|
<Center>
|
||||||
border:'2px black solid',
|
<HotspotPicture/>
|
||||||
borderRadius :"10%"
|
</Center>
|
||||||
}}
|
</Overlay>
|
||||||
/>
|
</MantineProvider>
|
||||||
</MantineProvider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
|
Before Width: | Height: | Size: 4.0 KiB |
51
src/components/CosmeticProductCard.jsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { Badge, Button, Card, Center, Divider, Group, Image, Text } from '@mantine/core';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
const CosmeticProductCard = ({ products, title }) => {
|
||||||
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||||||
|
const product = products[currentIndex];
|
||||||
|
|
||||||
|
const handlePrev = () => {
|
||||||
|
setCurrentIndex((prev) => (prev === 0 ? products.length - 1 : prev - 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNext = () => {
|
||||||
|
setCurrentIndex((prev) => (prev === products.length - 1 ? 0 : prev + 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card shadow="sm" padding="lg" radius="md" withBorder>
|
||||||
|
|
||||||
|
|
||||||
|
<Text ta="center" fw={500}>{title}</Text>
|
||||||
|
<Divider pb={2} />
|
||||||
|
|
||||||
|
<Card.Section>
|
||||||
|
<Image
|
||||||
|
src={`../../Images/Products/${product.img}`}
|
||||||
|
height={160}
|
||||||
|
fit="contain"
|
||||||
|
/>
|
||||||
|
</Card.Section>
|
||||||
|
|
||||||
|
<Text ta="center" size="sm" c="dimmed">
|
||||||
|
{product.name}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<a href={product.link} target="_blank" rel="noopener noreferrer">
|
||||||
|
<Button pb={2} color="blue" fullWidth mt="md" radius="md">
|
||||||
|
Buy Now
|
||||||
|
</Button>
|
||||||
|
</a>
|
||||||
|
<Center>
|
||||||
|
<Group mt="md" position="center">
|
||||||
|
<Button variant="light" onClick={handlePrev}>←</Button>
|
||||||
|
<Text size="sm">{currentIndex + 1} / {products.length}</Text>
|
||||||
|
<Button variant="light" onClick={handleNext}>→</Button>
|
||||||
|
</Group>
|
||||||
|
</Center>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CosmeticProductCard;
|
163
src/components/HotSpots.json
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
[{
|
||||||
|
"id": 1,
|
||||||
|
"left": 50,
|
||||||
|
"top": 35,
|
||||||
|
"title": "Skincare",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "Lancome Cream Cleanser",
|
||||||
|
"link": "https://www.amazon.co.uk/Lanc%C3%B4me-Galateis-Douceur-Gentle-Cleanser/dp/B001BOJSEI?crid=WIPAM2F9PZPG&dib=eyJ2IjoiMSJ9.HTIGX5OZpBoGCtTyEu7UuI53G2BHaz-OIMnYQsYOa8F1RFS5onVCzGH8R3A9JO_1ve2rQsvgdPgQdYlJ4IQRGO8GXYsJxPoHXnhZ5UMyrPWWbCIzYF7snZ1XOmyVPh4n6zBxWFBM1EG4uORsUY9Yn_Vf7IDIQQRpNZ5R4uFjpSRzcCZMJ6ON1RkPEA5opwVPme3OoKYSjb6yZdtHVThB7dKBFuOs0Rr9dDUBbo9bWQGlNCaL_PDiaMveudD8sd6KTq1UFs-V88NYoNrMnvdUiC1lMYqhoaLNoUq5saM5lKs.-CK91cVYFQsClkNJ4IQ0ScgbE3aYCVHEBtB7WMFlUF4&dib_tag=se&keywords=lancome%2Bcleansing%2Bmilk&qid=1756760264&sprefix=lacome%2Bclean%2Caps%2C119&sr=8-6&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=f785eb3d283949baea415228347237e1&language=en_GB&ref_=as_li_ss_tl",
|
||||||
|
"img": "LancomeCreamCleanser.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Clinique Cleansing Balm",
|
||||||
|
"link": "https://www.amazon.co.uk/Clinique-Take-Cleansing-Balm-Types/dp/B07D5C86RX?crid=3A4R0135S7XQZ&dib=eyJ2IjoiMSJ9.HiQxgAv9CgW42sO0u4POmSS3c5sTfB5VBo6s4MqR8jACwAQ9rxFCpvXH2kepwmTTWEXJwnRN8FU1Wqb7Ebl2eX9e8AC9ebbR8wp2KADo0RPiC6DJrjqMALYdQNBwlkE1y3SiFLitaOd-DRkEIMq_K4TJD2zrs9zF1dbTqjo_bnvVS9qGLHM_0qAsw3UBCAUBg_TLJAoBuyGUhTypo6Xg5wOle3nEziitBvFwJbFNb1HkOkcPrFttUowQ_RTI04iLn4KtYZBYvVE5Sczun5XTNgKA6OFh20kgvnB1P9oKRSY.uTFVIk5iY9hJiwARoTeeHItvO6Mz5WE5xAMxz2ZEQVo&dib_tag=se&keywords=clinique+cleanser&qid=1756760426&sprefix=clinique+cl%2Caps%2C119&sr=8-1&linkCode=ll1&tag=verityjanebea-21&linkId=754dc784fa780a8a78c487c730ee46e8&language=en_GB&ref_=as_li_ss_tl",
|
||||||
|
"img": "CliniqueCleansingBalm.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bioderma Créaline H2O Original Micellar Water",
|
||||||
|
"link": "https://www.amazon.co.uk/Bioderma-Cr%C3%A9aline-Original-Micellar-Water/dp/B0BLY6KH7B?crid=2ADZP8LAVUSWS&dib=eyJ2IjoiMSJ9.1mFmzxDBe-CSXKcvfF3SsS-_ZZz3Y_QOFe-heXBW4Q79FG2PX9xYxUI0FnpuHutQ5iMgI9byGbISijclbGLAQpMXnMwrVcDSQ10Q75ZSnoqDbONXubbyq-Gg-HchvhNd5A-M49QjJQqnYpQhUw6utDngJJWqTAZa6dWNNIH1NDqRE5XxQQxadC9BAPczl7XE5t_NK3iKrK1-6LxKXrY413E2Uhy5iXACXtUJmIxXmoZw761_UPzsGzz-gmX2rO3A5zdDpHLytLBcw95N0OhBVuiRcWGSGmcaNuWUoOefVFs.pb4wRl_rCFVLgeUy8ybqm9wa1sK6wd036VwW-IdrYxU&dib_tag=se&keywords=bioderma+micellar+water&qid=1756760508&sprefix=bioderma+micellar+water%2Caps%2C89&sr=8-8&linkCode=ll1&tag=verityjanebea-21&linkId=899248b760a52cc6bd3e4dc5325e03b5&language=en_GB&ref_=as_li_ss_tl",
|
||||||
|
"img": "BiodermaWater.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Estée Lauder Nutritious Radiant Essence Lotion",
|
||||||
|
"img": "EsteeLauderEssence.png",
|
||||||
|
"link": "https://www.boots.com/est%C3%89e-lauder-nutritious-radiant-essence-lotion-200ml-10326057"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "d'alba Italian White Truffle First Spray Serum",
|
||||||
|
"img": "dalbaSerum.png",
|
||||||
|
"link": "https://www.amazon.co.uk/dalba-Piedmont-Italian-hydrating-surfactant/dp/B0BFQ9RD5B?crid=29A6895FIMLHU&dib=eyJ2IjoiMSJ9.Gr990brEvRdYIkXNUNCw-ygKEqrZhUvwkWZWz5ifuBqNev-HgYlnnR2w8gXQGxRVVMhSgZX5tLdVKF8CTUdkSpdUXw0cI75PzMaGM4OmwOWoNQAyXhoDtywn_UKQ4n9XxXQSZZyblFESOSQl-E5wPisKg2ysoiYkR27cvuaoHbn-OGv6YxN3Cxrb4_JF5dGAmWOBPsQxos5YPL931d7o5Uq4dm0MPARrVOZCq8heHB-mJPCQAmxsfxTaJui8OH4dL3nO2yy7gnYyTLn8Hnzn-odEk677ofp8ZXS5kHW5glc.xDxDHGFYm3SM2rv_y0cL9Jho7e2FrTNRupWphlnGU2Q&dib_tag=se&keywords=d%27alba%2Bfirst%2Bspray%2Bserum&qid=1756760767&sprefix=d%27alba%2B%2Caps%2C114&sr=8-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=768bf661561dc64585e62fd0b5f49c32&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Embryolisse - Lait Crème Sensitive",
|
||||||
|
"img": "LaitCreme.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Embryolisse-Milk-Cream-Sensitive-100ml/dp/B08Q6GLMPT?crid=R788VALQ97IV&dib=eyJ2IjoiMSJ9.8u97ASZlowkx50huyr-LLJS2qHY5sDd5-QS6cxoJdlDOkM0IkKzJV6hjoCycFO_Wlbza943qVXbBZOwMFvjG0mZEHrzbSDa9V9gS04NEf8nJ_RhWUg2OKqbb6vk6203MHISAYPBtKMOFV-oovFqjv0-YBaCjPxVeJHZIhQAOnnBBaCD0LOL482v0j2H-xLMdOO5dNorbxSOZPz7JUkwi2MCC9vDwOx7r76deva3CqLTDcRBbMjDjorQstuni0QzJziGWuicjMZ4Sxw1DgUPsG_i8wzUbrK1mYqeZaENRotI.DAywg2tnl9vMKwcfbRl_VRaFd0PwNGBfFC0EgNCtHh8&dib_tag=se&keywords=embryolisse+lait-cr%C3%A8me+concentr%C3%A9&qid=1756760850&rdc=1&sprefix=embr%2Caps%2C121&sr=8-4&linkCode=ll1&tag=verityjanebea-21&linkId=fb22b76a9347580eebfe3e63bcf9f40e&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bobbi Brown Hydrating Eye Cream",
|
||||||
|
"img": "BobbiBrownEyeCream.png",
|
||||||
|
"link": "https://www.boots.com/bobbi-brown-hydrating-eye-cream-15ml-10300638"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "No7 Radiance+ Illuminating Hydrogel Eye Masks",
|
||||||
|
"img": "No7EyeMask.png",
|
||||||
|
"link": "https://www.amazon.co.uk/No7-Radiance-Illuminating-Hydrogel-Masks/dp/B09VXZJRPQ?crid=1GK7RCHFDNW6T&dib=eyJ2IjoiMSJ9.Z0UPlmFwMT6qZLVGlkhQuPRZnv6Xf58Q-tDL33F0uw2ar44zHkt5awhj_xOFoFOJD9XoEcgwo9b54X5WxoDXfmTqQyW6AUBqv4wT-ybfiJlUjOuk2rQ2dhzeyw19LM-wjRqTv2I8SafNsWyn8qBwkYrYVvymTBJwL_aVH0i5z00bYTLUh0dC2ZG9ATdgwaOz4hBmUTfuq5Dbm45iwgGjLAQ0uvG9U5Iqml-_y-Hxsobttp9moQFrF0-lbtDDdPohud6_GLar8fyBbWzebWaeY7cHlZ1spl6SBgfDfhKeR04.h9fvo3-UDBi8_0rwCYMLxzNp21QO4FNy4BGBThCvkKg&dib_tag=se&keywords=no+7+eye+masks&qid=1756761074&sprefix=no+7+eyemasks%2Caps%2C95&sr=8-6&linkCode=ll1&tag=verityjanebea-21&linkId=824121e23744106101047ca616b991b8&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"left": 44,
|
||||||
|
"top": 41,
|
||||||
|
"title": "Eyes",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "Maybelline Fit Me! Concealer",
|
||||||
|
"img": "FitMe.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Maybelline-Fit-Concealer-Light-6-8/dp/B0046VJTX8?crid=346JCU58XS1VB&dib=eyJ2IjoiMSJ9.Le8DkHivEgnK2RsV8SCIk0_llWQG6Ijr3GB8saT0WZrvc14YI3qGAAkkCUzf4C-lyH1zD9vCCyNUYquO_ko1rlEZ51SxIFIXG_JlwsZOjjmKmhYzRiNDPsKyLz8mSCiJrboK7jlGk3q0kfbSsa2SinhhpKIMBOibS6IkIBHU8WdQZiZMZXW0YjlgsTjL-1oDeaVq0aCOq0P2dQkbYukXnZTfCjVDbT7ueAMcYnX7SFW_tKpX7OGYxxJscGXVuvySfz7ejL0vt0ieK1_n_sm_kqxzMjiR0XVXDzcBsjZj5T4.yZZkr85qTqBDcs1Rx62FH-YwcuE95ssgYRfoRsuv7xM&dib_tag=se&keywords=maybelline%2Bfit%2Bme%2Bconcealer&qid=1756761276&sprefix=maybelline%2Bfi%2Caps%2C130&sr=8-1&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=cb59a015c8228a65bc1d353207453a25&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Estee Lauder Double Wear 24H Waterproof Gel Eye Pencil",
|
||||||
|
"img": "DoubleWear.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Est%C3%A9e-Lauder-Double-Waterproof-Pencil/dp/B09T1CCLYC?crid=2LKUPFXEQAOAT&dib=eyJ2IjoiMSJ9.Oycx_PbHUAVdtF98MuEZ01idXDV3Dv6Q4ieRUY-aErqcMyhBIq1N7Cw0fVZHbmvToY8M-6H2E66jagwNJe7rHVvKBMLuDtC71KcnybmSbNO4llB_hPb5ojgNAuLdUWbQTEivUyDF1oCyNqkPD7BcHdY3bRxglbQ0pFWR0HP_g4a4NPaA2dX9AkokQeMswfDOGNGcUnFPsw6E0yXrUEk_PjNuvsTJN5x5-TTpv0SyFkvn_TvrYlUgpf5UMM7VUQlxRZDIjrtC8WMpUGUSVKHX0_81NcZhZBXid1PoHW3Qk2s.JqFSS9U9lEnxRsGRSr49YXjzcWevJRbI3H2ShfON_WY&dib_tag=se&keywords=estee%2Blauder%2Bdouble%2Bwear%2Beyeliner&qid=1756761344&rdc=1&sprefix=estee%2Blauder%2Bdouble%2Bwear%2Beye%2Caps%2C111&sr=8-4&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=bb68297ff04fd70ed53b1db57b6eb2fc&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "L'Oreal Paris Volumising Mascara",
|
||||||
|
"img": "VolumisingMascara.png",
|
||||||
|
"link": "https://www.amazon.co.uk/LOreal-Paris-Volumising-Clump-free-Sensitive/dp/B0CJ5GW8RY?crid=2YRH21CRUV6O4&dib=eyJ2IjoiMSJ9.MbLEw-p6QFMlgh1zKc1Jc01Ztt8-_PQr2TyF3EzBu1t_uW0Q9sJl07BQtyjuxNYyAvfpD-uhIt_mhRdHkcSKMoTT3HOUy_Km2JTiiefWct14PZNDMXZQA8Uq-3AguJiSUvPfp60CspbfijeqVjyq4PIvIYDkvvVvtnJaTZbhp_LKVFv3p5i2YCp_IG2yGvybhAD0kvW1YPUF2AOmfBvkA8NEWz96CUY8d_0caw6joWow799cc0CI-SRsgyWxuxuxs66RoSZKYkIXvdZuWd4n0xlSk6Mw5Cfn55UwXUaz1RM.FHLh43gugt8ohFXXaIYNzjFNqc_-ZNZti0_w9zslbdM&dib_tag=se&keywords=panorama%2Bmascara&qid=1756761449&sprefix=Panorama%2B%2Caps%2C118&sr=8-6&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=ef0a13ef0f0d685c62ddd3e5532de784&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Eyelash Curler",
|
||||||
|
"img": "EyelashCurler.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Wet-Wild-Eyelash-Curler-Comfort/dp/B08RRLJDGM?crid=20ZADKN2JGSG2&dib=eyJ2IjoiMSJ9.F9aWME0-uJ2ek9bJC8Lu5xBU4T0GB4pkMIuwkz1LZXW6NA7r6U2Dw1Z3hmS70u3szLxdcKTyabbC7EbNnfguTvfqM_Z4c6ex5sIHJrVvy7tIhjhevBJ42p5jI4_dCW9dmvcUSdahm2ShEsuRzgba9_W-HZz89sywQWfnxfzc7r3_j62s8xendYPEKB0xe55FgKK0V6tHOhIqoMe79au6eTOv2L9-QL3kBuCLBQ4AnG72FblLtSe__3kZeyMX5r-QtU34edWuN3Hdv8_kR7wUE_1p5IdvwldLfvWfGN2L7X4.Ni3dgpxyja0oeyxneqp8ZuwOWhMEOnfl6uvzFh51H14&dib_tag=se&keywords=eyelash%2Bcurler&qid=1756761513&sprefix=eyelash%2Bcurler%2Caps%2C117&sr=8-8&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=3fd66a2c8b605ff784ea2c71b1997b16&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"left": 60,
|
||||||
|
"top": 38,
|
||||||
|
"title": "Brows",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "L'Oréal Paris Brow Lamination Gel ",
|
||||||
|
"img": "BrowLamination.png",
|
||||||
|
"link": "https://www.amazon.co.uk/LOr%C3%A9al-Paris-Lamination-Lightweight-Opthalmologically/dp/B0CQ3373JW?crid=7AZ1MSAGKBCQ&dib=eyJ2IjoiMSJ9.SRhJx6vvik2BkEovM6u9v4rWOwh5ZAPc4ULO6XiLEEcybeKMeWZOpredDLGxfRDGXUm-1OVVFwJ0ZkLrlJKvXm7yChwyztTIXBMtlIzm-baDPm0Q8rPw0Tbj7gVaFtOOXxZPufphJHbB0nvK6xHQ1a4ZpCYzo7qBLfKmpeN22bAsyAxzr4h-O_G2-9uvEadTo1hbl2ceHBAUACgIFftEKRHGkEChvcEjYEi9_j-pbg3f-H_ODVaPeVDxYp2vrwe9MYoDJ_l9ztvqEnyxXRzeVxQbNs3uBEXJB5uTx_gPz3w.dANmI2Mvj6ZHIyVnzIU9Y-yIJk5JM74XDgJTueSipiY&dib_tag=se&keywords=loreal%2Bbrow%2Blamination&qid=1756761681&sprefix=loreal%2Bbrow%2Bl%2Caps%2C109&sr=8-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=388f7e48674e2595f947be8d4836c5be&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"left": 52,
|
||||||
|
"top": 55,
|
||||||
|
"title": "Complexion",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "Maybelline Makeup Primer ",
|
||||||
|
"img": "MakeupPrimer.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Maybelline-New-York-Ultra-Blendable-Water-based/dp/B0DNT5HBHB?crid=3L7WO25EXOTBC&dib=eyJ2IjoiMSJ9.baoXMGRAEirOXFDGyc_5Apwh-lh3q0WihBRwEXk_CYv0PItsLnu11RTNNF9vjhMV_vwqDuhhSmuVkmvsW1b9h3tvk2bXLEGf_swvr1sPa70P-QH5Vh0lwCRPo-OWlxHORjDfvaOMrOq24HFS-I1ooCj-mgN5eDAmU3kTFK6bfsaQLGyW6nrLv09mS7sqB8QfHY-qyVQsi83u0afWoCwE1dN8SpyjX5ghexU0WtletWQldNPDCc1Xe1yK-vUbx7XqALRB_XaclYkuwYWxL3H00-7hLuNnv0xQmIDfbZTtMm4.GKedJZkZJZKX_4A7KQ7qWD8q3K-Vs5muP1y5XrfavnY&dib_tag=se&keywords=maybelline+grippy+primer&qid=1756761867&sprefix=maybelline+grip%2Caps%2C109&sr=8-1&linkCode=ll1&tag=verityjanebea-21&linkId=6c8619577ecefefbd18b0a91e7a62e88&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "L'Oréal Paris Infaillible 32H Liquid Foundation",
|
||||||
|
"img": "InfaillibleFoundation.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Infaillible-Long-Lasting-Protection-Function-Flawless/dp/B08PF9XJ3L?crid=3PHAD7YY4RK3&dib=eyJ2IjoiMSJ9.G6fkoKMm1E18k_de417EG_DDw94bGaNl6NhXuaxANrclCDPHsd1OFL2e63tTeVMvAG60kzaehYIbiR4Sjd5ewZ1oTEDYc3cNq6tzucD6zAlwKPIu8Kxt8HvyNxRintHPQ5rSulVKtSFG_HrVEKU3OgIyn0CLyuEl9oQpsGgasi7gPMcPZXVPImrbNptztrF69lWSKv7GcI2N_aPoTvE3uzZJruy2lQHV48ZB6mm84Wh5fKmRpCR4bI-3cXMsEB4cnYiE3fhwP96hq76Y1G-_0pdNR0RQOP8HKB_L1P8kEao.tgNJJZNtv38ipZG1oSA1L1dHeWbtF9E8sh_tAZme8X8&dib_tag=se&keywords=loreal%2Binfallible%2B32%2Bhour%2Bfoundation&qid=1756761924&sprefix=loreal%2Binfallible%2B32%2Bhour%2Bfoundation%2Caps%2C108&sr=8-9&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=6ee37816395de02449298271b2c30b13&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HUDA BEAUTY Easy Bake Loose Baking & Setting Powder Sugar",
|
||||||
|
"img": "SettingPowder.png",
|
||||||
|
"link": "https://www.amazon.co.uk/BEAUTY-Baking-Setting-Powder-Cookie/dp/B07GQ2YGVJ?dib=eyJ2IjoiMSJ9.EF6PVSVLdZK5CHDGmLocSp_SzUM9kMaNTox0jVsekm3j3aPr5mBLmH5LcEcbRLaOS9H-5dMvl6PY4ZqJZO2g4JRv_4fX8sNp7Ilvz8lMvR1PpViJGKdHOEIfA_OMl_i3u1CJlHYJ5uoUja7Soj6DlkNIMHBfVAzNL7Z5tcffZ5BZK_HJplcAZWxLr0lySn_qqAi02_qCW7nAdxfJCa5fA9jrBIcUjxi0ffdJxQCk0Ph6dQfVYoBzDfy0ilNzUuuBLRopVrqjsY8Sw7CZ59_tw578N9DZEq22s-eIZkHXJck.nedvMK_Uk-JH7T3oXkWtWpzieh_x7-3l0v8aGDv9EqY&dib_tag=se&qid=1756762102&refinements=p_89%3AHuda&sr=8-25&srs=18527346031&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=b979526f7fa0acad69e806cf22ae0479&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "L'Oréal Paris Setting Spray",
|
||||||
|
"img": "InfaillibleSpray.png",
|
||||||
|
"link": "https://www.amazon.co.uk/dp/B0CNQ4DJRV?aref=YUMJJiypco&aaxitk=1798f7b9e833dfdbdeec8c0652913699&pd_rd_plhdr=t&smid=A3P5ROKL5A1OLE&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=0c5c2dc69376cf37770af91536c83a98&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"left": 41,
|
||||||
|
"top": 48,
|
||||||
|
"title": "Contour & Blush",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "W7 Honolulu Bronzing Powder",
|
||||||
|
"img": "W7Primer.png",
|
||||||
|
"link": "https:////www.amazon.co.uk/W7-Bronzer-Honolulu/dp/B004KM1J5E?crid=3BXR48UJFFHZ2&dib=eyJ2IjoiMSJ9.Ggw2IBEST_2xZ5sEaa38bPlYyzxUnsgra3OIWCVfvryZO9mY-pCzZ_rTuR7nAx41287MlS77vRzVMx38HoPfk0ydBRP-kC25hL02dWIRdbwXBJ9G6leIOGPY3mi0HRzdgF2Ax10ezG9gG4_R868BgxKZ-S9vAxJJ16ooJE18l9NIsoZWPYyt1B8e7J06G04u3w4uTiXk93GMvVoUyl6CFfILOQg6hgPDXJHnb1NyeCU7BY2b_jKdUY3bzNMeGc9Zl0aLdzPmMu31iqs5xtyrykavCs-Wv_0hK7TCFg29VJ0.XxVZfiQ3uPpsyigbjCWMvYgKjg5VvOywXbr5myydoQ4&dib_tag=se&keywords=honolulu%2Bbronzer%2Bw7&qid=1756762346&sprefix=honolulu%2Bbronzer%2Caps%2C133&sr=8-1&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=a296b7c8d61ad1129733e36ba86b9120&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Morphe Hot Shot Blush Drops",
|
||||||
|
"img": "Morphe.png",
|
||||||
|
"link": "https:////www.boots.com/morphe-hot-shot-blush-drops-15ml-10350578"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rimmel London Lasting Finish Soft Colour Powder Blush",
|
||||||
|
"img": "RimmelBlush.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Rimmel-London-Lasting-Finish-Colour/dp/B009ACJZAK?crid=399TN0HQB34UY&dib=eyJ2IjoiMSJ9.YthZXCJ7F7wHdCbzKUSvAsNTioewzBleZgWHlM-d6BtktozTulKMvTUOQLFhLGVubQB360P3tS3IMcz9MbWmDDP8tffbnSlwAxcGTrIPMqb2F7fZcvrWOJq8QqVJ6ZeaXpRsL-IHA5wzrGnZ_JUfI03km7fh5qGEF64qPbPvnlREHNCdsmNowdIuDJwtnZ7VYmjYbM47_Mc2hy0GwqreFJ_JDgiVavaMwUu9BSrfxkdyYFt83xR1f7mmEwkpA17PwI6eVQSXrSUAjr8UJ4J6jPrjYFf5-eX1sBLtEVo2P6k.BQwkSu8VCtf-oFi2Tx674qRPVafQC_2a-w1FLKySNjw&dib_tag=se&keywords=rimmel%2Bblusher%2Bpowder&qid=1756762507&sprefix=rimmel%2Bblusher%2Bp%2Caps%2C119&sr=8-17&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=dbb4a8c105f64e19c8e115eba1ecbcd3&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Revolution Highlight Reloaded",
|
||||||
|
"img": "RevolutionHighlight.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Revolution-Highlighter-Reloaded-Just-Type/dp/B07QPZH86C?crid=2K0PK9HUFF5O6&dib=eyJ2IjoiMSJ9.mOGXegs1a5ZmvcNVFYSl7nqUPa00fU2PVvIDC7Z0xuvfAIinuEx3IB_2qgV7maaJZLLoDDEyuBnPDnjjwcKnvuT-gSYvR1AJPQkI2xACLvVtjjpzTgvphlp8mJEVDjU8qjL-htEH3lyye0CXCJF8CFV_9-os6LPOTBnhOGftzEACDAjc4Zc_vAQ9y5GyGgqv2_l-gQEzZKjDjPfUxBwVk_mKR1Rs13LhPDbTf63CD0WEvXxX69ZOI7Ga1de_KKEslr1LroIAz4fLu45Y6rNcF8Ie7L2Om7mjhAGLr6q36rk.x0t_usKkIp6YBJjDC4rhn8947XemU-eCaZUwxN2W4nk&dib_tag=se&keywords=revolution%2Bhighlighter&qid=1756762587&sprefix=Revolution%2Bhigh%2Caps%2C109&sr=8-1&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=e3d8a300b33db85d2457462812695416&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"left": 52,
|
||||||
|
"top": 51,
|
||||||
|
"title": "Contour & Blush",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "17. Lip Define Pencil Soft Liner",
|
||||||
|
"img": "LipDefine.png",
|
||||||
|
"link": "https://www.boots.com/17-lip-define-pencil-soft-liner-10306930"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "17. Lacquer Gloss",
|
||||||
|
"img": "LaquerGloss.png",
|
||||||
|
"link": "https:////www.boots.com/17-lacquer-gloss-10306929"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
79
src/components/HotspotPicture.jsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { Image, Paper, Popover, em, rgba } from '@mantine/core';
|
||||||
|
import clientPhoto from '../../Images/client/eva.jpg';
|
||||||
|
import CosmeticProductCard from './CosmeticProductCard';
|
||||||
|
import { useDisclosure, useMediaQuery } from '@mantine/hooks';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import hotspots from './HotSpots.json';
|
||||||
|
|
||||||
|
const HotspotPicture = () => {
|
||||||
|
const isMobile = useMediaQuery(`(max-width: ${em(750)})`);
|
||||||
|
const [activeCard, setActiveCard] = useState(null);
|
||||||
|
const pulseStyle = `
|
||||||
|
@keyframes fadePulse {
|
||||||
|
0% {
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 0 0px #ffc0cb;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
background-color: #ffc0cb;
|
||||||
|
box-shadow: 0 0 10px #ffc0cb;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 0 0px #ffc0cb;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<style>{pulseStyle}</style>
|
||||||
|
<div style={{ position: 'relative', maxWidth: '100vw', maxHeight: '100vh' }}>
|
||||||
|
<Image src={clientPhoto} mah={'85vh'} maw={"85vh"} radius="100%" />
|
||||||
|
|
||||||
|
{/* Hotspot with Popover */}
|
||||||
|
{hotspots.map((hotspot, index) => {
|
||||||
|
const { left, top, title, products } = hotspot;
|
||||||
|
const isOpen = activeCard === index;
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
key={index}
|
||||||
|
opened={isOpen}
|
||||||
|
onChange={()=>setActiveCard(isOpen ? null : index)}
|
||||||
|
position="top"
|
||||||
|
withArrow
|
||||||
|
trapFocus
|
||||||
|
transition="pop"
|
||||||
|
>
|
||||||
|
<Popover.Target>
|
||||||
|
<Paper
|
||||||
|
onPointerDown={()=>setActiveCard(isOpen ? null : index)}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: `${top}%`,
|
||||||
|
left: `${left}%`,
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: isMobile ? 10 : 20,
|
||||||
|
height: isMobile ? 10 : 20,
|
||||||
|
backgroundColor: 'pink',
|
||||||
|
borderRadius: '50%',
|
||||||
|
cursor: 'pointer',
|
||||||
|
animation: 'fadePulse 2s infinite',
|
||||||
|
zIndex: 10,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popover.Target>
|
||||||
|
<Popover.Dropdown bg={rgba("red", 0)} bd={'none'}>
|
||||||
|
<CosmeticProductCard products={products} title={title}/>
|
||||||
|
</Popover.Dropdown>
|
||||||
|
</Popover>)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HotspotPicture;
|
163
src/components/hotspots.jsx
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
const hotspots = [{
|
||||||
|
"id": 1,
|
||||||
|
"left": 50,
|
||||||
|
"right": 35,
|
||||||
|
"title": "Skincare",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "Lancome Cream Cleanser",
|
||||||
|
"link": "https://www.amazon.co.uk/Lanc%C3%B4me-Galateis-Douceur-Gentle-Cleanser/dp/B001BOJSEI?crid=WIPAM2F9PZPG&dib=eyJ2IjoiMSJ9.HTIGX5OZpBoGCtTyEu7UuI53G2BHaz-OIMnYQsYOa8F1RFS5onVCzGH8R3A9JO_1ve2rQsvgdPgQdYlJ4IQRGO8GXYsJxPoHXnhZ5UMyrPWWbCIzYF7snZ1XOmyVPh4n6zBxWFBM1EG4uORsUY9Yn_Vf7IDIQQRpNZ5R4uFjpSRzcCZMJ6ON1RkPEA5opwVPme3OoKYSjb6yZdtHVThB7dKBFuOs0Rr9dDUBbo9bWQGlNCaL_PDiaMveudD8sd6KTq1UFs-V88NYoNrMnvdUiC1lMYqhoaLNoUq5saM5lKs.-CK91cVYFQsClkNJ4IQ0ScgbE3aYCVHEBtB7WMFlUF4&dib_tag=se&keywords=lancome%2Bcleansing%2Bmilk&qid=1756760264&sprefix=lacome%2Bclean%2Caps%2C119&sr=8-6&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=f785eb3d283949baea415228347237e1&language=en_GB&ref_=as_li_ss_tl",
|
||||||
|
"img": "LancomeCreamCleanser.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Clinique Cleansing Balm",
|
||||||
|
"link": "https://www.amazon.co.uk/Clinique-Take-Cleansing-Balm-Types/dp/B07D5C86RX?crid=3A4R0135S7XQZ&dib=eyJ2IjoiMSJ9.HiQxgAv9CgW42sO0u4POmSS3c5sTfB5VBo6s4MqR8jACwAQ9rxFCpvXH2kepwmTTWEXJwnRN8FU1Wqb7Ebl2eX9e8AC9ebbR8wp2KADo0RPiC6DJrjqMALYdQNBwlkE1y3SiFLitaOd-DRkEIMq_K4TJD2zrs9zF1dbTqjo_bnvVS9qGLHM_0qAsw3UBCAUBg_TLJAoBuyGUhTypo6Xg5wOle3nEziitBvFwJbFNb1HkOkcPrFttUowQ_RTI04iLn4KtYZBYvVE5Sczun5XTNgKA6OFh20kgvnB1P9oKRSY.uTFVIk5iY9hJiwARoTeeHItvO6Mz5WE5xAMxz2ZEQVo&dib_tag=se&keywords=clinique+cleanser&qid=1756760426&sprefix=clinique+cl%2Caps%2C119&sr=8-1&linkCode=ll1&tag=verityjanebea-21&linkId=754dc784fa780a8a78c487c730ee46e8&language=en_GB&ref_=as_li_ss_tl",
|
||||||
|
"img": "CliniqueCleansingBalm.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bioderma Créaline H2O Original Micellar Water",
|
||||||
|
"link": "https://www.amazon.co.uk/Bioderma-Cr%C3%A9aline-Original-Micellar-Water/dp/B0BLY6KH7B?crid=2ADZP8LAVUSWS&dib=eyJ2IjoiMSJ9.1mFmzxDBe-CSXKcvfF3SsS-_ZZz3Y_QOFe-heXBW4Q79FG2PX9xYxUI0FnpuHutQ5iMgI9byGbISijclbGLAQpMXnMwrVcDSQ10Q75ZSnoqDbONXubbyq-Gg-HchvhNd5A-M49QjJQqnYpQhUw6utDngJJWqTAZa6dWNNIH1NDqRE5XxQQxadC9BAPczl7XE5t_NK3iKrK1-6LxKXrY413E2Uhy5iXACXtUJmIxXmoZw761_UPzsGzz-gmX2rO3A5zdDpHLytLBcw95N0OhBVuiRcWGSGmcaNuWUoOefVFs.pb4wRl_rCFVLgeUy8ybqm9wa1sK6wd036VwW-IdrYxU&dib_tag=se&keywords=bioderma+micellar+water&qid=1756760508&sprefix=bioderma+micellar+water%2Caps%2C89&sr=8-8&linkCode=ll1&tag=verityjanebea-21&linkId=899248b760a52cc6bd3e4dc5325e03b5&language=en_GB&ref_=as_li_ss_tl",
|
||||||
|
"img": "BiodermaWater.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Estée Lauder Nutritious Radiant Essence Lotion",
|
||||||
|
"img": "EsteeLauderEssence.png",
|
||||||
|
"link": "https://www.boots.com/est%C3%89e-lauder-nutritious-radiant-essence-lotion-200ml-10326057"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "d'alba Italian White Truffle First Spray Serum",
|
||||||
|
"img": "dalbaSerum.png",
|
||||||
|
"link": "https://www.amazon.co.uk/dalba-Piedmont-Italian-hydrating-surfactant/dp/B0BFQ9RD5B?crid=29A6895FIMLHU&dib=eyJ2IjoiMSJ9.Gr990brEvRdYIkXNUNCw-ygKEqrZhUvwkWZWz5ifuBqNev-HgYlnnR2w8gXQGxRVVMhSgZX5tLdVKF8CTUdkSpdUXw0cI75PzMaGM4OmwOWoNQAyXhoDtywn_UKQ4n9XxXQSZZyblFESOSQl-E5wPisKg2ysoiYkR27cvuaoHbn-OGv6YxN3Cxrb4_JF5dGAmWOBPsQxos5YPL931d7o5Uq4dm0MPARrVOZCq8heHB-mJPCQAmxsfxTaJui8OH4dL3nO2yy7gnYyTLn8Hnzn-odEk677ofp8ZXS5kHW5glc.xDxDHGFYm3SM2rv_y0cL9Jho7e2FrTNRupWphlnGU2Q&dib_tag=se&keywords=d%27alba%2Bfirst%2Bspray%2Bserum&qid=1756760767&sprefix=d%27alba%2B%2Caps%2C114&sr=8-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=768bf661561dc64585e62fd0b5f49c32&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Embryolisse - Lait Crème Sensitive",
|
||||||
|
"img": "LaitCreme.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Embryolisse-Milk-Cream-Sensitive-100ml/dp/B08Q6GLMPT?crid=R788VALQ97IV&dib=eyJ2IjoiMSJ9.8u97ASZlowkx50huyr-LLJS2qHY5sDd5-QS6cxoJdlDOkM0IkKzJV6hjoCycFO_Wlbza943qVXbBZOwMFvjG0mZEHrzbSDa9V9gS04NEf8nJ_RhWUg2OKqbb6vk6203MHISAYPBtKMOFV-oovFqjv0-YBaCjPxVeJHZIhQAOnnBBaCD0LOL482v0j2H-xLMdOO5dNorbxSOZPz7JUkwi2MCC9vDwOx7r76deva3CqLTDcRBbMjDjorQstuni0QzJziGWuicjMZ4Sxw1DgUPsG_i8wzUbrK1mYqeZaENRotI.DAywg2tnl9vMKwcfbRl_VRaFd0PwNGBfFC0EgNCtHh8&dib_tag=se&keywords=embryolisse+lait-cr%C3%A8me+concentr%C3%A9&qid=1756760850&rdc=1&sprefix=embr%2Caps%2C121&sr=8-4&linkCode=ll1&tag=verityjanebea-21&linkId=fb22b76a9347580eebfe3e63bcf9f40e&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bobbi Brown Hydrating Eye Cream",
|
||||||
|
"img": "BobbiBrownEyeCream.png",
|
||||||
|
"link": "https://www.boots.com/bobbi-brown-hydrating-eye-cream-15ml-10300638"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "No7 Radiance+ Illuminating Hydrogel Eye Masks",
|
||||||
|
"img": "No7EyeMask.png",
|
||||||
|
"link": "https://www.amazon.co.uk/No7-Radiance-Illuminating-Hydrogel-Masks/dp/B09VXZJRPQ?crid=1GK7RCHFDNW6T&dib=eyJ2IjoiMSJ9.Z0UPlmFwMT6qZLVGlkhQuPRZnv6Xf58Q-tDL33F0uw2ar44zHkt5awhj_xOFoFOJD9XoEcgwo9b54X5WxoDXfmTqQyW6AUBqv4wT-ybfiJlUjOuk2rQ2dhzeyw19LM-wjRqTv2I8SafNsWyn8qBwkYrYVvymTBJwL_aVH0i5z00bYTLUh0dC2ZG9ATdgwaOz4hBmUTfuq5Dbm45iwgGjLAQ0uvG9U5Iqml-_y-Hxsobttp9moQFrF0-lbtDDdPohud6_GLar8fyBbWzebWaeY7cHlZ1spl6SBgfDfhKeR04.h9fvo3-UDBi8_0rwCYMLxzNp21QO4FNy4BGBThCvkKg&dib_tag=se&keywords=no+7+eye+masks&qid=1756761074&sprefix=no+7+eyemasks%2Caps%2C95&sr=8-6&linkCode=ll1&tag=verityjanebea-21&linkId=824121e23744106101047ca616b991b8&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"left": 44,
|
||||||
|
"right": 41,
|
||||||
|
"title": "Eyes",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "Maybelline Fit Me! Concealer",
|
||||||
|
"img": "FitMe.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Maybelline-Fit-Concealer-Light-6-8/dp/B0046VJTX8?crid=346JCU58XS1VB&dib=eyJ2IjoiMSJ9.Le8DkHivEgnK2RsV8SCIk0_llWQG6Ijr3GB8saT0WZrvc14YI3qGAAkkCUzf4C-lyH1zD9vCCyNUYquO_ko1rlEZ51SxIFIXG_JlwsZOjjmKmhYzRiNDPsKyLz8mSCiJrboK7jlGk3q0kfbSsa2SinhhpKIMBOibS6IkIBHU8WdQZiZMZXW0YjlgsTjL-1oDeaVq0aCOq0P2dQkbYukXnZTfCjVDbT7ueAMcYnX7SFW_tKpX7OGYxxJscGXVuvySfz7ejL0vt0ieK1_n_sm_kqxzMjiR0XVXDzcBsjZj5T4.yZZkr85qTqBDcs1Rx62FH-YwcuE95ssgYRfoRsuv7xM&dib_tag=se&keywords=maybelline%2Bfit%2Bme%2Bconcealer&qid=1756761276&sprefix=maybelline%2Bfi%2Caps%2C130&sr=8-1&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=cb59a015c8228a65bc1d353207453a25&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Estee Lauder Double Wear 24H Waterproof Gel Eye Pencil",
|
||||||
|
"img": "DoubleWear.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Est%C3%A9e-Lauder-Double-Waterproof-Pencil/dp/B09T1CCLYC?crid=2LKUPFXEQAOAT&dib=eyJ2IjoiMSJ9.Oycx_PbHUAVdtF98MuEZ01idXDV3Dv6Q4ieRUY-aErqcMyhBIq1N7Cw0fVZHbmvToY8M-6H2E66jagwNJe7rHVvKBMLuDtC71KcnybmSbNO4llB_hPb5ojgNAuLdUWbQTEivUyDF1oCyNqkPD7BcHdY3bRxglbQ0pFWR0HP_g4a4NPaA2dX9AkokQeMswfDOGNGcUnFPsw6E0yXrUEk_PjNuvsTJN5x5-TTpv0SyFkvn_TvrYlUgpf5UMM7VUQlxRZDIjrtC8WMpUGUSVKHX0_81NcZhZBXid1PoHW3Qk2s.JqFSS9U9lEnxRsGRSr49YXjzcWevJRbI3H2ShfON_WY&dib_tag=se&keywords=estee%2Blauder%2Bdouble%2Bwear%2Beyeliner&qid=1756761344&rdc=1&sprefix=estee%2Blauder%2Bdouble%2Bwear%2Beye%2Caps%2C111&sr=8-4&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=bb68297ff04fd70ed53b1db57b6eb2fc&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "L'Oreal Paris Volumising Mascara",
|
||||||
|
"img": "VolumisingMascara.png",
|
||||||
|
"link": "https://www.amazon.co.uk/LOreal-Paris-Volumising-Clump-free-Sensitive/dp/B0CJ5GW8RY?crid=2YRH21CRUV6O4&dib=eyJ2IjoiMSJ9.MbLEw-p6QFMlgh1zKc1Jc01Ztt8-_PQr2TyF3EzBu1t_uW0Q9sJl07BQtyjuxNYyAvfpD-uhIt_mhRdHkcSKMoTT3HOUy_Km2JTiiefWct14PZNDMXZQA8Uq-3AguJiSUvPfp60CspbfijeqVjyq4PIvIYDkvvVvtnJaTZbhp_LKVFv3p5i2YCp_IG2yGvybhAD0kvW1YPUF2AOmfBvkA8NEWz96CUY8d_0caw6joWow799cc0CI-SRsgyWxuxuxs66RoSZKYkIXvdZuWd4n0xlSk6Mw5Cfn55UwXUaz1RM.FHLh43gugt8ohFXXaIYNzjFNqc_-ZNZti0_w9zslbdM&dib_tag=se&keywords=panorama%2Bmascara&qid=1756761449&sprefix=Panorama%2B%2Caps%2C118&sr=8-6&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=ef0a13ef0f0d685c62ddd3e5532de784&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Eyelash Curler",
|
||||||
|
"img": "EyelashCurler.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Wet-Wild-Eyelash-Curler-Comfort/dp/B08RRLJDGM?crid=20ZADKN2JGSG2&dib=eyJ2IjoiMSJ9.F9aWME0-uJ2ek9bJC8Lu5xBU4T0GB4pkMIuwkz1LZXW6NA7r6U2Dw1Z3hmS70u3szLxdcKTyabbC7EbNnfguTvfqM_Z4c6ex5sIHJrVvy7tIhjhevBJ42p5jI4_dCW9dmvcUSdahm2ShEsuRzgba9_W-HZz89sywQWfnxfzc7r3_j62s8xendYPEKB0xe55FgKK0V6tHOhIqoMe79au6eTOv2L9-QL3kBuCLBQ4AnG72FblLtSe__3kZeyMX5r-QtU34edWuN3Hdv8_kR7wUE_1p5IdvwldLfvWfGN2L7X4.Ni3dgpxyja0oeyxneqp8ZuwOWhMEOnfl6uvzFh51H14&dib_tag=se&keywords=eyelash%2Bcurler&qid=1756761513&sprefix=eyelash%2Bcurler%2Caps%2C117&sr=8-8&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=3fd66a2c8b605ff784ea2c71b1997b16&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"left": 60,
|
||||||
|
"right": 38,
|
||||||
|
"title": "Brows",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "L'Oréal Paris Brow Lamination Gel ",
|
||||||
|
"img": "BrowLamination.png",
|
||||||
|
"link": "https://www.amazon.co.uk/LOr%C3%A9al-Paris-Lamination-Lightweight-Opthalmologically/dp/B0CQ3373JW?crid=7AZ1MSAGKBCQ&dib=eyJ2IjoiMSJ9.SRhJx6vvik2BkEovM6u9v4rWOwh5ZAPc4ULO6XiLEEcybeKMeWZOpredDLGxfRDGXUm-1OVVFwJ0ZkLrlJKvXm7yChwyztTIXBMtlIzm-baDPm0Q8rPw0Tbj7gVaFtOOXxZPufphJHbB0nvK6xHQ1a4ZpCYzo7qBLfKmpeN22bAsyAxzr4h-O_G2-9uvEadTo1hbl2ceHBAUACgIFftEKRHGkEChvcEjYEi9_j-pbg3f-H_ODVaPeVDxYp2vrwe9MYoDJ_l9ztvqEnyxXRzeVxQbNs3uBEXJB5uTx_gPz3w.dANmI2Mvj6ZHIyVnzIU9Y-yIJk5JM74XDgJTueSipiY&dib_tag=se&keywords=loreal%2Bbrow%2Blamination&qid=1756761681&sprefix=loreal%2Bbrow%2Bl%2Caps%2C109&sr=8-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=388f7e48674e2595f947be8d4836c5be&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"left": 52,
|
||||||
|
"right": 55,
|
||||||
|
"title": "Complexion",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "Maybelline Makeup Primer ",
|
||||||
|
"img": "MakeupPrimer.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Maybelline-New-York-Ultra-Blendable-Water-based/dp/B0DNT5HBHB?crid=3L7WO25EXOTBC&dib=eyJ2IjoiMSJ9.baoXMGRAEirOXFDGyc_5Apwh-lh3q0WihBRwEXk_CYv0PItsLnu11RTNNF9vjhMV_vwqDuhhSmuVkmvsW1b9h3tvk2bXLEGf_swvr1sPa70P-QH5Vh0lwCRPo-OWlxHORjDfvaOMrOq24HFS-I1ooCj-mgN5eDAmU3kTFK6bfsaQLGyW6nrLv09mS7sqB8QfHY-qyVQsi83u0afWoCwE1dN8SpyjX5ghexU0WtletWQldNPDCc1Xe1yK-vUbx7XqALRB_XaclYkuwYWxL3H00-7hLuNnv0xQmIDfbZTtMm4.GKedJZkZJZKX_4A7KQ7qWD8q3K-Vs5muP1y5XrfavnY&dib_tag=se&keywords=maybelline+grippy+primer&qid=1756761867&sprefix=maybelline+grip%2Caps%2C109&sr=8-1&linkCode=ll1&tag=verityjanebea-21&linkId=6c8619577ecefefbd18b0a91e7a62e88&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "L'Oréal Paris Infaillible 32H Liquid Foundation",
|
||||||
|
"img": "InfaillibleFoundation.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Infaillible-Long-Lasting-Protection-Function-Flawless/dp/B08PF9XJ3L?crid=3PHAD7YY4RK3&dib=eyJ2IjoiMSJ9.G6fkoKMm1E18k_de417EG_DDw94bGaNl6NhXuaxANrclCDPHsd1OFL2e63tTeVMvAG60kzaehYIbiR4Sjd5ewZ1oTEDYc3cNq6tzucD6zAlwKPIu8Kxt8HvyNxRintHPQ5rSulVKtSFG_HrVEKU3OgIyn0CLyuEl9oQpsGgasi7gPMcPZXVPImrbNptztrF69lWSKv7GcI2N_aPoTvE3uzZJruy2lQHV48ZB6mm84Wh5fKmRpCR4bI-3cXMsEB4cnYiE3fhwP96hq76Y1G-_0pdNR0RQOP8HKB_L1P8kEao.tgNJJZNtv38ipZG1oSA1L1dHeWbtF9E8sh_tAZme8X8&dib_tag=se&keywords=loreal%2Binfallible%2B32%2Bhour%2Bfoundation&qid=1756761924&sprefix=loreal%2Binfallible%2B32%2Bhour%2Bfoundation%2Caps%2C108&sr=8-9&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=6ee37816395de02449298271b2c30b13&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HUDA BEAUTY Easy Bake Loose Baking & Setting Powder Sugar",
|
||||||
|
"img": "SettingPowder.png",
|
||||||
|
"link": "https://www.amazon.co.uk/BEAUTY-Baking-Setting-Powder-Cookie/dp/B07GQ2YGVJ?dib=eyJ2IjoiMSJ9.EF6PVSVLdZK5CHDGmLocSp_SzUM9kMaNTox0jVsekm3j3aPr5mBLmH5LcEcbRLaOS9H-5dMvl6PY4ZqJZO2g4JRv_4fX8sNp7Ilvz8lMvR1PpViJGKdHOEIfA_OMl_i3u1CJlHYJ5uoUja7Soj6DlkNIMHBfVAzNL7Z5tcffZ5BZK_HJplcAZWxLr0lySn_qqAi02_qCW7nAdxfJCa5fA9jrBIcUjxi0ffdJxQCk0Ph6dQfVYoBzDfy0ilNzUuuBLRopVrqjsY8Sw7CZ59_tw578N9DZEq22s-eIZkHXJck.nedvMK_Uk-JH7T3oXkWtWpzieh_x7-3l0v8aGDv9EqY&dib_tag=se&qid=1756762102&refinements=p_89%3AHuda&sr=8-25&srs=18527346031&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=b979526f7fa0acad69e806cf22ae0479&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "L'Oréal Paris Setting Spray",
|
||||||
|
"img": "InfaillibleSpray.png",
|
||||||
|
"link": "https://www.amazon.co.uk/dp/B0CNQ4DJRV?aref=YUMJJiypco&aaxitk=1798f7b9e833dfdbdeec8c0652913699&pd_rd_plhdr=t&smid=A3P5ROKL5A1OLE&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=0c5c2dc69376cf37770af91536c83a98&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"left": 41,
|
||||||
|
"right": 48,
|
||||||
|
"title": "Contour & Blush",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "W7 Honolulu Bronzing Powder",
|
||||||
|
"img": "W7Primer.png",
|
||||||
|
"link": "https:////www.amazon.co.uk/W7-Bronzer-Honolulu/dp/B004KM1J5E?crid=3BXR48UJFFHZ2&dib=eyJ2IjoiMSJ9.Ggw2IBEST_2xZ5sEaa38bPlYyzxUnsgra3OIWCVfvryZO9mY-pCzZ_rTuR7nAx41287MlS77vRzVMx38HoPfk0ydBRP-kC25hL02dWIRdbwXBJ9G6leIOGPY3mi0HRzdgF2Ax10ezG9gG4_R868BgxKZ-S9vAxJJ16ooJE18l9NIsoZWPYyt1B8e7J06G04u3w4uTiXk93GMvVoUyl6CFfILOQg6hgPDXJHnb1NyeCU7BY2b_jKdUY3bzNMeGc9Zl0aLdzPmMu31iqs5xtyrykavCs-Wv_0hK7TCFg29VJ0.XxVZfiQ3uPpsyigbjCWMvYgKjg5VvOywXbr5myydoQ4&dib_tag=se&keywords=honolulu%2Bbronzer%2Bw7&qid=1756762346&sprefix=honolulu%2Bbronzer%2Caps%2C133&sr=8-1&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=a296b7c8d61ad1129733e36ba86b9120&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Morphe Hot Shot Blush Drops",
|
||||||
|
"img": "Morphe.png",
|
||||||
|
"link": "https:////www.boots.com/morphe-hot-shot-blush-drops-15ml-10350578"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rimmel London Lasting Finish Soft Colour Powder Blush",
|
||||||
|
"img": "RimmelBlush.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Rimmel-London-Lasting-Finish-Colour/dp/B009ACJZAK?crid=399TN0HQB34UY&dib=eyJ2IjoiMSJ9.YthZXCJ7F7wHdCbzKUSvAsNTioewzBleZgWHlM-d6BtktozTulKMvTUOQLFhLGVubQB360P3tS3IMcz9MbWmDDP8tffbnSlwAxcGTrIPMqb2F7fZcvrWOJq8QqVJ6ZeaXpRsL-IHA5wzrGnZ_JUfI03km7fh5qGEF64qPbPvnlREHNCdsmNowdIuDJwtnZ7VYmjYbM47_Mc2hy0GwqreFJ_JDgiVavaMwUu9BSrfxkdyYFt83xR1f7mmEwkpA17PwI6eVQSXrSUAjr8UJ4J6jPrjYFf5-eX1sBLtEVo2P6k.BQwkSu8VCtf-oFi2Tx674qRPVafQC_2a-w1FLKySNjw&dib_tag=se&keywords=rimmel%2Bblusher%2Bpowder&qid=1756762507&sprefix=rimmel%2Bblusher%2Bp%2Caps%2C119&sr=8-17&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=dbb4a8c105f64e19c8e115eba1ecbcd3&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Revolution Highlight Reloaded",
|
||||||
|
"img": "RevolutionHighlight.png",
|
||||||
|
"link": "https://www.amazon.co.uk/Revolution-Highlighter-Reloaded-Just-Type/dp/B07QPZH86C?crid=2K0PK9HUFF5O6&dib=eyJ2IjoiMSJ9.mOGXegs1a5ZmvcNVFYSl7nqUPa00fU2PVvIDC7Z0xuvfAIinuEx3IB_2qgV7maaJZLLoDDEyuBnPDnjjwcKnvuT-gSYvR1AJPQkI2xACLvVtjjpzTgvphlp8mJEVDjU8qjL-htEH3lyye0CXCJF8CFV_9-os6LPOTBnhOGftzEACDAjc4Zc_vAQ9y5GyGgqv2_l-gQEzZKjDjPfUxBwVk_mKR1Rs13LhPDbTf63CD0WEvXxX69ZOI7Ga1de_KKEslr1LroIAz4fLu45Y6rNcF8Ie7L2Om7mjhAGLr6q36rk.x0t_usKkIp6YBJjDC4rhn8947XemU-eCaZUwxN2W4nk&dib_tag=se&keywords=revolution%2Bhighlighter&qid=1756762587&sprefix=Revolution%2Bhigh%2Caps%2C109&sr=8-1&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=e3d8a300b33db85d2457462812695416&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"left": 52,
|
||||||
|
"right": 51,
|
||||||
|
"title": "Contour & Blush",
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "17. Lip Define Pencil Soft Liner",
|
||||||
|
"img": "LipDefine.png",
|
||||||
|
"link": "https://www.boots.com/17-lip-define-pencil-soft-liner-10306930"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "17. Lacquer Gloss",
|
||||||
|
"img": "LaquerGloss.png",
|
||||||
|
"link": "https:////www.boots.com/17-lacquer-gloss-10306929"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
35
src/components/hotspots.txt
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"id":1,
|
||||||
|
"left":50,
|
||||||
|
"right":35,
|
||||||
|
"title":"Skincare",
|
||||||
|
"description":"Cleanser",
|
||||||
|
3 products to go here
|
||||||
|
Cleanser - "Lancome Cream Cleanser - link - https://www.amazon.co.uk/Lanc%C3%B4me-Galateis-Douceur-Gentle-Cleanser/dp/B001BOJSEI?crid=WIPAM2F9PZPG&dib=eyJ2IjoiMSJ9.HTIGX5OZpBoGCtTyEu7UuI53G2BHaz-OIMnYQsYOa8F1RFS5onVCzGH8R3A9JO_1ve2rQsvgdPgQdYlJ4IQRGO8GXYsJxPoHXnhZ5UMyrPWWbCIzYF7snZ1XOmyVPh4n6zBxWFBM1EG4uORsUY9Yn_Vf7IDIQQRpNZ5R4uFjpSRzcCZMJ6ON1RkPEA5opwVPme3OoKYSjb6yZdtHVThB7dKBFuOs0Rr9dDUBbo9bWQGlNCaL_PDiaMveudD8sd6KTq1UFs-V88NYoNrMnvdUiC1lMYqhoaLNoUq5saM5lKs.-CK91cVYFQsClkNJ4IQ0ScgbE3aYCVHEBtB7WMFlUF4&dib_tag=se&keywords=lancome%2Bcleansing%2Bmilk&qid=1756760264&sprefix=lacome%2Bclean%2Caps%2C119&sr=8-6&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=f785eb3d283949baea415228347237e1&language=en_GB&ref_=as_li_ss_tl"
|
||||||
|
Clinique Cleansing Balm - https://www.amazon.co.uk/Clinique-Take-Cleansing-Balm-Types/dp/B07D5C86RX?crid=3A4R0135S7XQZ&dib=eyJ2IjoiMSJ9.HiQxgAv9CgW42sO0u4POmSS3c5sTfB5VBo6s4MqR8jACwAQ9rxFCpvXH2kepwmTTWEXJwnRN8FU1Wqb7Ebl2eX9e8AC9ebbR8wp2KADo0RPiC6DJrjqMALYdQNBwlkE1y3SiFLitaOd-DRkEIMq_K4TJD2zrs9zF1dbTqjo_bnvVS9qGLHM_0qAsw3UBCAUBg_TLJAoBuyGUhTypo6Xg5wOle3nEziitBvFwJbFNb1HkOkcPrFttUowQ_RTI04iLn4KtYZBYvVE5Sczun5XTNgKA6OFh20kgvnB1P9oKRSY.uTFVIk5iY9hJiwARoTeeHItvO6Mz5WE5xAMxz2ZEQVo&dib_tag=se&keywords=clinique+cleanser&qid=1756760426&sprefix=clinique+cl%2Caps%2C119&sr=8-1&linkCode=ll1&tag=verityjanebea-21&linkId=754dc784fa780a8a78c487c730ee46e8&language=en_GB&ref_=as_li_ss_tl
|
||||||
|
Bioderma Créaline H2O Original Micellar Water - https://www.amazon.co.uk/Bioderma-Cr%C3%A9aline-Original-Micellar-Water/dp/B0BLY6KH7B?crid=2ADZP8LAVUSWS&dib=eyJ2IjoiMSJ9.1mFmzxDBe-CSXKcvfF3SsS-_ZZz3Y_QOFe-heXBW4Q79FG2PX9xYxUI0FnpuHutQ5iMgI9byGbISijclbGLAQpMXnMwrVcDSQ10Q75ZSnoqDbONXubbyq-Gg-HchvhNd5A-M49QjJQqnYpQhUw6utDngJJWqTAZa6dWNNIH1NDqRE5XxQQxadC9BAPczl7XE5t_NK3iKrK1-6LxKXrY413E2Uhy5iXACXtUJmIxXmoZw761_UPzsGzz-gmX2rO3A5zdDpHLytLBcw95N0OhBVuiRcWGSGmcaNuWUoOefVFs.pb4wRl_rCFVLgeUy8ybqm9wa1sK6wd036VwW-IdrYxU&dib_tag=se&keywords=bioderma+micellar+water&qid=1756760508&sprefix=bioderma+micellar+water%2Caps%2C89&sr=8-8&linkCode=ll1&tag=verityjanebea-21&linkId=899248b760a52cc6bd3e4dc5325e03b5&language=en_GB&ref_=as_li_ss_tl
|
||||||
|
Estée Lauder Nutritious Radiant Essence Lotion - https://www.boots.com/est%C3%89e-lauder-nutritious-radiant-essence-lotion-200ml-10326057
|
||||||
|
d'alba Italian White Truffle First Spray Serum -https://www.amazon.co.uk/dalba-Piedmont-Italian-hydrating-surfactant/dp/B0BFQ9RD5B?crid=29A6895FIMLHU&dib=eyJ2IjoiMSJ9.Gr990brEvRdYIkXNUNCw-ygKEqrZhUvwkWZWz5ifuBqNev-HgYlnnR2w8gXQGxRVVMhSgZX5tLdVKF8CTUdkSpdUXw0cI75PzMaGM4OmwOWoNQAyXhoDtywn_UKQ4n9XxXQSZZyblFESOSQl-E5wPisKg2ysoiYkR27cvuaoHbn-OGv6YxN3Cxrb4_JF5dGAmWOBPsQxos5YPL931d7o5Uq4dm0MPARrVOZCq8heHB-mJPCQAmxsfxTaJui8OH4dL3nO2yy7gnYyTLn8Hnzn-odEk677ofp8ZXS5kHW5glc.xDxDHGFYm3SM2rv_y0cL9Jho7e2FrTNRupWphlnGU2Q&dib_tag=se&keywords=d%27alba%2Bfirst%2Bspray%2Bserum&qid=1756760767&sprefix=d%27alba%2B%2Caps%2C114&sr=8-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=768bf661561dc64585e62fd0b5f49c32&language=en_GB&ref_=as_li_ss_tl
|
||||||
|
Embryolisse - Lait Crème Sensitive - https://www.amazon.co.uk/Embryolisse-Milk-Cream-Sensitive-100ml/dp/B08Q6GLMPT?crid=R788VALQ97IV&dib=eyJ2IjoiMSJ9.8u97ASZlowkx50huyr-LLJS2qHY5sDd5-QS6cxoJdlDOkM0IkKzJV6hjoCycFO_Wlbza943qVXbBZOwMFvjG0mZEHrzbSDa9V9gS04NEf8nJ_RhWUg2OKqbb6vk6203MHISAYPBtKMOFV-oovFqjv0-YBaCjPxVeJHZIhQAOnnBBaCD0LOL482v0j2H-xLMdOO5dNorbxSOZPz7JUkwi2MCC9vDwOx7r76deva3CqLTDcRBbMjDjorQstuni0QzJziGWuicjMZ4Sxw1DgUPsG_i8wzUbrK1mYqeZaENRotI.DAywg2tnl9vMKwcfbRl_VRaFd0PwNGBfFC0EgNCtHh8&dib_tag=se&keywords=embryolisse+lait-cr%C3%A8me+concentr%C3%A9&qid=1756760850&rdc=1&sprefix=embr%2Caps%2C121&sr=8-4&linkCode=ll1&tag=verityjanebea-21&linkId=fb22b76a9347580eebfe3e63bcf9f40e&language=en_GB&ref_=as_li_ss_tl
|
||||||
|
Bobbi Brown Hydrating Eye Cream - https://www.boots.com/bobbi-brown-hydrating-eye-cream-15ml-10300638
|
||||||
|
No7 Radiance+ Illuminating Hydrogel Eye Masks - https://www.amazon.co.uk/No7-Radiance-Illuminating-Hydrogel-Masks/dp/B09VXZJRPQ?crid=1GK7RCHFDNW6T&dib=eyJ2IjoiMSJ9.Z0UPlmFwMT6qZLVGlkhQuPRZnv6Xf58Q-tDL33F0uw2ar44zHkt5awhj_xOFoFOJD9XoEcgwo9b54X5WxoDXfmTqQyW6AUBqv4wT-ybfiJlUjOuk2rQ2dhzeyw19LM-wjRqTv2I8SafNsWyn8qBwkYrYVvymTBJwL_aVH0i5z00bYTLUh0dC2ZG9ATdgwaOz4hBmUTfuq5Dbm45iwgGjLAQ0uvG9U5Iqml-_y-Hxsobttp9moQFrF0-lbtDDdPohud6_GLar8fyBbWzebWaeY7cHlZ1spl6SBgfDfhKeR04.h9fvo3-UDBi8_0rwCYMLxzNp21QO4FNy4BGBThCvkKg&dib_tag=se&keywords=no+7+eye+masks&qid=1756761074&sprefix=no+7+eyemasks%2Caps%2C95&sr=8-6&linkCode=ll1&tag=verityjanebea-21&linkId=824121e23744106101047ca616b991b8&language=en_GB&ref_=as_li_ss_tl
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"id":2,
|
||||||
|
"left":44,
|
||||||
|
"right":41,
|
||||||
|
"title":"Eyes
|
||||||
|
"description":""
|
||||||
|
Maybelline Fit Me! Concealer - https://www.amazon.co.uk/Maybelline-Fit-Concealer-Light-6-8/dp/B0046VJTX8?crid=346JCU58XS1VB&dib=eyJ2IjoiMSJ9.Le8DkHivEgnK2RsV8SCIk0_llWQG6Ijr3GB8saT0WZrvc14YI3qGAAkkCUzf4C-lyH1zD9vCCyNUYquO_ko1rlEZ51SxIFIXG_JlwsZOjjmKmhYzRiNDPsKyLz8mSCiJrboK7jlGk3q0kfbSsa2SinhhpKIMBOibS6IkIBHU8WdQZiZMZXW0YjlgsTjL-1oDeaVq0aCOq0P2dQkbYukXnZTfCjVDbT7ueAMcYnX7SFW_tKpX7OGYxxJscGXVuvySfz7ejL0vt0ieK1_n_sm_kqxzMjiR0XVXDzcBsjZj5T4.yZZkr85qTqBDcs1Rx62FH-YwcuE95ssgYRfoRsuv7xM&dib_tag=se&keywords=maybelline%2Bfit%2Bme%2Bconcealer&qid=1756761276&sprefix=maybelline%2Bfi%2Caps%2C130&sr=8-1&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=cb59a015c8228a65bc1d353207453a25&language=en_GB&ref_=as_li_ss_tl
|
||||||
|
Estee Lauder Double Wear 24H Waterproof Gel Eye Pencil - https://www.amazon.co.uk/Est%C3%A9e-Lauder-Double-Waterproof-Pencil/dp/B09T1CCLYC?crid=2LKUPFXEQAOAT&dib=eyJ2IjoiMSJ9.Oycx_PbHUAVdtF98MuEZ01idXDV3Dv6Q4ieRUY-aErqcMyhBIq1N7Cw0fVZHbmvToY8M-6H2E66jagwNJe7rHVvKBMLuDtC71KcnybmSbNO4llB_hPb5ojgNAuLdUWbQTEivUyDF1oCyNqkPD7BcHdY3bRxglbQ0pFWR0HP_g4a4NPaA2dX9AkokQeMswfDOGNGcUnFPsw6E0yXrUEk_PjNuvsTJN5x5-TTpv0SyFkvn_TvrYlUgpf5UMM7VUQlxRZDIjrtC8WMpUGUSVKHX0_81NcZhZBXid1PoHW3Qk2s.JqFSS9U9lEnxRsGRSr49YXjzcWevJRbI3H2ShfON_WY&dib_tag=se&keywords=estee%2Blauder%2Bdouble%2Bwear%2Beyeliner&qid=1756761344&rdc=1&sprefix=estee%2Blauder%2Bdouble%2Bwear%2Beye%2Caps%2C111&sr=8-4&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=bb68297ff04fd70ed53b1db57b6eb2fc&language=en_GB&ref_=as_li_ss_tl
|
||||||
|
L'Oreal Paris Volumising Mascara - https://www.amazon.co.uk/LOreal-Paris-Volumising-Clump-free-Sensitive/dp/B0CJ5GW8RY?crid=2YRH21CRUV6O4&dib=eyJ2IjoiMSJ9.MbLEw-p6QFMlgh1zKc1Jc01Ztt8-_PQr2TyF3EzBu1t_uW0Q9sJl07BQtyjuxNYyAvfpD-uhIt_mhRdHkcSKMoTT3HOUy_Km2JTiiefWct14PZNDMXZQA8Uq-3AguJiSUvPfp60CspbfijeqVjyq4PIvIYDkvvVvtnJaTZbhp_LKVFv3p5i2YCp_IG2yGvybhAD0kvW1YPUF2AOmfBvkA8NEWz96CUY8d_0caw6joWow799cc0CI-SRsgyWxuxuxs66RoSZKYkIXvdZuWd4n0xlSk6Mw5Cfn55UwXUaz1RM.FHLh43gugt8ohFXXaIYNzjFNqc_-ZNZti0_w9zslbdM&dib_tag=se&keywords=panorama%2Bmascara&qid=1756761449&sprefix=Panorama%2B%2Caps%2C118&sr=8-6&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=ef0a13ef0f0d685c62ddd3e5532de784&language=en_GB&ref_=as_li_ss_tl
|
||||||
|
Eyelash curler - https://www.amazon.co.uk/Wet-Wild-Eyelash-Curler-Comfort/dp/B08RRLJDGM?crid=20ZADKN2JGSG2&dib=eyJ2IjoiMSJ9.F9aWME0-uJ2ek9bJC8Lu5xBU4T0GB4pkMIuwkz1LZXW6NA7r6U2Dw1Z3hmS70u3szLxdcKTyabbC7EbNnfguTvfqM_Z4c6ex5sIHJrVvy7tIhjhevBJ42p5jI4_dCW9dmvcUSdahm2ShEsuRzgba9_W-HZz89sywQWfnxfzc7r3_j62s8xendYPEKB0xe55FgKK0V6tHOhIqoMe79au6eTOv2L9-QL3kBuCLBQ4AnG72FblLtSe__3kZeyMX5r-QtU34edWuN3Hdv8_kR7wUE_1p5IdvwldLfvWfGN2L7X4.Ni3dgpxyja0oeyxneqp8ZuwOWhMEOnfl6uvzFh51H14&dib_tag=se&keywords=eyelash%2Bcurler&qid=1756761513&sprefix=eyelash%2Bcurler%2Caps%2C117&sr=8-8&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=3fd66a2c8b605ff784ea2c71b1997b16&language=en_GB&ref_=as_li_ss_tl
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"id":3,
|
||||||
|
"left":60,
|
||||||
|
"right":38,
|
||||||
|
"title":"brows"
|
||||||
|
"description":""
|
||||||
|
L'Oréal Paris Brow Lamination Gel - https://www.amazon.co.uk/LOr%C3%A9al-Paris-Lamination-Lightweight-Opthalmologically/dp/B0CQ3373JW?crid=7AZ1MSAGKBCQ&dib=eyJ2IjoiMSJ9.SRhJx6vvik2BkEovM6u9v4rWOwh5ZAPc4ULO6XiLEEcybeKMeWZOpredDLGxfRDGXUm-1OVVFwJ0ZkLrlJKvXm7yChwyztTIXBMtlIzm-baDPm0Q8rPw0Tbj7gVaFtOOXxZPufphJHbB0nvK6xHQ1a4ZpCYzo7qBLfKmpeN22bAsyAxzr4h-O_G2-9uvEadTo1hbl2ceHBAUACgIFftEKRHGkEChvcEjYEi9_j-pbg3f-H_ODVaPeVDxYp2vrwe9MYoDJ_l9ztvqEnyxXRzeVxQbNs3uBEXJB5uTx_gPz3w.dANmI2Mvj6ZHIyVnzIU9Y-yIJk5JM74XDgJTueSipiY&dib_tag=se&keywords=loreal%2Bbrow%2Blamination&qid=1756761681&sprefix=loreal%2Bbrow%2Bl%2Caps%2C109&sr=8-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&th=1&linkCode=ll1&tag=verityjanebea-21&linkId=388f7e48674e2595f947be8d4836c5be&language=en_GB&ref_=as_li_ss_tl
|
||||||
|
}
|
1
src/favicon.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 163 163"><path fill="#339AF0" d="M162.162 81.5c0-45.011-36.301-81.5-81.08-81.5C36.301 0 0 36.489 0 81.5 0 126.51 36.301 163 81.081 163s81.081-36.49 81.081-81.5z"/><path fill="#fff" d="M65.983 43.049a6.234 6.234 0 00-.336 6.884 6.14 6.14 0 001.618 1.786c9.444 7.036 14.866 17.794 14.866 29.52 0 11.726-5.422 22.484-14.866 29.52a6.145 6.145 0 00-1.616 1.786 6.21 6.21 0 00-.694 4.693 6.21 6.21 0 001.028 2.186 6.151 6.151 0 006.457 2.319 6.154 6.154 0 002.177-1.035 50.083 50.083 0 007.947-7.39h17.493c3.406 0 6.174-2.772 6.174-6.194s-2.762-6.194-6.174-6.194h-9.655a49.165 49.165 0 004.071-19.69 49.167 49.167 0 00-4.07-19.692h9.66c3.406 0 6.173-2.771 6.173-6.194 0-3.422-2.762-6.193-6.173-6.193H82.574a50.112 50.112 0 00-7.952-7.397 6.15 6.15 0 00-4.578-1.153 6.189 6.189 0 00-4.055 2.438h-.006z"/><path fill="#fff" fill-rule="evenodd" d="M56.236 79.391a9.342 9.342 0 01.632-3.608 9.262 9.262 0 011.967-3.077 9.143 9.143 0 012.994-2.063 9.06 9.06 0 017.103 0 9.145 9.145 0 012.995 2.063 9.262 9.262 0 011.967 3.077 9.339 9.339 0 01-2.125 10.003 9.094 9.094 0 01-6.388 2.63 9.094 9.094 0 01-6.39-2.63 9.3 9.3 0 01-2.755-6.395z" clip-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -1,68 +0,0 @@
|
|||||||
/* :root {
|
|
||||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
||||||
line-height: 1.5;
|
|
||||||
font-weight: 400;
|
|
||||||
|
|
||||||
color-scheme: light dark;
|
|
||||||
color: rgba(255, 255, 255, 0.87);
|
|
||||||
background-color: #242424;
|
|
||||||
|
|
||||||
font-synthesis: none;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #646cff;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #535bf2;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
display: flex;
|
|
||||||
place-items: center;
|
|
||||||
min-width: 320px;
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 3.2em;
|
|
||||||
line-height: 1.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 0.6em 1.2em;
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: 500;
|
|
||||||
font-family: inherit;
|
|
||||||
background-color: #1a1a1a;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: border-color 0.25s;
|
|
||||||
}
|
|
||||||
button:hover {
|
|
||||||
border-color: #646cff;
|
|
||||||
}
|
|
||||||
button:focus,
|
|
||||||
button:focus-visible {
|
|
||||||
outline: 4px auto -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
|
||||||
:root {
|
|
||||||
color: #213547;
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #747bff;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
}
|
|
||||||
} */
|
|
12
src/main.jsx
@ -1,10 +1,4 @@
|
|||||||
import { StrictMode } from 'react'
|
import ReactDOM from 'react-dom/client';
|
||||||
import { createRoot } from 'react-dom/client'
|
import App from './App';
|
||||||
// import './index.css'
|
|
||||||
import App from './App.jsx'
|
|
||||||
|
|
||||||
createRoot(document.getElementById('root')).render(
|
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
|
||||||
<StrictMode>
|
|
||||||
<App />
|
|
||||||
</StrictMode>,
|
|
||||||
)
|
|
||||||
|
5
src/theme.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { createTheme } from '@mantine/core';
|
||||||
|
|
||||||
|
export const theme = createTheme({
|
||||||
|
/** Put your mantine theme override here */
|
||||||
|
});
|
1
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
5
test-utils/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
|
export * from '@testing-library/react';
|
||||||
|
export { render } from './render';
|
||||||
|
export { userEvent };
|
13
test-utils/render.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { render as testingLibraryRender } from '@testing-library/react';
|
||||||
|
import { MantineProvider } from '@mantine/core';
|
||||||
|
import { theme } from '../src/theme';
|
||||||
|
|
||||||
|
export function render(ui: React.ReactNode) {
|
||||||
|
return testingLibraryRender(ui, {
|
||||||
|
wrapper: ({ children }: { children: React.ReactNode }) => (
|
||||||
|
<MantineProvider theme={theme} env="test">
|
||||||
|
{children}
|
||||||
|
</MantineProvider>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
25
tsconfig.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": ["node", "@testing-library/jest-dom", "vitest/globals"],
|
||||||
|
"target": "ESNext",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
|
"allowJs": false,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": false,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"],
|
||||||
|
"@test-utils": ["./test-utils"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["src", "test-utils"]
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
import { defineConfig } from 'vite'
|
|
||||||
import react from '@vitejs/plugin-react'
|
|
||||||
|
|
||||||
// https://vite.dev/config/
|
|
||||||
export default defineConfig({
|
|
||||||
plugins: [react()],
|
|
||||||
})
|
|
12
vite.config.mjs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react(), tsconfigPaths()],
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
setupFiles: './vitest.setup.mjs',
|
||||||
|
},
|
||||||
|
});
|
28
vitest.setup.mjs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import '@testing-library/jest-dom/vitest';
|
||||||
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
|
const { getComputedStyle } = window;
|
||||||
|
window.getComputedStyle = (elt) => getComputedStyle(elt);
|
||||||
|
window.HTMLElement.prototype.scrollIntoView = () => {};
|
||||||
|
|
||||||
|
Object.defineProperty(window, 'matchMedia', {
|
||||||
|
writable: true,
|
||||||
|
value: vi.fn().mockImplementation((query) => ({
|
||||||
|
matches: false,
|
||||||
|
media: query,
|
||||||
|
onchange: null,
|
||||||
|
addListener: vi.fn(),
|
||||||
|
removeListener: vi.fn(),
|
||||||
|
addEventListener: vi.fn(),
|
||||||
|
removeEventListener: vi.fn(),
|
||||||
|
dispatchEvent: vi.fn(),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
class ResizeObserver {
|
||||||
|
observe() {}
|
||||||
|
unobserve() {}
|
||||||
|
disconnect() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.ResizeObserver = ResizeObserver;
|