5 Commits

Author SHA1 Message Date
DwCay
bfdddee46a Add method for get passPhrase and generation hex for account logo 2022-06-18 16:50:32 +03:00
kandrusyak
0da68ddd63 migrate to webpack 2022-06-17 16:56:30 +03:00
DwCay
eeaabeebf3 Add method for get passPhrase 2022-06-15 17:41:02 +03:00
DwCay
da04efbf80 Add registration store 2022-06-14 13:13:58 +03:00
DuCay
541c5988e9 Merge pull request #20 from franze6/Deleting_elements
Delete Onboarding and Component from Sidebar
2022-06-02 15:53:43 +03:00
21 changed files with 12497 additions and 1251 deletions

View File

@@ -1,26 +0,0 @@
# Mosaic React
React landing page template designed by Cruip.
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run dev
```
### Compiles and minifies for production
```
npm run build
```
### Customize configuration
See [Configuration Reference](https://vitejs.dev/guide/).
## Support notes
We are shipping our templates with a very basic React configuration to let you quickly get into the development process, but we don't discourage you from using any other configuration or framework built on the top of React. So, please note that any request dealing with React (e.g. extra features, customisations, et cetera) is to be considered out of the support scope.
For more information about what support covers, please see our (FAQs)[https://cruip.com/faq/].

View File

@@ -1,21 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body class="font-inter antialiased bg-slate-100 text-slate-600">
<noscript>You need to enable JavaScript to run this app.</noscript>
<script>
if (localStorage.getItem('sidebar-expanded') == 'true') {
document.querySelector('body').classList.add('sidebar-expanded');
} else {
document.querySelector('body').classList.remove('sidebar-expanded');
}
</script>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

13260
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,27 +2,60 @@
"name": "mosaic-react",
"version": "0.1.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
"dev": "webpack-dev-server",
"build": "webpack"
},
"dependencies": {
"@liskhq/lisk-client": "^5.2.2",
"@tailwindcss/forms": "^0.4.0",
"autoprefixer": "^10.4.5",
"buffer": "^6.0.3",
"chart.js": "^3.5.0",
"chartjs-adapter-moment": "^1.0.0",
"crypto-browserify": "^3.12.0",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"mobx": "^6.6.0",
"mobx-react-lite": "^3.4.0",
"moment": "^2.29.1",
"net": "^1.0.2",
"os-browserify": "^0.3.0",
"path-browserify": "^1.0.1",
"postcss-loader": "^7.0.0",
"process": "^0.11.10",
"querystring-es3": "^0.2.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-flatpickr": "^3.10.7",
"react-router-dom": "^6.2.1",
"react-transition-group": "^4.4.1"
"react-transition-group": "^4.4.1",
"stream-browserify": "^3.0.0",
"url": "^0.11.0",
"util": "^0.12.4"
},
"devDependencies": {
"@vitejs/plugin-react": "^1.0.7",
"autoprefixer": "^10.4.2",
"@babel/core": "^7.18.5",
"@babel/preset-env": "^7.18.2",
"@babel/preset-react": "^7.17.12",
"babel-loader": "^8.2.5",
"css-loader": "^6.7.1",
"html-loader": "^3.1.2",
"postcss": "^8.4.5",
"sass": "^1.49.0",
"sass": "^1.52.3",
"sass-loader": "^13.0.0",
"style-loader": "^3.3.1",
"tailwindcss": "^3.0.18",
"vite": "^2.7.2"
"webpack": "^5.73.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.9.2"
},
"babel": {
"presets": [
"@babel/env",
"@babel/react"
]
},
"browser": {
"fs": false
}
}

View File

@@ -1,7 +1,7 @@
import tailwind from 'tailwindcss'
import autoprefixer from 'autoprefixer'
import tailwindConfig from './src/css/tailwind.config.js'
const tailwind = require('tailwindcss')
const autoprefixer = require('autoprefixer')
const tailwindConfig = require('./src/tailwind.config.js')
export default {
module.exports = {
plugins: [tailwind(tailwindConfig), autoprefixer],
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

11
public/index.html Normal file
View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@@ -1,12 +1,14 @@
import React, { useState, useRef, useEffect } from 'react';
import {observer} from "mobx-react-lite";
import { Link } from 'react-router-dom';
import Transition from '../utils/Transition';
import {registrationStore} from "../store/registrationStore";
import {generateSvgAvatar} from "../images/GenerateOnboardingSvg/GenerateSvg";
import UserAvatar from '../images/user-avatar-32.png';
function DropdownProfile({
const DropdownProfile = observer(({
align
}) {
})=>{
const [dropdownOpen, setDropdownOpen] = useState(false);
@@ -43,7 +45,7 @@ function DropdownProfile({
onClick={() => setDropdownOpen(!dropdownOpen)}
aria-expanded={dropdownOpen}
>
<img className="w-8 h-8 rounded-full" src={localStorage.getItem('svgAvatar') || UserAvatar} width="32" height="32" alt="User" />
<img className="w-8 h-8 rounded-full" src={generateSvgAvatar(registrationStore.pubKey) || UserAvatar} width="32" height="32" alt="User" />
<div className="flex items-center truncate">
<span className="truncate ml-2 text-sm font-medium group-hover:text-slate-800">Acme Inc.</span>
<svg className="w-3 h-3 shrink-0 ml-1 fill-current text-slate-400" viewBox="0 0 12 12">
@@ -95,6 +97,6 @@ function DropdownProfile({
</Transition>
</div>
)
}
})
export default DropdownProfile;

View File

@@ -3,7 +3,6 @@
@tailwind base;
@tailwind components;
// Additional styles
@import 'additional-styles/utility-patterns.scss';
@import 'additional-styles/range-slider.scss';
@import 'additional-styles/toggle-switch.scss';

View File

@@ -35,13 +35,10 @@ function createBlob(options) {
return path + "z";
}
export var generateSvgAvatar = (function () {
return function (seed, raw) {
let pubKey = localStorage.getItem('svgKey') || Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16);
export var generateSvgAvatar = ( function () {
return function (publicKey, seed, raw) {
let pubKey = publicKey || Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16);
//pubKey = "73f47d4929d7b2b6598ca4999d52567f9bb5aef3e353e0a66b468096db6e4e88"
if (!localStorage.getItem('svgKey')) {
localStorage.setItem('svgKey', `${pubKey}`)
}
let particles = [];
let gradients = ['#000000'];
let defs = [];

View File

@@ -1,8 +1,11 @@
import React from 'react'
import ReactDOM from 'react-dom'
import {Buffer} from "buffer";
import { BrowserRouter as Router } from 'react-router-dom'
import App from './App'
globalThis.Buffer = Buffer
ReactDOM.render(
<React.StrictMode>
<Router>

View File

@@ -1,4 +1,4 @@
import React, {useEffect, useState} from 'react';
import React, {useState} from 'react';
import Sidebar from '../partials/Sidebar';
import Header from '../partials/Header';
@@ -19,9 +19,6 @@ import DashboardCard10 from '../partials/dashboard/DashboardCard10';
import DashboardCard11 from '../partials/dashboard/DashboardCard11';
function Dashboard() {
useEffect(() => {
localStorage.setItem('svgKey', '')
}, [])
const [sidebarOpen, setSidebarOpen] = useState(false);
return (

View File

@@ -1,11 +1,20 @@
import React from 'react';
import React, {useEffect} from 'react';
import { Link } from 'react-router-dom';
import OnboardingImage from '../images/onboarding-image.jpg';
import OnboardingDecoration from '../images/auth-decoration.png';
import Logo from "../images/logo.png";
import {observer} from "mobx-react-lite";
import {passphrase} from "@liskhq/lisk-client";
import {registrationStore} from "../store/registrationStore";
const Onboarding1 = observer(()=>{
let phrase = passphrase.Mnemonic.generateMnemonic()
registrationStore.savePassPhrase(phrase)
useEffect(()=>{
},[])
function Onboarding1() {
return (
<main className="bg-white">
@@ -127,6 +136,6 @@ function Onboarding1() {
</main>
);
}
})
export default Onboarding1;

View File

@@ -1,11 +1,54 @@
import React from 'react';
import React, {useEffect, useState} from 'react';
import { Link } from 'react-router-dom';
import { observer } from "mobx-react-lite";
import { registrationStore } from "../store/registrationStore";
import OnboardingImage from '../images/onboarding-image.jpg';
import OnboardingDecoration from '../images/auth-decoration.png';
import Logo from "../images/logo.png";
function Onboarding2() {
const Onboarding2 = observer(()=>{
const [dataRegistration, setDataRegistration] = useState(
{
first_name: '',
last_name: '',
gender: '',
date_birth: '',
}
)
const [fillingForm, setFillingForm] = useState(false)
const saveValueChange = (event)=>{
const newValue=event.target.value;
setDataRegistration({
...dataRegistration,
[event.target.id]: newValue
})
}
const saveStoreRegistration = ()=>{
Object.keys(dataRegistration).forEach(item=>{
let element=document.getElementById(item)
if(dataRegistration[item]) {
element.style.borderColor=""
} else {
element.style.borderColor="red"
}
})
if(Object.keys(dataRegistration).find(item=>!dataRegistration[item])) {
return
} else {
setFillingForm(true)
}
registrationStore.saveDataRegistration(dataRegistration)
}
useEffect(()=>{
if(fillingForm===true) {
document.getElementById("signup").click()
}
},[fillingForm])
return (
<main className="bg-white">
@@ -60,23 +103,24 @@ function Onboarding2() {
<form>
<div className="space-y-4 mb-8">
<div>
<label className="block text-sm font-medium mb-1" htmlFor="email">First name <span className="text-rose-500">*</span></label>
<input id="email" className="form-input w-full" type="email" />
<label className="block text-sm font-medium mb-1" htmlFor="first_name">First name <span className="text-rose-500">*</span></label>
<input id="first_name" onChange={(event)=>saveValueChange(event)} className="form-input w-full" type="text" />
</div>
<div>
<label className="block text-sm font-medium mb-1" htmlFor="name">Last name <span className="text-rose-500">*</span></label>
<input id="name" className="form-input w-full" type="text" />
<label className="block text-sm font-medium mb-1" htmlFor="last_name">Last name <span className="text-rose-500">*</span></label>
<input id="last_name" onChange={(event)=>saveValueChange(event)} className="form-input w-full" type="text" />
</div>
<div>
<label className="block text-sm font-medium mb-1" htmlFor="role">Gender <span className="text-rose-500">*</span></label>
<select id="role" className="form-select w-full">
<label className="block text-sm font-medium mb-1" htmlFor="gender">Gender <span className="text-rose-500">*</span></label>
<select id="gender" onChange={(event)=>saveValueChange(event)} className="form-select w-full">
<option className="hidden"></option>
<option>male</option>
<option>feemale</option>
</select>
</div>
<div>
<label className="block text-sm font-medium mb-1" htmlFor="password">Date of birth <span className="text-rose-500">*</span></label>
<input id="password" className="form-input w-full" type="password" autoComplete="on" />
<label className="block text-sm font-medium mb-1" htmlFor="date_birth">Date of birth <span className="text-rose-500">*</span></label>
<input id="date_birth" onChange={(event)=>saveValueChange(event)} className="form-input w-full" type="date" autoComplete="on" />
</div>
</div>
<div className="flex items-center justify-between mt-6">
@@ -86,8 +130,8 @@ function Onboarding2() {
<span className="text-sm ml-2">Email me about product news.</span>
</label>
</div>
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white ml-3 whitespace-nowrap">
<Link to="/onboarding-3">Sign Up</Link>
<button onClick={()=>saveStoreRegistration()} className="btn bg-indigo-500 hover:bg-indigo-600 text-white ml-3 whitespace-nowrap">
<Link id="signup" to={fillingForm && "/onboarding-3"} >Sign Up</Link>
</button>
</div>
</form>
@@ -114,6 +158,6 @@ function Onboarding2() {
</main>
);
}
});
export default Onboarding2;

View File

@@ -1,17 +1,34 @@
import React, {useEffect} from 'react';
import React, { useState} from 'react';
import { Link } from 'react-router-dom';
import {generateSvgAvatar} from "../images/GenerateOnboardingSvg/GenerateSvg";
import Logo from "../images/logo.png";
import {registrationStore} from "../store/registrationStore";
import { passphrase } from "@liskhq/lisk-client";
function Onboarding3() {
useEffect(()=>{
return ()=>{
localStorage.setItem('svgAvatar', generateSvgAvatar())
const [passPhrase, setPassPhrase] = useState(registrationStore.passPhraseStore.replace(/\s+/g, ' ').split(' ').map((item, index) => ({str:item, id:index })))
function generatePassPhrase() {
let phrase = passphrase.Mnemonic.generateMnemonic()
registrationStore.savePassPhrase(phrase)
let newPassPhrase = registrationStore.passPhraseStore.split(' ').map((item, index) => ({str:item, id:index }))
setPassPhrase(newPassPhrase)
}
}, [])
const arrayBadges = ['judge', 'jelly', 'wasp', 'true', 'clog', 'forward', 'talent', 'ozone', 'belive', 'fresh', 'bulk', 'hobby']
function savePassPhraseInStore (copiedPhrase) {
let phrasePaste = copiedPhrase.trim().replace(/\s+/g, ' ').split(' ')
if(phrasePaste.length===12) {
registrationStore.savePassPhrase(copiedPhrase)
setPassPhrase(phrasePaste.map((item, index) => ({str:item, id:index })))
} else {
return false
}
}
function pastePassPhrase() {
navigator.clipboard.readText().then(res=>savePassPhraseInStore(res))
}
return (
<main className="bg-white">
@@ -66,21 +83,21 @@ function Onboarding3() {
<h1 className="text-3xl text-slate-800 font-bold mb-12">Company information </h1>
{/* htmlForm */}
<div className="grid grid-cols-4 gap-y-2.5 gap-[18px] mb-14">
{arrayBadges.map(tag => (
<button key={tag} className="min-w-93px w-24 min-h-26px h-26px bg-slate-100 text-slate-500 cursor-pointer hover:bg-blue-100 hover:text-blue-600 rounded-full text-center px-2.5">
<span className="text-sm font-medium">{tag}</span>
{passPhrase.map(tag => (
<button key={tag.id} className="min-w-93px w-24 min-h-26px h-26px bg-slate-100 text-slate-500 cursor-pointer hover:bg-blue-100 hover:text-blue-600 rounded-full text-center px-2.5">
<span className="text-sm font-medium">{tag.str}</span>
</button>
))}
</div>
<div className="flex pl-7 gap-x-5">
<button className="btn pl-9 pr-16 border-slate-200 hover:border-slate-300 text-slate-600">
<button onClick={()=>pastePassPhrase()} className="btn pl-9 pr-16 border-slate-200 hover:border-slate-300 text-slate-600">
<svg className="w-4 h-4 fill-current text-slate-400 shrink-0 mb-0.5" viewBox="0 0 16 16">
<path
d="M11.7.3c-.4-.4-1-.4-1.4 0l-10 10c-.2.2-.3.4-.3.7v4c0 .6.4 1 1 1h4c.3 0 .5-.1.7-.3l10-10c.4-.4.4-1 0-1.4l-4-4zM4.6 14H2v-2.6l6-6L10.6 8l-6 6zM12 6.6L9.4 4 11 2.4 13.6 5 12 6.6z"></path>
</svg>
<span className="ml-2">Paste</span>
</button>
<button className="btn pr-11 pl-7 border-slate-200 hover:border-slate-300 text-rose-500">
<button onClick={()=>generatePassPhrase()} className="btn pr-11 pl-7 border-slate-200 hover:border-slate-300 text-rose-500">
<svg className="mb-0.5" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.5744 5.66943L13.1504 7.09343C13.4284 7.44043 13.6564 7.75743 13.8194 8.00043C13.0594 9.13043 10.9694 11.8204 8.25836 11.9854L6.44336 13.8004C6.93936 13.9244 7.45736 14.0004 8.00036 14.0004C12.7074 14.0004 15.7444 8.71643 15.8714 8.49243C16.0424 8.18843 16.0434 7.81643 15.8724 7.51243C15.8254 7.42743 15.3724 6.63143 14.5744 5.66943Z" fill="#F43F5E"/>
<path fillRule="evenodd" clipRule="evenodd" d="M1.00038 16.0002C0.744375 16.0002 0.488375 15.9022 0.293375 15.7072C-0.0976249 15.3162 -0.0976249 14.6842 0.292375 14.2942L2.82138 11.7653C1.17238 10.2913 0.198375 8.61425 0.128375 8.48925C-0.0416249 8.18625 -0.0426249 7.81725 0.126375 7.51425C0.251375 7.28925 3.24537 2.00025 8.00037 2.00025C9.33138 2.00025 10.5154 2.43125 11.5484 3.03825L14.2934 0.29325C14.6844 -0.09775 15.3164 -0.09775 15.7074 0.29325C16.0984 0.68425 16.0984 1.31625 15.7074 1.70725L1.70738 15.7072C1.51238 15.9022 1.25638 16.0002 1.00038 16.0002ZM8.00037 4.00025C5.14637 4.00025 2.95837 6.83525 2.18138 7.99925C2.55938 8.56225 3.28538 9.51025 4.24038 10.3463L6.07438 8.51225C6.02938 8.34825 6.00037 8.17825 6.00037 8.00025C6.00037 6.89525 6.89537 6.00025 8.00037 6.00025C8.17838 6.00025 8.34838 6.02925 8.51237 6.07425L10.0784 4.50825C9.43738 4.20125 8.74237 4.00025 8.00037 4.00025Z" fill="#F43F5E"/>
@@ -106,7 +123,7 @@ function Onboarding3() {
{/* Image */}
<div className="flex flex-col items-center h-full w-full hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2" aria-hidden="true">
<div className="flex mt-40 flex-col items-center gap-2.5">
<img className="object-cover object-center" src={generateSvgAvatar()} width="493px" height="493px" alt="Onboarding" />
<img className="object-cover object-center" src={generateSvgAvatar(registrationStore.pubKey)} width="493px" height="493px" alt="Onboarding" />
<span className="text-sm">Your generated Digital ID</span>
</div>
</div>

View File

@@ -1,15 +1,29 @@
import React, {useEffect} from 'react';
import React, {useEffect, useState} from 'react';
import { Link } from 'react-router-dom';
import {generateSvgAvatar} from "../images/GenerateOnboardingSvg/GenerateSvg";
import Logo from "../images/logo.png";
import {observer} from "mobx-react-lite";
import { registrationStore } from "../store/registrationStore";
function Onboarding4() {
const Onboarding4 = observer(()=>{
const [checkBoxesSelected, setCheckBoxesSelected] = useState(false)
function validateCheckBox () {
let checkBoxes=[...document.getElementsByClassName("form-checkbox")]
if(checkBoxes.find(item=>item.checked===false)) {
return
} else {
setCheckBoxesSelected(true)
}
}
useEffect(()=>{
return ()=>{
localStorage.setItem('svgAvatar', generateSvgAvatar())
if(checkBoxesSelected===true) {
document.getElementById("link-dashboard").click()
}
}, [])
},[checkBoxesSelected])
return (
<main className="bg-white">
@@ -66,9 +80,9 @@ function Onboarding4() {
<circle className="text-emerald-100" cx="32" cy="32" r="32" />
<path className="text-emerald-500" d="m28.5 41-8-8 3-3 5 5 12-12 3 3z" />
</svg>
<h1 className="text-3xl text-slate-800 font-bold mb-8">Nice to meet you, Ivan 🙌</h1>
<button className="btn px-6 bg-indigo-500 hover:bg-indigo-600 text-white">
<Link to="/dashboard">Go To Profile -&gt;</Link>
<h1 className="text-3xl text-slate-800 font-bold mb-8">{registrationStore.accountData.first_name ? `Nice to meet you, ${registrationStore.accountData.first_name} 🙌` : 'Please, go back step 2'}</h1>
<button onClick={()=>validateCheckBox()} className="btn px-6 bg-indigo-500 hover:bg-indigo-600 text-white">
<Link id="link-dashboard" to={checkBoxesSelected && "/dashboard"}>Go To Profile -&gt;</Link>
</button>
</div>
@@ -97,7 +111,7 @@ function Onboarding4() {
{/* Image */}
<div className="flex flex-col items-center h-full w-full hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2" aria-hidden="true">
<div className="flex mt-40 flex-col items-center gap-2.5">
<img className="object-cover object-center" src={generateSvgAvatar()} width="493px" height="493px" alt="Onboarding" />
<img className="object-cover object-center" src={generateSvgAvatar(registrationStore.pubKey)} width="493px" height="493px" alt="Onboarding" />
<span className="text-sm">Your generated Digital ID</span>
</div>
</div>
@@ -106,6 +120,6 @@ function Onboarding4() {
</main>
);
}
});
export default Onboarding4;

View File

@@ -0,0 +1,41 @@
import { reaction, makeAutoObservable } from "mobx";
import {cryptography} from "@liskhq/lisk-client";
class RegistrationStore {
_accountData = {}
_passPhraseStore=''
_pubKey = ''
constructor() {
makeAutoObservable(this);
reaction(()=>this.passPhraseStore, ()=>this.savePubKey())
};
savePassPhrase(phrase) {
this._passPhraseStore = phrase
}
saveDataRegistration(data) {
this._accountData = data;
};
savePubKey() {
this._pubKey = cryptography.bufferToHex(cryptography.getAddressAndPublicKeyFromPassphrase(this.passPhraseStore).publicKey)
}
get passPhraseStore() {
return this._passPhraseStore
}
get accountData() {
return this._accountData
};
get pubKey() {
return this._pubKey
}
};
export const registrationStore = new RegistrationStore();

View File

@@ -2,7 +2,7 @@ import resolveConfig from 'tailwindcss/resolveConfig';
export const tailwindConfig = () => {
// Tailwind config
return resolveConfig('./src/css/tailwind.config.js')
return resolveConfig('./src/tailwind.config.js')
}
export const hexToRGB = (h) => {

View File

@@ -1,29 +0,0 @@
import { defineConfig } from 'vite'
import postcss from './postcss.config.js'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
define: {
'process.env': process.env
},
css: {
postcss,
},
plugins: [react()],
resolve: {
alias: [
{
find: /^~.+/,
replacement: (val) => {
return val.replace(/^~/, "");
},
},
],
},
build: {
commonjsOptions: {
transformMixedEsModules: true,
}
}
})

91
webpack.config.js Normal file
View File

@@ -0,0 +1,91 @@
const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const plugins = [
new HtmlWebpackPlugin({
favicon: './public/favicon.ico',
template: './public/index.html',
}),
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
}),
new webpack.ProvidePlugin({
process: 'process/browser',
}),
require('tailwindcss')
];
module.exports = {
entry: './src/main.jsx',
mode: 'development',
devtool: 'eval-source-map',
plugins,
output: {
clean: true,
path: path.resolve(__dirname, 'build'),
assetModuleFilename: 'assets/[hash][ext]',
filename: 'main.[hash:8].js',
},
devServer: {
open: true,
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 'auto',
hot: true,
client: {
progress: true,
},
},
module: {
rules: [
{ test: /\.(html)$/, use: ['html-loader'] },
{
test: /\.m?jsx?$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.scss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ["file-loader"]
}
]
},
resolve: {
extensions: ['.js', '.jsx'],
fallback: {
"path": require.resolve("path-browserify"),
"os": require.resolve("os-browserify/browser"),
"querystring": require.resolve("querystring-es3"),
"crypto": require.resolve("crypto-browserify"),
"util": require.resolve("util/"),
"stream": require.resolve("stream-browserify"),
"url": require.resolve("url/"),
"buffer": require.resolve("buffer/"),
"fs": false
}
},
};