diff --git a/src/components/Checklist/Checklist.jsx b/src/components/Checklist/Checklist.jsx index de9aec0..d2cfec7 100644 --- a/src/components/Checklist/Checklist.jsx +++ b/src/components/Checklist/Checklist.jsx @@ -11,7 +11,7 @@ const renderIcon = (status) => { case "completed": return ; case "in-progress": - return ; + return ; default: return ; } @@ -35,7 +35,7 @@ const getStepStatus = (stepIndex, currentStep) => { const Checklist = ({ wsMessages }) => { const [calculatedCurrentStep, setCalculatedCurrentStep] = useState(0); const [isFinished, setIsFinished] = useState(false); - const navigate = useNavigate(); + const navigate = useNavigate(); useEffect(() => { let latestCompletedStepIndex = -1; @@ -58,7 +58,13 @@ const Checklist = ({ wsMessages }) => { setCalculatedCurrentStep(latestCompletedStepIndex + 1); setIsFinished(pipelineOverallFinished); - }, [wsMessages]); + }, [wsMessages]); + + const ncmsMessage = wsMessages.find(msg => msg.process === "get_ncms" && msg.status === "success"); + const ncmsArray = ncmsMessage?.data || []; + const onlyNcms = ncmsArray.map((item) => ({ + ncms: item.ncms + })); return (
@@ -74,7 +80,7 @@ const Checklist = ({ wsMessages }) => { ); })} - +
) } diff --git a/src/components/DragDrop/DragDrop.jsx b/src/components/DragDrop/DragDrop.jsx index 9b3bc29..6964cf5 100644 --- a/src/components/DragDrop/DragDrop.jsx +++ b/src/components/DragDrop/DragDrop.jsx @@ -5,11 +5,12 @@ import { useState, useRef, useEffect } from "react"; import styles from './DragDrop.module.css'; import api from "../../services/axiosConfig"; import Button from "../Button"; -import { connectWebSocket } from "../../services/websocket"; +import { connectWebSocket, disconnectWebSocket } from "../../services/websocket"; const DragDropFiles = ({ isFileUploaded, setIsFileUploaded, setWsMessages, wsMessages, setCurrentStep }) => { const [file, setFile] = useState(null); const inputRef = useRef(); + const wsRef = useRef(null); // const navigate = useNavigate(); const handleDragOver = (event) => { event.preventDefault(); @@ -40,7 +41,7 @@ const DragDropFiles = ({ isFileUploaded, setIsFileUploaded, setWsMessages, wsMes const formData = new FormData(); formData.append("pdf", file[0]); - connectWebSocket( + wsRef.current = connectWebSocket( handleWsMessage, null, null @@ -57,6 +58,17 @@ const DragDropFiles = ({ isFileUploaded, setIsFileUploaded, setWsMessages, wsMes setCurrentStep(2) }; + const handleCancelProcess = () => { + if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) { + wsRef.current.send(JSON.stringify({ action: "cancel_process" })); + } + + disconnectWebSocket(); + setFile(null); + setIsFileUploaded(false); + setCurrentStep(1); + setWsMessages([]); + }; if (isFileUploaded) { return ( @@ -79,10 +91,10 @@ const DragDropFiles = ({ isFileUploaded, setIsFileUploaded, setWsMessages, wsMes
@@ -96,7 +108,7 @@ const DragDropFiles = ({ isFileUploaded, setIsFileUploaded, setWsMessages, wsMes
- +
diff --git a/src/components/Footer/Footer.module.css b/src/components/Footer/Footer.module.css index 76d81a3..9ff3151 100644 --- a/src/components/Footer/Footer.module.css +++ b/src/components/Footer/Footer.module.css @@ -6,6 +6,7 @@ footer#footer{ bottom: 0; right: 0; left: 0; + z-index: 200; } footer#footer > div{ diff --git a/src/components/Input/Dropdown/Dropdown.jsx b/src/components/Input/Dropdown/Dropdown.jsx index 9b7c749..ecd0d93 100644 --- a/src/components/Input/Dropdown/Dropdown.jsx +++ b/src/components/Input/Dropdown/Dropdown.jsx @@ -6,14 +6,14 @@ import { faChevronDown } from '@fortawesome/free-solid-svg-icons' import inputStyles from '../Input/Input.module.css' import styles from './Dropdown.module.css' -const Dropdown = ({label, options, onChange, dataType}) => { +const Dropdown = ({ label, options, onChange, dataType }) => { // 'options' deve ser um array de opções do dropdown const [currentIndex, setCurrentIndex] = useState(0) const [isActivated, setIsActivated] = useState(false) const isObj = dataType === 'object' - - return( + + return (
{label && ( )} - {options.length > 0 ? ( + {Array.isArray(options) && options.length > 0 ? ( <> - - +
{isActivated && (
{options.map((option, i) => ( -

{ onChange(option) setCurrentIndex(i); setIsActivated(false) @@ -57,10 +57,10 @@ const Dropdown = ({label, options, onChange, dataType}) => { )}

- ) - : ( -
Opções deve ser um Array
- )} + ) + : ( +
Opções deve ser um Array
+ )}
) diff --git a/src/components/Navbar/Navbar.jsx b/src/components/Navbar/Navbar.jsx index 2506c54..4bbc978 100644 --- a/src/components/Navbar/Navbar.jsx +++ b/src/components/Navbar/Navbar.jsx @@ -29,7 +29,7 @@ const Navbar = () => {
  • - Guia de Uso + Guia de Uso
diff --git a/src/index.css b/src/index.css index e340f75..d3c4dce 100644 --- a/src/index.css +++ b/src/index.css @@ -2,4 +2,5 @@ @import './styles/global.css'; @import './styles/reset.css'; @import './styles/typography.css'; -@import './styles/tableCommons.css' \ No newline at end of file +@import './styles/tableCommons.css'; +@import './styles/dark-mode.css'; \ No newline at end of file diff --git a/src/main.jsx b/src/main.jsx index 16ac828..eb536fb 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -6,6 +6,7 @@ import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/js/bootstrap.bundle.min.js'; import 'bootstrap-icons/font/bootstrap-icons.css'; import App from './App.jsx' +import './scripts/darkModeToggle.js' createRoot(document.getElementById('root')).render( diff --git a/src/pages/Homepage/Homepage.jsx b/src/pages/Homepage/Homepage.jsx index 5f2eac0..e98e585 100644 --- a/src/pages/Homepage/Homepage.jsx +++ b/src/pages/Homepage/Homepage.jsx @@ -45,6 +45,9 @@ function Homepage () { icon={faArrowUpRightFromSquare} iconPosition="right" className={styles.userGuideBtn} + onClick={() => { + navigate('/user-guide') + }} > Ver Guia de Uso diff --git a/src/pages/Homepage/Homepage.module.css b/src/pages/Homepage/Homepage.module.css index 6406141..46222d8 100644 --- a/src/pages/Homepage/Homepage.module.css +++ b/src/pages/Homepage/Homepage.module.css @@ -119,4 +119,15 @@ div.buttonsContainer .startProcessBtn{ background-size: 1000% 100%; background-position: right; } +} + +/* Dark Mode - Descriptum e PDF */ +[data-theme="dark"] p.text > b{ + background: var(--base-white); + color: var(--black-700); +} + +[data-theme="dark"] p.text > abbr{ + background: var(--base-white); + color: var(--black-700); } \ No newline at end of file diff --git a/src/pages/TableEdit/TableEdit.jsx b/src/pages/TableEdit/TableEdit.jsx index 649c44f..de57762 100644 --- a/src/pages/TableEdit/TableEdit.jsx +++ b/src/pages/TableEdit/TableEdit.jsx @@ -1,8 +1,10 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import api from '../../services/axiosConfig'; +import { useLocation } from 'react-router-dom'; import styles from './TableEdit.module.css'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faCircleInfo , faFilePen } from '@fortawesome/free-solid-svg-icons'; +import { faCircleInfo, faFilePen } from '@fortawesome/free-solid-svg-icons'; import StepMap from '../../components/StepMap/StepMap'; import Input from '../../components/Input/Input/Input' @@ -11,82 +13,159 @@ import Button from '../../components/Button/Button'; import Tooltip from '../../components/Tooltip/Tooltip'; function TableEdit() { + const location = useLocation(); + // ESTADOS PARA O FORMULÁRIO ----------------------------------- - const [formPN, setFormPN] = useState('MA0603CG150J500'); - const [formCodERP, setFormCodERP] = useState('20020067'); - const [formDescERP, setFormDescERP] = useState('0603 15PF 50V 5% C0G PN: MA0603CG'); - const [formDescDI, setFormDescDI] = useState('CONDENSADORES ELÉTRICOS( CAPACITORES) DE CAMADAS MÚLTIPLAS, FIXOS, SMD, 15 PF ± 5% 50V, C0G P/N: MA0603CG150J500. (COD. 020020067)'); - // NCM ------------------------------ - // Todos NCM's pai - const [formParentNCMArray, setParentNCMArray] = useState([ - { - valor: '8532.24', - descricao: 'Descrição', - }, - { - valor: '8532.40', - descricao: 'Descrição', - }, - { - valor: '8532.19', - descricao: 'Descrição', - } - ]); - // NCM Pai Atual (primeiro do array formParentNCMArray) - const [formParentNCM, setFormParentNCM] = useState(formParentNCMArray[0]); - // Todos NCM's filho - const [formNCMArray, setFormNCMArray] = useState([ - [ - { - valor: '8532.24.10', - descricao: 'Descrição', - }, - { - valor: '8532.24.70', - descricao: 'Descrição', - }, - { - valor: '8532.24.20', - descricao: 'Descrição', - }, - ], - [ - { - valor: '8532.40.10', - descricao: 'Descrição', - }, - { - valor: '8532.40.70', - descricao: 'Descrição', - }, - { - valor: '8532.40.20', - descricao: 'Descrição', - }, - ], - [ - { - valor: '8532.19.10', - descricao: 'Descrição', - }, - { - valor: '8532.19.70', - descricao: 'Descrição', - }, - { - valor: '8532.19.20', - descricao: 'Descrição', - }, - ], - - ]); - // NCM Filho Atual (primeiro do array formNCMArray) - const [formNCM, setFormNCM] = useState(formNCMArray[0]); - const [formFabNome, setFormFabNome] = useState('MERITEK ELECTRONICS CORPORATION'); - const [formFabEndereco, setFormFabEndereco] = useState('5160 RIVERGRADE RD, CA 91706'); - const [formFabDesc, setFormFabDesc] = useState('ESTADOS UNIDOS'); + const [formPN, setFormPN] = useState('MA0603CG150J500'); + const [formCodERP, setFormCodERP] = useState('20020067'); + const [formDescERP, setFormDescERP] = useState('0603 15PF 50V 5% C0G PN: MA0603CG'); + const [formDescDI, setFormDescDI] = useState('CONDENSADORES ELÉTRICOS( CAPACITORES) DE CAMADAS MÚLTIPLAS, FIXOS, SMD, 15 PF ± 5% 50V, C0G P/N: MA0603CG150J500. (COD. 020020067)'); + // NCM ------------------------------ + // Todos NCM's pai + const [formParentNCMArray, setParentNCMArray] = useState([]); + // NCM Pai Atual (primeiro do array formParentNCMArray) + const [formParentNCM, setFormParentNCM] = useState(formParentNCMArray[0]); + // Todos NCM's filho + const [formNCMArray, setFormNCMArray] = useState([ + [ + { + valor: '8532.24.10', + descricao: 'Descrição', + }, + { + valor: '8532.24.70', + descricao: 'Descrição', + }, + { + valor: '8532.24.20', + descricao: 'Descrição', + }, + ], + [ + { + valor: '8532.40.10', + descricao: 'Descrição', + }, + { + valor: '8532.40.70', + descricao: 'Descrição', + }, + { + valor: '8532.40.20', + descricao: 'Descrição', + }, + ], + [ + { + valor: '8532.19.10', + descricao: 'Descrição', + }, + { + valor: '8532.19.70', + descricao: 'Descrição', + }, + { + valor: '8532.19.20', + descricao: 'Descrição', + }, + ], + + ]); + const handleFinalizar = async () => { + try { + const response = await api.get("export?format=xlsx&download=true", { + responseType: "blob", + }); + + const blob = new Blob([response.data], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + + const url = URL.createObjectURL(blob); + + const a = document.createElement("a"); + a.href = url; + a.download = "export.xlsx"; + a.click(); + + URL.revokeObjectURL(url); + + } catch (err) { + console.error("Erro ao exportar:", err); + } + }; + + const [formNCM, setFormNCM] = useState(formNCMArray[0]); + const [formFabNome, setFormFabNome] = useState('MERITEK ELECTRONICS CORPORATION'); + const [formFabEndereco, setFormFabEndereco] = useState('5160 RIVERGRADE RD, CA 91706'); + const [formFabDesc, setFormFabDesc] = useState('ESTADOS UNIDOS'); + + const [orderData, setOrderData] = useState() + const [orderNcms, setOrderNcms] = useState() //NCMs virão aqui + + useEffect(() => { + api.get('/imports/') + .then(res => setOrderData(res.data)) + .catch(err => console.err("Erro ao chamar dados", err)) + }, []) + + useEffect(() => { + if (!location.state.data) return; + + const data = location.state.data || []; + // 1 — transforma a lista inteira + const transformed = data.map(item => { + const ncms = item.ncms || []; + return ncms.map(ncm => ({ + valor: ncm.ncm_6, + descricao: ncm.description, + filhos: (ncm.ncm_8 ?? []).map(f => ({ + valor: f.ncm_code, + descricao: f.description + })) + })); + }); + // 2 — duplica essa lista transformada para cada item + const final = data.map(() => ({ + item: transformed + })); + console.log('result', transformed) + + + setOrderNcms(transformed) + + }, [location]) + + function setInfoToModal(i) { + const d = orderData[i]; + + // --- Preenche dados gerais --- + setFormPN(d.product_part_number); + setFormCodERP(d.supplier_product.product.erp_code); + setFormDescERP(d.supplier_product.erp_description); + setFormDescDI(d.supplier_product.product.final_description); + setFormFabNome(d.manufacturer.name); + + const ncms = location.state.data?.[i]?.ncms || []; + + const result = ncms.map(ncm => ({ + valor: ncm.ncm_6, + descricao: ncm.description, + filhos: (ncm.ncm_8 ?? []).map(f => ({ + valor: f.ncm_code, + descricao: f.description + })) + })); + setParentNCMArray(result); + + const firstParent = result[0] || null; + setFormParentNCM(firstParent); + + const firstChildren = firstParent?.filhos || []; + setFormNCM(firstChildren); + } return (
@@ -101,72 +180,115 @@ function TableEdit() {

- - - - - {/* */} - - - - - - - - - - - - {/* */} - - - - - - - - - - {/* */} - - - - - - - - -
SEQCod ERPDescrição ERPDescrição para DINCMFabricanteEndereçoDescrição País
1200200670603 15PF 50V 5% C0G PN: MA0603CGCONDENSADORES ELÉTRICOS( CAPACITORES) DE CAMADAS MÚLTIPLAS, FIXOS, SMD, 15 PF ± 5% 50V, C0G P/N: MA0603CG150J500. (COD. 020020067) - - NCM 8532.24: Descrição do NCM -
-
- NCM 8532.24.10: Descrição do NCM filho - - } position='right'> - 8532.24.10 - -
-
MERITEK ELECTRONICS CORPORATION5160 RIVERGRADE RD, CA 91706ESTADOS UNIDOS
2200200670603 15PF 50V 5% C0G PN: MA0603CGCONDENSADORES ELÉTRICOS( CAPACITORES) DE CAMADAS MÚLTIPLAS, FIXOS, SMD, 15 PF ± 5% 50V, C0G P/N: MA0603CG150J500. (COD. 020020067) - - NCM 8532.24: Descrição do NCM -
-
- NCM 8532.24.10: Descrição do NCM filho - - } position='right'> - 8532.24.10 - -
-
MERITEK ELECTRONICS CORPORATION5160 RIVERGRADE RD, CA 91706ESTADOS UNIDOS
+ + + + + + + + + + + + + + + + + {orderData && ( + orderData.map((d, index) => ( + setInfoToModal(index)}> + + + + + + + + + + )) + )} + + + +
SEQCod ERPDescrição ERPDescrição para DINCMFabricanteEndereçoDescrição País
{index + 1} + {d.supplier_product.product.erp_code} + + {d.supplier_product.erp_description} + {` + ${d.supplier_product.product.final_description}. + P/N: ${d.product_part_number}. + `} + {orderNcms && ( + + + {orderNcms[index][0].valor} + + + {orderNcms[index][0].descricao} + + +
+
+ + + {orderNcms[index][0].filhos[0].valor} + + + {orderNcms[index][0].filhos[0].descricao} + + + } position='right'> + {orderNcms[index][0].filhos[0].valor} + +
+ )} +
{d.manufacturer.name} 5160 RIVERGRADE RD, CA 91706ESTADOS UNIDOS
-
+ {/* MODAL EXCEL */} + {/* MODAL FORMULÁRIO */} @@ -189,13 +311,18 @@ function TableEdit() { setFormPN(e.target.value)} /> setFormCodERP(e.target.value)} /> - + setFormDescERP(e.target.value)} /> setFormDescDI(e.target.value)} />
- setFormParentNCM(value)}/> - o.valor === formParentNCM.valor)]} dataType='object' onChange={value => setFormNCM(value)} /> + setFormParentNCM(value)} /> + setFormNCM(value)} + />
setFormFabNome(e.target.value)} /> @@ -207,11 +334,11 @@ function TableEdit() {
-
- +
diff --git a/src/pages/TableEdit/TableEdit.module.css b/src/pages/TableEdit/TableEdit.module.css index 8097de9..11172b0 100644 --- a/src/pages/TableEdit/TableEdit.module.css +++ b/src/pages/TableEdit/TableEdit.module.css @@ -14,8 +14,6 @@ section.buttonsContainer{ gap: .7rem; } - - /* MODAL */ div.formModal div.modalBody{ background-color: var(--base-white); @@ -56,4 +54,36 @@ form{ margin-top: 2rem; display: flex; gap: .8rem; + } + +/* MODAL EXCEL */ +div.excelModal div.modalBody{ + padding: 1.5rem; + padding-bottom: 1.7rem; + border-radius: 10px; +} + + div.excelModal header.modalHeader{ + display: flex; + align-items: center; + margin-bottom: 1.5rem; + + color: var(--base-green); + } + header.modalHeader i{ + color: currentColor; + margin-right: .5rem; + font-size: 3.5rem; + } + header.modalHeader .modalTitle{ + color: currentColor; + } + + div.excelModal div.modalBody p.modalExcelMain{ + font: var(--text-regular); + margin-bottom: .5rem; + line-height: 20px; + } + div.excelModal div.modalBody p.modalExcelText{ + font: var(--label-medium); } \ No newline at end of file diff --git a/src/pages/UserGuide/UserGuide.jsx b/src/pages/UserGuide/UserGuide.jsx new file mode 100644 index 0000000..f44d2a6 --- /dev/null +++ b/src/pages/UserGuide/UserGuide.jsx @@ -0,0 +1,400 @@ +import { useState, useEffect, useRef } from 'react' +import styles from './UserGuide.module.css' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { + faFileUpload, + faGears, + faEdit, + faDatabase, + faChevronRight, + faFileArrowDown, + faLightbulb +} from '@fortawesome/free-solid-svg-icons' +import Button from '../../components/Button' +import { useNavigate } from 'react-router-dom' + +function UserGuide() { + const navigate = useNavigate() + const [activeSection, setActiveSection] = useState('overview') + const timeoutIdRef = useRef(null) + + useEffect(() => { + const handleScroll = () => { + if (timeoutIdRef.current) clearTimeout(timeoutIdRef.current) + timeoutIdRef.current = setTimeout(() => { + const sections = ['overview', 'upload', 'process', 'edit', 'database'] + const scrollPosition = window.scrollY + 150 + + for (const sectionId of sections) { + const element = document.getElementById(sectionId) + if (element) { + const offsetTop = element.offsetTop + const offsetBottom = offsetTop + element.offsetHeight + + if (scrollPosition >= offsetTop && scrollPosition < offsetBottom) { + setActiveSection(sectionId) + break + } + } + } + }, 100) + } + + window.addEventListener('scroll', handleScroll) + return () => { + if (timeoutIdRef.current) clearTimeout(timeoutIdRef.current) + window.removeEventListener('scroll', handleScroll) + } + }, []) + + const sections = [ + { id: 'overview', label: 'Visão Geral', icon: faLightbulb }, + { id: 'upload', label: 'Carregar Pedido', icon: faFileUpload }, + { id: 'process', label: 'Processar Pedido', icon: faGears }, + { id: 'edit', label: 'Editar Resultados', icon: faEdit }, + { id: 'database', label: 'Banco de Dados', icon: faDatabase }, + ] + + const scrollToSection = (sectionId) => { + const element = document.getElementById(sectionId) + if (element) { + element.scrollIntoView({ behavior: 'smooth', block: 'start' }) + } + } + + return ( +
+ {/* Sidebar de Navegação */} + + + {/* Conteúdo Principal */} +
+ {/* Visão Geral */} +
+
+ +

Bem-vindo ao Descriptum

+
+ +

+ O Descriptum é uma solução completa para automatizar o processo de registro aduaneiro, + transformando pedidos de compra em informações organizadas e prontas para análise. +

+ +
+
+ +

Envio Rápido

+

Carregue seus pedidos em PDF de forma simples e rápida

+
+
+ +

Processamento Automático

+

O sistema identifica automaticamente produtos, fabricantes e fornecedores

+
+
+ +

Associação de NCM

+

Produtos são associados aos principais NCM's correspondentes

+
+
+ +

Revisão Facilitada

+

Revise e ajuste detalhes conforme necessário antes de finalizar

+
+
+ +
+

Fluxo de Trabalho

+
+
+
1
+
+

Carregar Pedido

+

Faça upload do PDF do pedido de compra

+
+
+ +
+
2
+
+

Processar Pedido

+

Acompanhe a extração automática dos dados

+
+
+ +
+
3
+
+

Editar Resultados

+

Revise e ajuste as informações geradas

+
+
+
+
+
+ + {/* Carregar Pedido */} +
+
+ +

Passo 1: Carregar Pedido

+
+ +

+ Nesta etapa, você fará o upload do arquivo PDF contendo o pedido de compra que deseja processar. +

+ +
+

Como fazer:

+
    +
  1. + Clique no botão "Começar a Extrair" na página inicial ou acesse diretamente a página de upload +
  2. +
  3. + Arraste e solte o arquivo PDF do pedido na área indicada ou clique para selecionar +
  4. +
  5. + Aguarde o upload ser concluído - você verá uma confirmação visual +
  6. +
+
+ +
+ +
+

Dicas importantes:

+
    +
  • Certifique-se de que o arquivo está em formato PDF
  • +
  • O arquivo deve conter informações legíveis do pedido de compra
  • +
  • Verifique se o PDF não está protegido por senha
  • +
+
+
+
+ + {/* Processar Pedido */} +
+
+ +

Passo 2: Processar Pedido

+
+ +

+ Após o upload, o sistema iniciará automaticamente o processamento do pedido. + Nesta fase, o Descriptum extrai e organiza todas as informações relevantes. +

+ +
+

O que acontece nesta etapa:

+
    +
  1. + Extração de Dados: O sistema lê o PDF e identifica produtos, códigos e quantidades +
  2. +
  3. + Identificação Automática: Cada produto é analisado e associado a informações de fabricante e fornecedor +
  4. +
  5. + Associação de NCM: O sistema sugere os códigos NCM mais adequados para cada produto +
  6. +
  7. + Geração de Descrições: Descrições completas são criadas automaticamente para declaração aduaneira +
  8. +
+
+ +
+

Acompanhamento em Tempo Real

+

+ Durante o processamento, você verá uma lista de verificação (checklist) indicando + o progresso de cada etapa. Aguarde até que todas as etapas sejam concluídas antes de prosseguir. +

+
+ +
+ +
+

Importante:

+
    +
  • Não feche a página durante o processamento
  • +
  • O tempo de processamento varia de acordo com o tamanho do pedido
  • +
  • Você será automaticamente direcionado para a próxima etapa quando concluído
  • +
+
+
+
+ + {/* Editar Resultados */} +
+
+ +

Passo 3: Editar Resultados

+
+ +

+ Após o processamento, você terá acesso à tabela com todos os dados extraídos e poderá + revisar e editar qualquer informação antes de finalizar. +

+ +
+

Como revisar e editar:

+
    +
  1. + Visualizar a Tabela: Todos os produtos extraídos serão exibidos em formato de tabela +
  2. +
  3. + Editar um Item: Clique na linha do produto que deseja editar +
  4. +
  5. + Modificar Campos: Um formulário será aberto com todos os campos editáveis: +
      +
    • Part Number (PN)
    • +
    • Código ERP
    • +
    • Descrição ERP
    • +
    • Descrição para DI (Declaração de Importação)
    • +
    • NCM (Nomenclatura Comum do Mercosul)
    • +
    • Dados do Fabricante (Nome, Endereço, País)
    • +
    +
    +
  6. +
  7. + Salvar Alterações: Clique em "Salvar" para confirmar as modificações +
  8. +
  9. + Finalizar: Quando estiver satisfeito com todas as informações, clique em "Finalizar" para gerar o Excel +
  10. +
+
+ +
+ +
+

Exportação de Dados

+

+ Ao finalizar, o sistema gera automaticamente um arquivo Excel contendo todos os dados + organizados e prontos para uso no processo de registro aduaneiro. +

+
+
+ +
+ +
+

Dicas para edição:

+
    +
  • Revise especialmente as descrições para DI, garantindo que estejam completas e corretas
  • +
  • Verifique se os códigos NCM sugeridos estão adequados ao produto
  • +
  • Confirme os dados de fabricante e fornecedor para evitar problemas na documentação
  • +
  • Você pode editar quantas linhas forem necessárias antes de finalizar
  • +
+
+
+
+ + {/* Banco de Dados */} +
+
+ +

Banco de Dados

+
+ +

+ O Descriptum mantém um banco de dados completo com informações de produtos, fornecedores e + fabricantes, além do histórico de todas as extrações realizadas. +

+ +
+
+ +

Histórico de Extrações

+

Acesse o registro completo de todos os pedidos processados, com data, status e informações detalhadas de cada extração realizada.

+
+ +
+ +

Produtos

+

Explore o catálogo completo de produtos já processados. Visualize e atualize informações como códigos, descrições e especificações técnicas.

+
+ +
+ +

Fornecedores

+

Gerencie o cadastro de fornecedores, incluindo razão social, endereço, país de origem e outras informações relevantes para o processo aduaneiro.

+
+ +
+ +

Fabricantes

+

Mantenha atualizado o cadastro de fabricantes com nome, endereço completo, país de fabricação e demais dados necessários para documentação.

+
+
+ +
+

Como utilizar o Banco de Dados:

+
    +
  1. + Acesse o menu "Banco de Dados" na navegação principal +
  2. +
  3. + Selecione a categoria que deseja consultar ou editar +
  4. +
  5. + Use os filtros e busca para encontrar registros específicos +
  6. +
  7. + Clique em qualquer registro para visualizar detalhes ou editar informações +
  8. +
+
+ +
+ +
+

Benefícios do Banco de Dados:

+
    +
  • Reutilização de informações em futuras extrações
  • +
  • Melhoria contínua da precisão dos dados
  • +
  • Histórico completo para auditoria e rastreabilidade
  • +
  • Facilita a padronização de descrições e classificações
  • +
+
+
+
+ + {/* Call to Action */} +
+

Pronto para começar?

+

Inicie agora o processo de extração e aproveite todos os recursos do Descriptum!

+ +
+
+
+ ) +} + +export default UserGuide diff --git a/src/pages/UserGuide/UserGuide.module.css b/src/pages/UserGuide/UserGuide.module.css new file mode 100644 index 0000000..14662d3 --- /dev/null +++ b/src/pages/UserGuide/UserGuide.module.css @@ -0,0 +1,467 @@ +.container { + display: flex; + min-height: 100vh; + background: var(--base-white); +} + +/* Sidebar */ +.sidebar { + position: fixed; + left: 0; + top: 75px; + width: 280px; + height: calc(100vh - 75px); + background: var(--white-300); + border-right: 1px solid var(--white-500); + padding: 2rem 1rem; + overflow-y: auto; + z-index: 100; +} + +.sidebarTitle { + font-size: 1.5rem; + font-weight: 700; + color: var(--base-black); + margin-bottom: 2rem; + padding: 0 1rem; +} + +.nav { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.navItem { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.875rem 1rem; + background: transparent; + border: none; + border-radius: 8px; + color: var(--white-700); + font-size: 0.95rem; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + text-align: left; +} + +.navItem:hover { + background: var(--white-500); + color: var(--base-black); +} + +.navItemActive { + background: var(--royal-300); + color: var(--base-navy); +} + +.navItemActive:hover { + background: var(--royal-300); + color: var(--base-navy); +} + +.navIcon { + width: 18px; + font-size: 1rem; +} + +/* Content */ +.content { + margin-left: 280px; + flex: 1; + padding: 3rem; + max-width: 1200px; +} + +.section { + margin-bottom: 4rem; + scroll-margin-top: 2rem; +} + +.sectionHeader { + display: flex; + align-items: center; + gap: 1rem; + margin-bottom: 1.5rem; + padding-bottom: 1rem; + border-bottom: 2px solid var(--white-500); +} + +.sectionIcon { + font-size: 2rem; + color: var(--royal-500); +} + +.sectionTitle { + font-size: 2rem; + font-weight: 700; + color: var(--base-black); + margin: 0; +} + +.description { + font-size: 1.125rem; + line-height: 1.7; + color: var(--white-700); + margin-bottom: 2rem; +} + +/* Features Grid */ +.featuresGrid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5rem; + margin: 2rem 0; +} + +.featureCard { + padding: 1.5rem; + background: var(--white-300); + border: 1px solid var(--white-500); + border-radius: 12px; + transition: all 0.3s ease; +} + +.featureCard:hover { + transform: translateY(-4px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); + border-color: var(--royal-300); +} + +.featureIcon { + font-size: 2rem; + color: var(--royal-500); + margin-bottom: 1rem; +} + +.featureCard h3 { + font-size: 1.125rem; + font-weight: 600; + color: var(--base-black); + margin-bottom: 0.5rem; +} + +.featureCard p { + font-size: 0.95rem; + color: var(--white-700); + line-height: 1.6; +} + +/* Workflow */ +.workflow { + margin: 3rem 0; + padding: 2rem; + background: var(--white-300); + border-radius: 12px; +} + +.workflow h2 { + font-size: 1.5rem; + font-weight: 600; + color: var(--base-black); + margin-bottom: 2rem; +} + +.workflowSteps { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; +} + +.workflowStep { + flex: 1; + display: flex; + align-items: center; + gap: 1rem; + padding: 1.5rem; + background: var(--base-white); + border: 1px solid var(--white-500); + border-radius: 10px; +} + +.stepNumber { + display: flex; + align-items: center; + justify-content: center; + width: 48px; + height: 48px; + min-width: 48px; + background: var(--royal-500); + color: white; + font-size: 1.5rem; + font-weight: 700; + border-radius: 50%; +} + +.stepContent h4 { + font-size: 1rem; + font-weight: 600; + color: var(--base-black); + margin-bottom: 0.25rem; +} + +.stepContent p { + font-size: 0.875rem; + color: var(--white-700); +} + +.stepArrow { + font-size: 1.5rem; + color: var(--white-700); + min-width: 24px; +} + +/* Instruction Box */ +.instructionBox { + background: var(--white-300); + border-left: 4px solid var(--royal-500); + border-radius: 8px; + padding: 1.5rem; + margin: 2rem 0; +} + +.instructionBox h3 { + font-size: 1.25rem; + font-weight: 600; + color: var(--base-black); + margin-bottom: 1rem; +} + +.instructionList { + list-style: none; + counter-reset: item; + padding: 0; + margin: 0; +} + +.instructionList > li { + display: flex; + align-items: flex-start; + gap: 1rem; + padding: 0.75rem 0; + color: var(--white-700); + line-height: 1.6; + counter-increment: item; +} + +.instructionList > li::before { + content: counter(item) "."; + font-weight: 700; + color: var(--royal-500); + min-width: 24px; +} + +.subList { + margin-top: 0.5rem; + margin-left: 1rem; +} + +.subList li { + padding: 0.25rem 0; +} + +/* Tip Box */ +.tipBox { + display: flex; + gap: 1rem; + background: var(--yellow-300); + border: 1px solid var(--yellow-500); + border-radius: 8px; + padding: 1.5rem; + margin: 2rem 0; +} + +.tipIcon { + color: var(--yellow-700); + font-size: 1.5rem; + min-width: 24px; + margin-top: 0.25rem; +} + +.tipBox h4 { + font-size: 1rem; + font-weight: 600; + color: var(--base-black); + margin-bottom: 0.5rem; +} + +.tipBox ul { + margin: 0.5rem 0 0 1.25rem; + color: var(--white-700); +} + +.tipBox li { + padding: 0.25rem 0; + line-height: 1.6; +} + +/* Progress Info */ +.progressInfo { + background: var(--white-300); + border: 1px solid var(--royal-300); + border-radius: 8px; + padding: 1.5rem; + margin: 2rem 0; +} + +.progressInfo h3 { + font-size: 1.125rem; + font-weight: 600; + color: var(--base-black); + margin-bottom: 0.75rem; +} + +.progressInfo p { + color: var(--white-700); + line-height: 1.6; +} + +/* Feature Highlight */ +.featureHighlight { + display: flex; + gap: 1.5rem; + align-items: center; + background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%); + border-radius: 12px; + padding: 2rem; + margin: 2rem 0; +} + +.highlightIcon { + font-size: 3rem; + color: var(--royal-500); + min-width: 48px; +} + +.featureHighlight h3 { + font-size: 1.25rem; + font-weight: 600; + color: var(--base-black); + margin-bottom: 0.5rem; +} + +.featureHighlight p { + color: var(--white-700); + line-height: 1.6; +} + +/* Database Grid */ +.databaseGrid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 1.5rem; + margin: 2rem 0; +} + +.databaseCard { + padding: 2rem; + background: var(--white-300); + border: 1px solid var(--white-500); + border-radius: 12px; + transition: all 0.3s ease; +} + +.databaseCard:hover { + transform: translateY(-4px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); + border-color: var(--royal-300); +} + +.databaseIcon { + font-size: 2.5rem; + color: var(--royal-500); + margin-bottom: 1rem; +} + +.databaseCard h3 { + font-size: 1.25rem; + font-weight: 600; + color: var(--base-black); + margin-bottom: 0.75rem; +} + +.databaseCard p { + font-size: 0.95rem; + color: var(--white-700); + line-height: 1.6; +} + +/* CTA Section */ +.ctaSection { + text-align: center; + padding: 3rem; + background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%); + border-radius: 16px; + margin-top: 4rem; +} + +.ctaSection h2 { + font-size: 2rem; + font-weight: 700; + color: var(--base-black); + margin-bottom: 1rem; +} + +.ctaSection p { + font-size: 1.125rem; + color: var(--white-700); + margin-bottom: 2rem; +} + +/* Responsive */ +@media (max-width: 1024px) { + .sidebar { + width: 240px; + } + + .content { + margin-left: 240px; + padding: 2rem; + } + + .workflowSteps { + flex-direction: column; + } + + .stepArrow { + transform: rotate(90deg); + } +} + +@media (max-width: 768px) { + .container { + flex-direction: column; + } + + .sidebar { + position: relative; + width: 100%; + height: auto; + border-right: none; + border-bottom: 1px solid var(--white-500); + top: 0; + } + + .content { + margin-left: 0; + padding: 1.5rem; + } + + .sectionTitle { + font-size: 1.5rem; + } + + .featuresGrid, + .databaseGrid { + grid-template-columns: 1fr; + } + + .featureHighlight { + flex-direction: column; + text-align: center; + } +} diff --git a/src/routes.jsx b/src/routes.jsx index 27259c1..325d5d2 100644 --- a/src/routes.jsx +++ b/src/routes.jsx @@ -3,6 +3,7 @@ import { Routes , Route } from "react-router-dom"; import Homepage from "./pages/Homepage/Homepage"; import TableEdit from "./pages/TableEdit/TableEdit"; import InputFiles from "./pages/InputFiles/InputFiles"; +import UserGuide from "./pages/UserGuide/UserGuide"; import DataBase from "./pages/DataBase/DataBase"; @@ -18,6 +19,7 @@ const RoutesApp = () => { } /> } /> } /> + } /> } /> } /> } /> diff --git a/src/scripts/darkModeToggle.js b/src/scripts/darkModeToggle.js new file mode 100644 index 0000000..f576361 --- /dev/null +++ b/src/scripts/darkModeToggle.js @@ -0,0 +1,171 @@ +/** + * Dark Mode Toggle - Sistema Independente + * + * Script vanilla JavaScript que: + * - Cria um botão no navbar com ícone Bootstrap Icons + * - Gerencia o estado do tema (light/dark) + * - Persiste a escolha no localStorage + * - Detecta preferência do sistema + * - Não interfere com código React existente + */ + +(function() { + 'use strict'; + + // Chave para localStorage + const STORAGE_KEY = 'theme-preference'; + + // Número máximo de tentativas para criar o botão (20 × 100ms = 2 segundos) + const MAX_BUTTON_CREATION_ATTEMPTS = 20; + + // Função para obter o tema inicial + function getInitialTheme() { + // Primeiro, verifica localStorage + try { + const saved = localStorage.getItem(STORAGE_KEY); + if (saved) { + return saved; + } + } catch (error) { + console.warn('Dark mode: não foi possível acessar localStorage:', error); + } + + // Depois, verifica preferência do sistema + if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { + return 'dark'; + } + + // Padrão: light + return 'light'; + } + + // Função para aplicar o tema + function applyTheme(theme) { + document.documentElement.setAttribute('data-theme', theme); + try { + localStorage.setItem(STORAGE_KEY, theme); + } catch (error) { + console.warn('Dark mode: não foi possível salvar preferência de tema:', error); + } + updateToggleButton(theme); + } + + // Função para alternar tema + function toggleTheme() { + const current = document.documentElement.getAttribute('data-theme') || 'light'; + const next = current === 'light' ? 'dark' : 'light'; + applyTheme(next); + } + + // Função para criar o botão de toggle + function createToggleButton() { + // Verifica se já existe + if (document.getElementById('dark-mode-toggle')) { + return; + } + + // Encontra o navbar + const navbar = document.querySelector('.navbar-nav:last-child'); + if (!navbar) { + console.warn('Navbar não encontrado, botão não foi criado'); + return; + } + + // Cria o item de lista + const li = document.createElement('li'); + li.className = 'nav-item'; + + // Cria o botão + const button = document.createElement('button'); + button.id = 'dark-mode-toggle'; + button.setAttribute('aria-label', 'Alternar modo escuro'); + button.setAttribute('type', 'button'); + button.setAttribute('tabindex', '0'); + button.innerHTML = ''; + + // Event listeners para mouse e teclado + button.addEventListener('click', toggleTheme); + button.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + toggleTheme(); + } + }); + + // Adiciona ao navbar + li.appendChild(button); + navbar.appendChild(li); + } + + // Função para atualizar o ícone do botão + function updateToggleButton(theme) { + const button = document.getElementById('dark-mode-toggle'); + if (button) { + const icon = theme === 'light' + ? '' + : ''; + const title = theme === 'light' ? 'Ativar modo escuro' : 'Ativar modo claro'; + button.innerHTML = icon; + button.setAttribute('title', title); + } + } + + // Listener para mudanças na preferência do sistema + function watchSystemTheme() { + if (window.matchMedia) { + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + mediaQuery.addEventListener('change', (e) => { + // Só aplica se não houver preferência salva + try { + if (!localStorage.getItem(STORAGE_KEY)) { + applyTheme(e.matches ? 'dark' : 'light'); + } + } catch (error) { + console.warn('Dark mode: não foi possível verificar preferência de tema:', error); + } + }); + } + } + + // Inicialização + function init() { + // Aplica tema inicial imediatamente (antes do DOM carregar) + const initialTheme = getInitialTheme(); + document.documentElement.setAttribute('data-theme', initialTheme); + + // Função para tentar criar o botão (com retry) + function tryCreateButton(attempts = 0) { + const navbar = document.querySelector('.navbar-nav:last-child'); + if (navbar) { + createToggleButton(); + updateToggleButton(initialTheme); + } else if (attempts < MAX_BUTTON_CREATION_ATTEMPTS) { + // Tenta novamente após 100ms + setTimeout(() => tryCreateButton(attempts + 1), 100); + } else { + console.warn('Dark mode toggle: navbar não encontrado após múltiplas tentativas'); + } + } + + // Quando o DOM estiver pronto, tenta criar o botão + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => { + tryCreateButton(); + watchSystemTheme(); + }); + } else { + tryCreateButton(); + watchSystemTheme(); + } + } + + // Executa inicialização + init(); + + // Expõe funções globalmente (opcional, para debug) + window.darkMode = { + toggle: toggleTheme, + set: applyTheme, + get: () => document.documentElement.getAttribute('data-theme') + }; +})(); diff --git a/src/styles/dark-mode.css b/src/styles/dark-mode.css new file mode 100644 index 0000000..edeafcc --- /dev/null +++ b/src/styles/dark-mode.css @@ -0,0 +1,399 @@ +/* + * Dark Mode - Implementação Independente + * Não modifica os estilos existentes. Apenas adiciona regras quando [data-theme="dark"] está ativo. + * Usa apenas as cores da paleta oficial do sistema. + */ + +/* Background principal */ +[data-theme="dark"] body, +[data-theme="dark"] div#root { + background-color: var(--base-black) !important; + color: var(--base-white) !important; +} + +/* Navbar */ +[data-theme="dark"] nav.navbar { + background-color: var(--black-700) !important; + color: var(--base-white) !important; +} + +[data-theme="dark"] nav.navbar img, +[data-theme="dark"] .navbar-brand img { + filter: brightness(0) invert(1); +} + +[data-theme="dark"] .nav-link { + color: var(--white-500) !important; +} + +[data-theme="dark"] .nav-link:hover { + color: var(--base-white) !important; +} + +[data-theme="dark"] .navbar-toggler-icon { + filter: invert(1); +} + +/* Footer */ +[data-theme="dark"] footer#footer { + background-color: var(--base-navy) !important; +} + +/* Tabelas */ +[data-theme="dark"] table.table > thead * { + background-color: var(--black-700) !important; + color: var(--white-500) !important; +} + +[data-theme="dark"] table.table > tbody tr, +[data-theme="dark"] table.table > tbody tr th, +[data-theme="dark"] table.table > tbody tr td { + background-color: var(--base-black) !important; + color: var(--white-700) !important; +} + +[data-theme="dark"] table.table > tbody tr:hover th, +[data-theme="dark"] table.table > tbody tr:hover td { + background-color: var(--black-700) !important; +} + +/* Inputs e Formulários */ +[data-theme="dark"] input, +[data-theme="dark"] textarea, +[data-theme="dark"] select { + background-color: var(--black-700) !important; + color: var(--base-white) !important; + border-color: var(--black-500) !important; +} + +[data-theme="dark"] input::placeholder, +[data-theme="dark"] textarea::placeholder { + color: var(--white-700) !important; +} + +/* Labels */ +[data-theme="dark"] label { + color: var(--base-white) !important; +} + +/* Cards e Containers */ +[data-theme="dark"] .card, +[data-theme="dark"] div[class*="card"] { + background-color: var(--black-700) !important; + border-color: var(--black-500) !important; +} + +[data-theme="dark"] .card:hover, +[data-theme="dark"] div[class*="card"]:hover { + background-color: var(--black-700) !important; + border-color: var(--royal-500) !important; + box-shadow: 0 4px 12px rgba(35, 111, 189, 0.3) !important; +} + +[data-theme="dark"] .card-body, +[data-theme="dark"] div[class*="card-content"] { + background-color: transparent !important; +} + +[data-theme="dark"] .card-title, +[data-theme="dark"] .card h1, +[data-theme="dark"] .card h2, +[data-theme="dark"] .card h3, +[data-theme="dark"] .card h4, +[data-theme="dark"] .card h5, +[data-theme="dark"] .card h6, +[data-theme="dark"] div[class*="card"] h1, +[data-theme="dark"] div[class*="card"] h2, +[data-theme="dark"] div[class*="card"] h3 { + color: var(--base-white) !important; +} + +[data-theme="dark"] .card-text, +[data-theme="dark"] .card p, +[data-theme="dark"] div[class*="card"] p { + color: var(--white-500) !important; +} + +/* Ícone dentro dos cards */ +[data-theme="dark"] .card-icon, +[data-theme="dark"] div[class*="card-icon"] { + background-color: var(--black-500) !important; +} + +[data-theme="dark"] .card:hover .card-icon, +[data-theme="dark"] div[class*="card"]:hover div[class*="card-icon"] { + background-color: var(--black-500) !important; +} + +[data-theme="dark"] .card svg, +[data-theme="dark"] .card i, +[data-theme="dark"] div[class*="card"] svg, +[data-theme="dark"] div[class*="card"] i { + filter: brightness(1) !important; +} + +[data-theme="dark"] .container, +[data-theme="dark"] .container-sm, +[data-theme="dark"] .container-fluid, +[data-theme="dark"] [class*="container"] > div { + background-color: transparent !important; + color: var(--base-white) !important; +} + +/* Títulos */ +[data-theme="dark"] h1, +[data-theme="dark"] h2, +[data-theme="dark"] h3, +[data-theme="dark"] h4, +[data-theme="dark"] h5, +[data-theme="dark"] h6 { + color: var(--base-white) !important; +} + +/* Parágrafos */ +[data-theme="dark"] p { + color: var(--white-500) !important; +} + +/* Links */ +[data-theme="dark"] a { + color: var(--royal-300) !important; +} + +[data-theme="dark"] a:hover { + color: var(--royal-500) !important; +} + +/* Dropzone (DragDrop) */ +[data-theme="dark"] [class*="dropzone"], +[data-theme="dark"] [class*="drop-zone"] { + background-color: var(--black-700) !important; + color: var(--base-white) !important; +} + +/* Step Map */ +[data-theme="dark"] [class*="step-map-circle"] { + background-color: var(--black-700) !important; + color: var(--base-white) !important; +} + +[data-theme="dark"] [class*="step-map-count"], +[data-theme="dark"] [class*="step-map-label"] { + color: var(--base-white) !important; +} + +[data-theme="dark"] [class*="step-map-load"], +[data-theme="dark"] [class*="loading"], +[data-theme="dark"] .fa-spinner, +[data-theme="dark"] .fa-circle-notch, +[data-theme="dark"] .fa-arrow-rotate-right { + color: var(--base-white) !important; +} + +/* Dropdown Options */ +[data-theme="dark"] [class*="option"] { + background-color: var(--black-700) !important; + color: var(--base-white) !important; +} + +[data-theme="dark"] [class*="option"]:hover { + background-color: var(--black-500) !important; +} + +/* Modals e Overlays */ +[data-theme="dark"] .modal-content { + background-color: var(--black-700) !important; + color: var(--base-white) !important; +} + +/* Borders gerais */ +[data-theme="dark"] [class*="border"], +[data-theme="dark"] .border { + border-color: var(--black-500) !important; +} + +/* Botão de Toggle - Minimalista com Bootstrap Icons */ +#dark-mode-toggle { + background: transparent; + border: none; + cursor: pointer; + font-size: 1.1rem; + padding: 8px 10px; + margin-left: 0.5rem; + display: inline-flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + color: var(--base-navy) !important; +} + +#dark-mode-toggle:hover { + color: var(--royal-700) !important; + transform: scale(1.15); +} + +[data-theme="dark"] #dark-mode-toggle { + color: var(--base-white) !important; +} + +[data-theme="dark"] #dark-mode-toggle:hover { + color: var(--white-300) !important; +} + +/* Botões outlined no modo escuro */ +[data-theme="dark"] button[class*="outlined"], +[data-theme="dark"] a[class*="outlined"] { + border-color: var(--white-500) !important; + color: var(--base-white) !important; +} + +[data-theme="dark"] button[class*="outlined"]:hover, +[data-theme="dark"] a[class*="outlined"]:hover { + background-color: var(--black-500) !important; + border-color: var(--base-white) !important; + color: var(--base-white) !important; +} + +/* ===== USER GUIDE PAGE ===== */ + +/* Sidebar */ +[data-theme="dark"] [class*="sidebar"] { + background: var(--black-700) !important; + border-right-color: var(--black-500) !important; +} + +[data-theme="dark"] [class*="sidebarTitle"] { + color: var(--base-white) !important; +} + +[data-theme="dark"] [class*="navItem"] { + color: var(--white-500) !important; +} + +[data-theme="dark"] [class*="navItem"]:hover { + background: var(--black-500) !important; + color: var(--base-white) !important; +} + +[data-theme="dark"] [class*="navItemActive"] { + background: var(--royal-700) !important; + color: var(--base-white) !important; +} + +[data-theme="dark"] [class*="navItemActive"]:hover { + background: var(--royal-700) !important; + color: var(--base-white) !important; +} + +/* Content Area */ +[data-theme="dark"] [class*="sectionHeader"] { + border-bottom-color: var(--black-500) !important; +} + +[data-theme="dark"] [class*="sectionIcon"], +[data-theme="dark"] [class*="featureIcon"], +[data-theme="dark"] [class*="highlightIcon"], +[data-theme="dark"] [class*="databaseIcon"] { + color: var(--royal-300) !important; +} + +[data-theme="dark"] [class*="sectionTitle"], +[data-theme="dark"] [class*="featureCard"] h3, +[data-theme="dark"] [class*="databaseCard"] h3, +[data-theme="dark"] [class*="workflow"] h2, +[data-theme="dark"] [class*="instructionBox"] h3, +[data-theme="dark"] [class*="featureHighlight"] h3 { + color: var(--base-white) !important; +} + +[data-theme="dark"] [class*="description"], +[data-theme="dark"] [class*="featureCard"] p, +[data-theme="dark"] [class*="databaseCard"] p, +[data-theme="dark"] [class*="stepContent"] p, +[data-theme="dark"] [class*="instructionList"] li, +[data-theme="dark"] [class*="featureHighlight"] p { + color: var(--white-500) !important; +} + +/* Feature Cards */ +[data-theme="dark"] [class*="featureCard"], +[data-theme="dark"] [class*="databaseCard"] { + background: var(--black-700) !important; + border-color: var(--black-500) !important; +} + +[data-theme="dark"] [class*="featureCard"]:hover, +[data-theme="dark"] [class*="databaseCard"]:hover { + border-color: var(--royal-500) !important; + box-shadow: 0 8px 24px rgba(30, 100, 184, 0.3) !important; +} + +/* Workflow */ +[data-theme="dark"] [class*="workflow"] { + background: var(--black-700) !important; +} + +[data-theme="dark"] [class*="workflowStep"] { + background: var(--base-black) !important; + border-color: var(--black-500) !important; +} + +[data-theme="dark"] [class*="stepNumber"] { + background: var(--royal-500) !important; +} + +[data-theme="dark"] [class*="stepContent"] h4 { + color: var(--base-white) !important; +} + +[data-theme="dark"] [class*="stepArrow"] { + color: var(--white-500) !important; +} + +/* Instruction Box */ +[data-theme="dark"] [class*="instructionBox"] { + background: var(--black-700) !important; + border-left-color: var(--royal-500) !important; +} + +[data-theme="dark"] [class*="instructionList"] > li::before { + color: var(--royal-300) !important; +} + +/* Progress Info Box (azul) */ +[data-theme="dark"] [class*="progressInfo"] { + background: rgba(59, 130, 246, 0.1) !important; + border-color: rgba(59, 130, 246, 0.3) !important; +} + +[data-theme="dark"] [class*="progressInfo"] h3, +[data-theme="dark"] [class*="progressInfo"] p { + color: var(--base-white) !important; +} + +/* Tip Box (amarelo/laranja) */ +[data-theme="dark"] [class*="tipBox"] { + background: rgba(245, 158, 11, 0.1) !important; + border-color: rgba(245, 158, 11, 0.3) !important; +} + +[data-theme="dark"] [class*="tipBox"] h4, +[data-theme="dark"] [class*="tipBox"] ul, +[data-theme="dark"] [class*="tipBox"] li { + color: var(--base-white) !important; +} + +/* Feature Highlight */ +[data-theme="dark"] [class*="featureHighlight"] { + background: linear-gradient(135deg, var(--royal-700) 0%, var(--royal-500) 100%) !important; +} + +/* CTA Section */ +[data-theme="dark"] [class*="ctaSection"] { + background: linear-gradient(135deg, var(--royal-700) 0%, var(--base-navy) 100%) !important; +} + +[data-theme="dark"] [class*="ctaSection"] h2, +[data-theme="dark"] [class*="ctaSection"] p { + color: var(--base-white) !important; +}