Docker + Jenkfins File + v0.1

This commit is contained in:
Marco Santos
2024-11-18 10:42:44 +00:00
parent 964bad93f1
commit 048d3ea82f
32 changed files with 505 additions and 975 deletions

View File

@@ -1,11 +1,11 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app WORKDIR /app
EXPOSE 8080 EXPOSE 8080
EXPOSE 443 EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src WORKDIR /src
COPY ["GeradoresWS/GeradoresWS.csproj", "GeradoresWS/"] COPY ["GeradoresWS/GeradoresWS.csproj", "GeradoresWS/"]
@@ -25,7 +25,7 @@ WORKDIR /app
COPY --from=publish /app/publish . COPY --from=publish /app/publish .
# Set environment variables # Set environment variables
ENV ASPNETCORE_URLS=http://+:8080 ENV ASPNETCORE_URLS=http://+:8080, http://+:443
ENV ASPNETCORE_ENVIRONMENT=Production ENV ASPNETCORE_ENVIRONMENT=Production
ENTRYPOINT ["dotnet", "GeradoresWS.dll"] ENTRYPOINT ["dotnet", "GeradoresWS.dll"]

View File

@@ -5,16 +5,22 @@ VisualStudioVersion = 17.6.33829.357
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionFiles", "SolutionFiles", "{6370AD16-6443-4846-B933-702A86A48A19}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionFiles", "SolutionFiles", "{6370AD16-6443-4846-B933-702A86A48A19}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.dockerignore = .dockerignore
.gitattributes = .gitattributes .gitattributes = .gitattributes
.gitignore = .gitignore .gitignore = .gitignore
docker-compose.yml = docker-compose.yml
Dockerfile = Dockerfile
Jenkinsfile = Jenkinsfile
README.md = README.md README.md = README.md
EndProjectSection EndProjectSection
EndProject EndProject
Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "geradoresfe", "geradoresfe\geradoresfe.esproj", "{1D9DDDEB-6FBA-4A9C-AE85-6A3630D8B9AC}" Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "geradoresfe", "geradoresfe\geradoresfe.esproj", "{1D9DDDEB-6FBA-4A9C-AE85-6A3630D8B9AC}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeradoresWS", "GeradoresWS\GeradoresWS.csproj", "{78B34F6D-E9C9-4FD0-A3E4-670BA401ACF6}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeradoresWS", "GeradoresWS\GeradoresWS.csproj", "{78B34F6D-E9C9-4FD0-A3E4-670BA401ACF6}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeradoresService", "GeradoresService\GeradoresService.csproj", "{35C4D726-3771-4D34-9A43-541588FCECAA}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeradoresService", "GeradoresService\GeradoresService.csproj", "{35C4D726-3771-4D34-9A43-541588FCECAA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "UnitTest\UnitTest.csproj", "{911FEEB4-749E-43CA-9FE3-CE8334B5E0C9}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -36,6 +42,10 @@ Global
{35C4D726-3771-4D34-9A43-541588FCECAA}.Debug|Any CPU.Build.0 = Debug|Any CPU {35C4D726-3771-4D34-9A43-541588FCECAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35C4D726-3771-4D34-9A43-541588FCECAA}.Release|Any CPU.ActiveCfg = Release|Any CPU {35C4D726-3771-4D34-9A43-541588FCECAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35C4D726-3771-4D34-9A43-541588FCECAA}.Release|Any CPU.Build.0 = Release|Any CPU {35C4D726-3771-4D34-9A43-541588FCECAA}.Release|Any CPU.Build.0 = Release|Any CPU
{911FEEB4-749E-43CA-9FE3-CE8334B5E0C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{911FEEB4-749E-43CA-9FE3-CE8334B5E0C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{911FEEB4-749E-43CA-9FE3-CE8334B5E0C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{911FEEB4-749E-43CA-9FE3-CE8334B5E0C9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
namespace GeradoresService.DAL;
public partial class Geradore
{
public int Id { get; set; }
public int? Tipo { get; set; }
public string? Valor { get; set; }
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace GeradoresService.DAL;
public partial class GeradoresContext : DbContext
{
public GeradoresContext()
{
}
public GeradoresContext(DbContextOptions<GeradoresContext> options)
: base(options)
{
}
public virtual DbSet<Geradore> Geradores { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Geradore>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__Geradore__3214EC2710D5AD88");
entity.Property(e => e.Id).HasColumnName("ID");
entity.Property(e => e.Valor).HasMaxLength(50);
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

View File

@@ -1,9 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Folder Include="DAL\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,10 +1,18 @@
using System.ComponentModel; using GeradoresService.DAL;
using System.ComponentModel;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
namespace GeradoresService namespace GeradoresService
{ {
public class NIF public class NIF
{ {
private readonly GeradoresContext _geradoresContext;
public NIF(GeradoresContext geradoresContext)
{
_geradoresContext = geradoresContext;
}
public enum NIFType public enum NIFType
{ {
[Description("Pessoa singular (1)")] [Description("Pessoa singular (1)")]
@@ -29,16 +37,14 @@ namespace GeradoresService
PessoaColectivaIrregular = 9 PessoaColectivaIrregular = 9
} }
/*public static GetNIFTypes(){ public string Generate(string? type)
EnumHelper.GetEnumValuesAndDescriptions(NIFType);
}*/
public static string Generate(string? type)
{ {
return GenerateRandomNIF(type); var nif = GenerateRandomNIF(type);
//SaveNIF(nif);
return nif;
} }
public static string GenerateRandomNIF(string? nifType) public string GenerateRandomNIF(string? nifType)
{ {
var firstDigitValidate = new char[] { '1', '2', '3', '5', '6', '8', '9' }; var firstDigitValidate = new char[] { '1', '2', '3', '5', '6', '8', '9' };
Random rnd = new Random(); Random rnd = new Random();
@@ -86,7 +92,7 @@ namespace GeradoresService
return randomNIF; return randomNIF;
} }
public static bool Validate(string nif) public bool Validate(string nif)
{ {
// Verificar se o NIF tem 9 dígitos // Verificar se o NIF tem 9 dígitos
if (nif.Length != 9) if (nif.Length != 9)
@@ -117,5 +123,16 @@ namespace GeradoresService
return digitoControlo == digitos[8]; return digitoControlo == digitos[8];
} }
public void SaveNIF(string NIF)
{
var ger = new Geradore()
{
Valor = NIF
};
_geradoresContext.Geradores.Add(ger);
_geradoresContext.SaveChanges();
}
} }
} }

View File

@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using GeradoresService; using GeradoresService;
using GeradoresService.DAL;
namespace GeradoresWS.Controllers namespace GeradoresWS.Controllers
{ {
@@ -7,8 +8,13 @@ namespace GeradoresWS.Controllers
[Route("[controller]")] [Route("[controller]")]
public class GenerateController : Controller public class GenerateController : Controller
{ {
#region NIF GeradoresContext _context;
public GenerateController(GeradoresContext context)
{
_context = context;
}
#region NIF
[HttpGet("GetNIFTypes")] [HttpGet("GetNIFTypes")]
public List<NIF.NIFType> GetNIFTypes() public List<NIF.NIFType> GetNIFTypes()
{ {
@@ -18,13 +24,15 @@ namespace GeradoresWS.Controllers
[HttpGet("GenerateNIF")] [HttpGet("GenerateNIF")]
public string GenerateNIF(string? type) public string GenerateNIF(string? type)
{ {
return NIF.Generate(type); var nif = new NIF(_context);
return nif.Generate(type);
} }
[HttpGet("ValidateNIF")] [HttpGet("ValidateNIF")]
public bool ValidateNIF(string nif) public bool ValidateNIF(string nif)
{ {
return NIF.Validate(nif); var teste = new NIF(_context);
return teste.Validate(nif);
} }
#endregion #endregion

32
GeradoresWS/Dockerfile Normal file
View File

@@ -0,0 +1,32 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 8080
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["GeradoresWS/GeradoresWS.csproj", "GeradoresWS/"]
COPY ["GeradoresService/GeradoresService.csproj", "GeradoresService/"]
RUN dotnet restore "GeradoresWS/GeradoresWS.csproj"
COPY . .
WORKDIR "/src/GeradoresWS"
RUN dotnet build "GeradoresWS.csproj" -c debug -o /app/build
FROM build AS publish
RUN dotnet publish "GeradoresWS.csproj" -c debug -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
# Set environment variables
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Production
ENTRYPOINT ["dotnet", "GeradoresWS.dll"]

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>df357c84-88b1-4100-86d1-889166b333f7</UserSecretsId> <UserSecretsId>df357c84-88b1-4100-86d1-889166b333f7</UserSecretsId>

View File

@@ -1,3 +1,6 @@
using GeradoresService.DAL;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Add services to the container. // Add services to the container.
@@ -7,13 +10,16 @@ builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen();
var connectionString = builder.Configuration.GetConnectionString("GeradoresConnection");
builder.Services.AddDbContext<GeradoresContext>(options => options.UseSqlServer(connectionString));
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
app.UseSwagger(); app.UseSwagger();
app.UseSwaggerUI(); app.UseSwaggerUI();
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseAuthorization(); app.UseAuthorization();

View File

@@ -32,6 +32,10 @@
"commandName": "Docker", "commandName": "Docker",
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_URLS": "http://+:8080",
"ASPNETCORE_ENVIRONMENT": "Development"
},
"publishAllPorts": true, "publishAllPorts": true,
"useSSL": false "useSSL": false
} }

View File

@@ -5,5 +5,9 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*",
"ConnectionStrings": {
"GeradoresConnection": "server=127.0.0.1;uid=sa;pwd=mssqlAdmin!1;database=Geradores;TrustServerCertificate=True;"
}
} }

27
Jenkinsfile vendored
View File

@@ -12,12 +12,21 @@ pipeline {
environment { environment {
now = new Date().format('yyyyMMdd-HHmm', TimeZone.getTimeZone('UTC')) now = new Date().format('yyyyMMdd-HHmm', TimeZone.getTimeZone('UTC'))
DOCKER_IMAGE = 'GeradoresWs/api'
DOCKER_TAG = "${env.BUILD_ID}"
DOCKER_REGISTRY = 'Shini89'
REMOTE_DOCKER_HOST = '192.168.2.20'
REMOTE_DOCKER_USER = 'admin'
REMOTE_DOCKER_PORT = '2375'
REACT_DIR = 'geradoresfe' // Diret<65>rio do frontend React
SERVICE_DIR = 'GeradoresService' // Diret<65>rio do projeto DLL
API_DIR = 'GeradoresWS' // Diret<65>rio do Web API
DOCKER_REGISTRY = 'your-docker-registry.com' // Registro Docker
} }
stages { stages {
/*******************************************************
Stage BUILD
*******************************************************/
stage('Check for Changes') { stage('Check for Changes') {
steps { steps {
script { script {
@@ -43,12 +52,20 @@ pipeline {
} }
} }
stage('Checkout Code') {
steps {
git branch: 'master', url: 'https://git.homeware.pt/Marco/Geradores.git'
}
}
/******************************************************* /*******************************************************
Stage BUILD Stage BUILD
*******************************************************/ *******************************************************/
stage('Build') { stage('Build Service DLL') {
steps { steps {
echo 'Construindo o projeto...' echo 'Building Business Logic DLL...'
dir("${env.SERVICE_DIR}") {
sh 'dotnet build -c Release'
}
} }
} }
} }

38
UnitTest/DB.cs Normal file
View File

@@ -0,0 +1,38 @@
using GeradoresService;
using GeradoresService.DAL;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace UnitTest
{
public class DB
{
private readonly GeradoresContext _context;
public DB()
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
// Obter a connection string a partir do arquivo de configura<72><61>o
var connectionString = configuration.GetConnectionString("GeradoresConnection");
// Configurar o DbContext para usar o InMemoryDatabase
var options = new DbContextOptionsBuilder<GeradoresContext>()
.UseSqlServer(connectionString)
.Options;
_context = new GeradoresContext(options);
}
[Fact]
public void GenerateNIF()
{
var nif = new NIF(_context);
var gerenatednif = nif.Generate("2");
Assert.NotEmpty(gerenatednif);
}
}
}

54
UnitTest/UnitTest.csproj Normal file
View File

@@ -0,0 +1,54 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.Development.json" />
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.Development.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GeradoresService\GeradoresService.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

13
UnitTest/appsettings.json Normal file
View File

@@ -0,0 +1,13 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"GeradoresConnection": "server=127.0.0.1;uid=sa;pwd=mssqlAdmin!1;database=Geradores;TrustServerCertificate=True;"
}
}

View File

@@ -5,6 +5,8 @@
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.4", "@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5", "@emotion/styled": "^11.11.5",
"@headlessui/react": "^2.2.0",
"@heroicons/react": "^2.1.5",
"@mui/icons-material": "^5.15.15", "@mui/icons-material": "^5.15.15",
"@mui/material": "^5.15.15", "@mui/material": "^5.15.15",
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
@@ -50,6 +52,7 @@
"@types/react-helmet": "^6.1.11", "@types/react-helmet": "^6.1.11",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-react-app": "^7.0.1", "eslint-config-react-app": "^7.0.1",
"jest-editor-support": "^31.1.2" "jest-editor-support": "^31.1.2",
"tailwindcss": "^3.4.13"
} }
} }

View File

@@ -1,99 +1,20 @@
import * as React from 'react'; import React from 'react';
import { PaletteMode } from '@mui/material'; import Navbar from './components/Navbar';
import CssBaseline from '@mui/material/CssBaseline';
import Box from '@mui/material/Box';
import Divider from '@mui/material/Divider';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import { Helmet } from 'react-helmet';
import getLPTheme from './GeradoresTheme';
import AppAppBar from './components/AppAppBar';
import Hero from './components/Hero'; import Hero from './components/Hero';
import LogoCollection from './components/LogoCollection'; import FeatureSection from './components/Features';
import Highlights from './components/Highlights';
import Pricing from './components/Pricing';
import Features from './components/Features';
import Testimonials from './components/Testimonials';
import FAQ from './components/FAQ';
import Footer from './components/Footer'; import Footer from './components/Footer';
import GeradorCC from './components/GeradorNIF';
const App = () => {
interface ToggleCustomThemeProps {
showCustomTheme: Boolean;
toggleCustomTheme: () => void;
}
function ToggleCustomTheme({
showCustomTheme,
toggleCustomTheme,
}: ToggleCustomThemeProps) {
return ( return (
<Box <div className="min-h-screen flex flex-col">
sx={{ <Navbar />
display: 'flex', <main className="flex-grow">
flexDirection: 'column', <Hero />
alignItems: 'center', <FeatureSection />
width: '100dvw', </main>
position: 'fixed', <Footer />
bottom: 24,
}}
>
<ToggleButtonGroup
color="primary"
exclusive
value={showCustomTheme}
onChange={toggleCustomTheme}
aria-label="Platform"
sx={{
backgroundColor: 'background.default',
'& .Mui-selected': {
pointerEvents: 'none',
},
}}
>
<ToggleButton value>
Custom theme
</ToggleButton>
<ToggleButton value={false}>Material Design 2</ToggleButton>
</ToggleButtonGroup>
</Box>
);
}
function App() {
/*const [mode, setMode] = React.useState<PaletteMode>('light');
const [showCustomTheme, setShowCustomTheme] = React.useState(true);
const LPtheme = createTheme(getLPTheme(mode));
const defaultTheme = createTheme({ palette: { mode } });
const toggleColorMode = () => {
setMode((prev) => (prev === 'dark' ? 'light' : 'dark'));
};
const toggleCustomTheme = () => {
setShowCustomTheme((prev) => !prev);
};*/
return (
<div className="App">
<Helmet>
<meta charSet="utf-8" />
<title>Geradores</title>
</Helmet>
{ /*<ThemeProvider theme={showCustomTheme ? LPtheme : defaultTheme}></ThemeProvider>*/}
<div>
<CssBaseline />
<GeradorCC />
</div>
</div> </div>
); );
} };
export default App; export default App;

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

View File

@@ -1,227 +0,0 @@
import * as React from 'react';
import { PaletteMode } from '@mui/material';
import Box from '@mui/material/Box';
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import Button from '@mui/material/Button';
import IconButton from '@mui/material/IconButton';
import Container from '@mui/material/Container';
import Divider from '@mui/material/Divider';
import MenuItem from '@mui/material/MenuItem';
import Drawer from '@mui/material/Drawer';
import MenuIcon from '@mui/icons-material/Menu';
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
import ToggleColorMode from './ToggleColorMode';
import Sitemark from './SitemarkIcon';
interface AppAppBarProps {
mode: PaletteMode;
toggleColorMode: () => void;
}
export default function AppAppBar({ mode, toggleColorMode }: AppAppBarProps) {
const [open, setOpen] = React.useState(false);
const toggleDrawer = (newOpen: boolean) => () => {
setOpen(newOpen);
};
const scrollToSection = (sectionId: string) => {
const sectionElement = document.getElementById(sectionId);
const offset = 128;
if (sectionElement) {
const targetScroll = sectionElement.offsetTop - offset;
sectionElement.scrollIntoView({ behavior: 'smooth' });
window.scrollTo({
top: targetScroll,
behavior: 'smooth',
});
setOpen(false);
}
};
return (
<AppBar
position="fixed"
sx={{
boxShadow: 0,
bgcolor: 'transparent',
backgroundImage: 'none',
mt: 2,
}}
>
<Container maxWidth="lg">
<Toolbar
variant="regular"
sx={(theme) => ({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
flexShrink: 0,
borderRadius: '999px',
bgcolor:
theme.palette.mode === 'light'
? 'hsla(220, 60%, 99%, 0.6)'
: 'hsla(220, 0%, 0%, 0.7)',
backdropFilter: 'blur(24px)',
maxHeight: 40,
border: '1px solid',
borderColor: 'divider',
boxShadow:
theme.palette.mode === 'light'
? '0 1px 2px hsla(210, 0%, 0%, 0.05), 0 2px 12px hsla(210, 100%, 80%, 0.5)'
: '0 1px 2px hsla(210, 0%, 0%, 0.5), 0 2px 12px hsla(210, 100%, 25%, 0.3)',
})}
>
<Box
sx={{
flexGrow: 1,
display: 'flex',
alignItems: 'center',
px: 0,
}}
>
<Sitemark />
<Box sx={{ display: { xs: 'none', md: 'flex' } }}>
<Button
variant="text"
color="info"
size="small"
onClick={() => scrollToSection('features')}
>
Features
</Button>
<Button
variant="text"
color="info"
size="small"
onClick={() => scrollToSection('testimonials')}
>
Testimonials
</Button>
<Button
variant="text"
color="info"
size="small"
onClick={() => scrollToSection('highlights')}
>
Highlights
</Button>
<Button
variant="text"
color="info"
size="small"
onClick={() => scrollToSection('pricing')}
>
Pricing
</Button>
<Button
variant="text"
color="info"
size="small"
onClick={() => scrollToSection('faq')}
sx={{ minWidth: 0 }}
>
FAQ
</Button>
</Box>
</Box>
<Box
sx={{
display: { xs: 'none', md: 'flex' },
gap: 0.5,
alignItems: 'center',
}}
>
<ToggleColorMode mode={mode} toggleColorMode={toggleColorMode} />
<Button
color="primary"
variant="text"
size="small"
component="a"
href="/material-ui/getting-started/templates/sign-in/"
target="_blank"
>
Sign in
</Button>
<Button
color="primary"
variant="contained"
size="small"
component="a"
href="/material-ui/getting-started/templates/sign-up/"
target="_blank"
>
Sign up
</Button>
</Box>
<Box sx={{ display: { sm: 'flex', md: 'none' } }}>
<IconButton aria-label="Menu button" onClick={toggleDrawer(true)}>
<MenuIcon />
</IconButton>
<Drawer anchor="top" open={open} onClose={toggleDrawer(false)}>
<Box
sx={{
p: 2,
backgroundColor: 'background.default',
}}
>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<ToggleColorMode mode={mode} toggleColorMode={toggleColorMode} />
<IconButton onClick={toggleDrawer(false)}>
<CloseRoundedIcon />
</IconButton>
</Box>
<Divider sx={{ my: 3 }} />
<MenuItem onClick={() => scrollToSection('features')}>
Features
</MenuItem>
<MenuItem onClick={() => scrollToSection('testimonials')}>
Testimonials
</MenuItem>
<MenuItem onClick={() => scrollToSection('highlights')}>
Highlights
</MenuItem>
<MenuItem onClick={() => scrollToSection('pricing')}>
Pricing
</MenuItem>
<MenuItem onClick={() => scrollToSection('faq')}>FAQ</MenuItem>
<MenuItem>
<Button
color="primary"
variant="contained"
component="a"
href="/material-ui/getting-started/templates/sign-up/"
target="_blank"
fullWidth
>
Sign up
</Button>
</MenuItem>
<MenuItem>
<Button
color="primary"
variant="outlined"
component="a"
href="/material-ui/getting-started/templates/sign-in/"
target="_blank"
fullWidth
>
Sign in
</Button>
</MenuItem>
</Box>
</Drawer>
</Box>
</Toolbar>
</Container>
</AppBar>
);
}

View File

@@ -1,272 +1,27 @@
import * as React from 'react'; import React from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Card from '@mui/material/Card';
import Chip from '@mui/material/Chip';
import Container from '@mui/material/Container';
import Grid from '@mui/material/Grid';
import Link from '@mui/material/Link';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import ChevronRightRoundedIcon from '@mui/icons-material/ChevronRightRounded';
import DevicesRoundedIcon from '@mui/icons-material/DevicesRounded';
import EdgesensorHighRoundedIcon from '@mui/icons-material/EdgesensorHighRounded';
import ViewQuiltRoundedIcon from '@mui/icons-material/ViewQuiltRounded';
const items = [
{
icon: <ViewQuiltRoundedIcon />,
title: 'Dashboard',
description:
'This item could provide a snapshot of the most important metrics or data points related to the product.',
imageLight: 'url("/static/images/templates/templates-images/dash-light.png")',
imageDark: 'url("/static/images/templates/templates-images/dash-dark.png")',
},
{
icon: <EdgesensorHighRoundedIcon />,
title: 'Mobile integration',
description:
'This item could provide information about the mobile app version of the product.',
imageLight: 'url("/static/images/templates/templates-images/mobile-light.png")',
imageDark: 'url("/static/images/templates/templates-images/mobile-dark.png")',
},
{
icon: <DevicesRoundedIcon />,
title: 'Available on all platforms',
description:
'This item could let users know the product is available on all platforms, such as web, mobile, and desktop.',
imageLight: 'url("/static/images/templates/templates-images/devices-light.png")',
imageDark: 'url("/static/images/templates/templates-images/devices-dark.png")',
},
];
export default function Features() {
const [selectedItemIndex, setSelectedItemIndex] = React.useState(0);
const handleItemClick = (index: number) => {
setSelectedItemIndex(index);
};
const selectedFeature = items[selectedItemIndex];
function FeatureSection() {
return ( return (
<Container id="features" sx={{ py: { xs: 8, sm: 16 } }}> <section id="features" className="py-20 bg-white">
<Grid container spacing={6}> <div className="container mx-auto px-4 text-center">
<Grid item xs={12} md={6}> <h2 className="text-3xl font-bold text-gray-800">Why Use Our Generator?</h2>
<div> <div className="mt-8 grid grid-cols-1 md:grid-cols-3 gap-8">
<Typography component="h2" variant="h4" color="text.primary"> <div className="p-6 bg-gray-50 rounded-lg shadow-md">
Product features <h3 className="text-xl font-bold text-gray-800">NIF (N<EFBFBD>mero Identifica<EFBFBD><EFBFBD>o Fiscal)</h3>
</Typography> <p className="mt-4 text-gray-600">Quickly generate valid Portuguese Tax Identification Numbers (NIF) for testing.</p>
<Typography
variant="body1"
color="text.secondary"
sx={{ mb: { xs: 2, sm: 4 } }}
>
Provide a brief overview of the key features of the product. For
example, you could list the number of features, their types or
benefits, and add-ons.
</Typography>
</div> </div>
<Grid container item gap={1} sx={{ display: { xs: 'auto', sm: 'none' } }}> <div className="p-6 bg-gray-50 rounded-lg shadow-md">
{items.map(({ title }, index) => ( <h3 className="text-xl font-bold text-gray-800">NISS (N<EFBFBD>mero Identifica<EFBFBD><EFBFBD>o Seguran<EFBFBD>a Social)</h3>
<Chip <p className="mt-4 text-gray-600">Create Portuguese Social Security Numbers (NISS) easily with one click.</p>
key={index}
label={title}
onClick={() => handleItemClick(index)}
sx={(theme) => ({
...(selectedItemIndex === index && {
borderColor:
theme.palette.mode === 'light'
? 'primary.light'
: 'primary.dark',
background:
'linear-gradient(to bottom right, hsl(210, 98%, 48%), hsl(210, 98%, 35%))',
color: 'hsl(0, 0%, 100%)',
'& .MuiChip-label': {
color: 'hsl(0, 0%, 100%)',
},
}),
})}
/>
))}
</Grid>
<Card
variant="outlined"
sx={{
display: { xs: 'auto', sm: 'none' },
mt: 4,
}}
>
<Box
sx={{
backgroundImage: (theme) =>
theme.palette.mode === 'light'
? items[selectedItemIndex].imageLight
: items[selectedItemIndex].imageDark,
backgroundSize: 'cover',
backgroundPosition: 'center',
minHeight: 280,
}}
/>
<Box sx={{ px: 2, pb: 2 }}>
<Typography color="text.primary" fontWeight="medium" gutterBottom>
{selectedFeature.title}
</Typography>
<Typography color="text.secondary" variant="body2" sx={{ mb: 1.5 }}>
{selectedFeature.description}
</Typography>
<Link
color="primary"
variant="body2"
fontWeight="bold"
sx={{
display: 'inline-flex',
alignItems: 'center',
'& > svg': { transition: '0.2s' },
'&:hover > svg': { transform: 'translateX(2px)' },
}}
>
<span>Learn more</span>
<ChevronRightRoundedIcon
fontSize="small"
sx={{ mt: '1px', ml: '2px' }}
/>
</Link>
</Box>
</Card>
<Stack
direction="column"
justifyContent="center"
alignItems="flex-start"
spacing={2}
useFlexGap
sx={{ width: '100%', display: { xs: 'none', sm: 'flex' } }}
>
{items.map(({ icon, title, description }, index) => (
<Card
key={index}
component={Button}
onClick={() => handleItemClick(index)}
sx={(theme) => ({
p: 3,
height: 'fit-content',
width: '100%',
background: 'none',
...(selectedItemIndex === index && {
backgroundColor: 'action.selected',
borderColor:
theme.palette.mode === 'light'
? 'primary.light'
: 'primary.dark',
}),
'&:hover': {
background:
theme.palette.mode === 'light'
? 'linear-gradient(to bottom right, hsla(210, 100%, 97%, 0.5) 25%, hsla(210, 100%, 90%, 0.3) 100%)'
: 'linear-gradient(to right bottom, hsla(210, 100%, 12%, 0.2) 25%, hsla(210, 100%, 16%, 0.2) 100%)',
borderColor:
theme.palette.mode === 'light'
? 'primary.light'
: 'primary.dark',
boxShadow:
theme.palette.mode === 'light'
? '0px 2px 8px hsla(0, 0%, 0%, 0.1)'
: '0px 1px 8px hsla(210, 100%, 25%, 0.5) ',
},
})}
>
<Box
sx={{
width: '100%',
display: 'flex',
textAlign: 'left',
flexDirection: { xs: 'column', md: 'row' },
alignItems: { md: 'center' },
gap: 2.5,
}}
>
<Box
sx={(theme) => ({
color:
theme.palette.mode === 'light' ? 'grey.400' : 'grey.600',
...(selectedItemIndex === index && {
color: 'primary.main',
}),
})}
>
{icon}
</Box>
<div>
<Typography
color="text.primary"
fontWeight="medium"
gutterBottom
>
{title}
</Typography>
<Typography
color="text.secondary"
variant="body2"
sx={{ mb: 1.5 }}
>
{description}
</Typography>
<Link
color="primary"
variant="body2"
fontWeight="bold"
sx={{
display: 'inline-flex',
alignItems: 'center',
'& > svg': { transition: '0.2s' },
'&:hover > svg': { transform: 'translateX(2px)' },
}}
onClick={(event) => {
event.stopPropagation();
}}
>
<span>Learn more</span>
<ChevronRightRoundedIcon
fontSize="small"
sx={{ mt: '1px', ml: '2px' }}
/>
</Link>
</div> </div>
</Box> <div className="p-6 bg-gray-50 rounded-lg shadow-md">
</Card> <h3 className="text-xl font-bold text-gray-800">Cart<EFBFBD>o de Cidad<EFBFBD>o</h3>
))} <p className="mt-4 text-gray-600">Generate valid Citizen Card numbers for testing purposes in a few seconds.</p>
</Stack> </div>
</Grid> </div>
<Grid </div>
item </section>
xs={12}
md={6}
sx={{ display: { xs: 'none', sm: 'flex' }, width: '100%' }}
>
<Card
variant="outlined"
sx={{
height: '100%',
width: '100%',
display: { xs: 'none', sm: 'flex' },
pointerEvents: 'none',
}}
>
<Box
sx={{
m: 'auto',
width: 420,
height: 500,
backgroundSize: 'contain',
backgroundImage: (theme) =>
theme.palette.mode === 'light'
? items[selectedItemIndex].imageLight
: items[selectedItemIndex].imageDark,
}}
/>
</Card>
</Grid>
</Grid>
</Container>
); );
} };
export default FeatureSection;

View File

@@ -1,215 +1,16 @@
import * as React from 'react'; import React from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Container from '@mui/material/Container';
import IconButton from '@mui/material/IconButton';
import InputLabel from '@mui/material/InputLabel';
import Link from '@mui/material/Link';
import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import { visuallyHidden } from '@mui/utils'; const Footer = () => {
import FacebookIcon from '@mui/icons-material/GitHub';
import LinkedInIcon from '@mui/icons-material/LinkedIn';
import TwitterIcon from '@mui/icons-material/X';
import SitemarkIcon from './SitemarkIcon';
function Copyright() {
return ( return (
<Typography variant="body2" color="text.secondary" mt={1}> <footer id="contact" className="bg-gray-800 py-6">
{'Copyright © '} <div className="container mx-auto px-4 text-center text-white">
<Link href="https://mui.com/">Sitemark&nbsp;</Link> <p className="text-sm">&copy; {new Date().getFullYear()} GeneratorApp. All rights reserved.</p>
{new Date().getFullYear()} <p className="mt-2">
</Typography> <a href="mailto:info@generatorapp.com" className="underline">info@generatorapp.com</a>
); </p>
}
export default function Footer() {
return (
<Container
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: { xs: 4, sm: 8 },
py: { xs: 8, sm: 10 },
textAlign: { sm: 'center', md: 'left' },
}}
>
<Box
sx={{
display: 'flex',
flexDirection: { xs: 'column', sm: 'row' },
width: '100%',
justifyContent: 'space-between',
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
gap: 4,
minWidth: { xs: '100%', sm: '60%' },
}}
>
<Box sx={{ width: { xs: '100%', sm: '60%' } }}>
<SitemarkIcon />
<Typography variant="body2" fontWeight={600} gutterBottom sx={{ mt: 2 }}>
Join the newsletter
</Typography>
<Typography variant="body2" color="text.secondary" mb={2}>
Subscribe for weekly updates. No spams ever!
</Typography>
<Stack direction="row" spacing={1} useFlexGap>
<InputLabel htmlFor="email-newsletter" sx={visuallyHidden}>
Email
</InputLabel>
<TextField
id="email-newsletter"
hiddenLabel
size="small"
variant="outlined"
fullWidth
aria-label="Enter your email address"
placeholder="Your email address"
inputProps={{
autocomplete: 'off',
ariaLabel: 'Enter your email address',
}}
/>
<Button variant="contained" color="primary" sx={{ flexShrink: 0 }}>
Subscribe
</Button>
</Stack>
</Box>
</Box>
<Box
sx={{
display: { xs: 'none', sm: 'flex' },
flexDirection: 'column',
gap: 1,
}}
>
<Typography variant="body2" fontWeight="medium">
Product
</Typography>
<Link color="text.secondary" variant="body2" href="#">
Features
</Link>
<Link color="text.secondary" variant="body2" href="#">
Testimonials
</Link>
<Link color="text.secondary" variant="body2" href="#">
Highlights
</Link>
<Link color="text.secondary" variant="body2" href="#">
Pricing
</Link>
<Link color="text.secondary" variant="body2" href="#">
FAQs
</Link>
</Box>
<Box
sx={{
display: { xs: 'none', sm: 'flex' },
flexDirection: 'column',
gap: 1,
}}
>
<Typography variant="body2" fontWeight="medium">
Company
</Typography>
<Link color="text.secondary" variant="body2" href="#">
About us
</Link>
<Link color="text.secondary" variant="body2" href="#">
Careers
</Link>
<Link color="text.secondary" variant="body2" href="#">
Press
</Link>
</Box>
<Box
sx={{
display: { xs: 'none', sm: 'flex' },
flexDirection: 'column',
gap: 1,
}}
>
<Typography variant="body2" fontWeight="medium">
Legal
</Typography>
<Link color="text.secondary" variant="body2" href="#">
Terms
</Link>
<Link color="text.secondary" variant="body2" href="#">
Privacy
</Link>
<Link color="text.secondary" variant="body2" href="#">
Contact
</Link>
</Box>
</Box>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
pt: { xs: 4, sm: 8 },
width: '100%',
borderTop: '1px solid',
borderColor: 'divider',
}}
>
<div>
<Link color="text.secondary" variant="body2" href="#">
Privacy Policy
</Link>
<Typography display="inline" sx={{ mx: 0.5, opacity: 0.5 }}>
&nbsp;&nbsp;
</Typography>
<Link color="text.secondary" variant="body2" href="#">
Terms of Service
</Link>
<Copyright />
</div> </div>
<Stack </footer>
direction="row"
justifyContent="left"
spacing={1}
useFlexGap
sx={{
color: 'text.secondary',
}}
>
<IconButton
color="inherit"
href="https://github.com/mui"
aria-label="GitHub"
sx={{ alignSelf: 'center' }}
>
<FacebookIcon />
</IconButton>
<IconButton
color="inherit"
href="https://twitter.com/MaterialUI"
aria-label="X"
sx={{ alignSelf: 'center' }}
>
<TwitterIcon />
</IconButton>
<IconButton
color="inherit"
href="https://www.linkedin.com/company/mui/"
aria-label="LinkedIn"
sx={{ alignSelf: 'center' }}
>
<LinkedInIcon />
</IconButton>
</Stack>
</Box>
</Container>
); );
} };
export default Footer;

View File

@@ -1,132 +1,23 @@
import * as React from 'react'; import React from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Container from '@mui/material/Container';
import InputLabel from '@mui/material/InputLabel';
import Link from '@mui/material/Link';
import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import { visuallyHidden } from '@mui/utils'; function Hero(){
export default function Hero() {
return ( return (
<Box <section id="home" className="bg-blue-50 py-20">
id="hero" <div className="container mx-auto text-center">
sx={(theme) => ({ <h1 className="text-5xl font-bold text-gray-800">
width: '100%', Generate Your NIF, NISS, and Cart<EFBFBD>o de Cidad<EFBFBD>o Easily
backgroundImage: </h1>
theme.palette.mode === 'light' <p className="mt-4 text-gray-600">
? 'radial-gradient(ellipse 80% 50% at 50% -20%, hsl(210, 100%, 90%), transparent)' Use our simple and efficient platform to generate valid testing numbers quickly.
: 'radial-gradient(ellipse 80% 50% at 50% -20%, hsl(210, 100%, 16%), transparent)', </p>
backgroundRepeat: 'no-repeat', <div className="mt-6">
})} <a href="#generate" className="px-6 py-3 bg-blue-600 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700">
> Get Started
<Container </a>
sx={{ </div>
display: 'flex', </div>
flexDirection: 'column', </section>
alignItems: 'center',
pt: { xs: 14, sm: 20 },
pb: { xs: 8, sm: 12 },
}}
>
<Stack
spacing={2}
alignItems="center"
useFlexGap
sx={{ width: { xs: '100%', sm: '70%' } }}
>
<Typography
variant="h1"
sx={{
display: 'flex',
flexDirection: { xs: 'column', sm: 'row' },
alignItems: 'center',
fontSize: 'clamp(3rem, 10vw, 3.5rem)',
}}
>
Our&nbsp;latest&nbsp;
<Typography
component="span"
variant="h1"
sx={{
fontSize: 'inherit',
color: (theme) =>
theme.palette.mode === 'light' ? 'primary.main' : 'primary.light',
}}
>
products
</Typography>
</Typography>
<Typography
textAlign="center"
color="text.secondary"
sx={{ width: { sm: '100%', md: '80%' } }}
>
Explore our cutting-edge dashboard, delivering high-quality solutions
tailored to your needs. Elevate your experience with top-tier features
and services.
</Typography>
<Stack
direction={{ xs: 'column', sm: 'row' }}
spacing={1}
useFlexGap
sx={{ pt: 2, width: { xs: '100%', sm: 'auto' } }}
>
<InputLabel htmlFor="email-hero" sx={visuallyHidden}>
Email
</InputLabel>
<TextField
id="email-hero"
hiddenLabel
size="small"
variant="outlined"
aria-label="Enter your email address"
placeholder="Your email address"
inputProps={{
autocomplete: 'off',
ariaLabel: 'Enter your email address',
}}
/>
<Button variant="contained" color="primary">
Start now
</Button>
</Stack>
<Typography variant="caption" textAlign="center">
By clicking &quot;Start now&quot; you agree to our&nbsp;
<Link href="#" color="primary">
Terms & Conditions
</Link>
.
</Typography>
</Stack>
<Box
id="image"
sx={(theme) => ({
mt: { xs: 8, sm: 10 },
alignSelf: 'center',
height: { xs: 200, sm: 700 },
width: '100%',
backgroundImage:
theme.palette.mode === 'light'
? 'url("/static/images/templates/templates-images/hero-light.png")'
: 'url("/static/images/templates/templates-images/hero-dark.png")',
backgroundSize: 'cover',
borderRadius: '12px',
outline: '1px solid',
outlineColor:
theme.palette.mode === 'light'
? 'hsla(220, 25%, 80%, 0.5)'
: 'hsla(210, 100%, 80%, 0.1)',
boxShadow:
theme.palette.mode === 'light'
? '0 0 12px 8px hsla(220, 25%, 80%, 0.2)'
: '0 0 24px 12px hsla(210, 100%, 25%, 0.2)',
})}
/>
</Container>
</Box>
); );
} };
export default Hero;

View File

@@ -0,0 +1,108 @@
import React, { useState, useEffect } from 'react';
import { Transition } from '@headlessui/react';
import { MoonIcon, SunIcon } from '@heroicons/react/24/outline';
import Logo from '../assets/logotipo.png';
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const [darkMode, setDarkMode] = useState(false);
// Apply dark mode based on the toggle state
useEffect(() => {
if (darkMode) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}, [darkMode]);
return (
<nav className="bg-blue-900 dark:bg-gray-800 shadow-lg sticky top-0 z-50">
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
{/* Logo e Nome da Marca */}
<div className="flex items-center space-x-2">
<img src={Logo} alt="FactoryID Logo" className="h-8 w-auto" />
</div>
{/* Desktop Navigation Links */}
<div className="hidden md:flex space-x-8">
<a href="#home" className="text-gray-800 dark:text-white hover:text-yellow-300 transition duration-300 transform hover:scale-110">
Home
</a>
<a href="#features" className="text-gray-800 dark:text-white hover:text-yellow-300 transition duration-300 transform hover:scale-110">
Features
</a>
<a href="#contact" className="text-gray-800 dark:text-white hover:text-yellow-300 transition duration-300 transform hover:scale-110">
Contact
</a>
<a href="#get-started" className="bg-yellow-300 text-gray-800 px-4 py-2 rounded-lg shadow-md hover:bg-yellow-400 transition duration-300">
Get Started
</a>
</div>
{/* Dark Mode Toggle */}
<div className="flex items-center space-x-4">
<button
onClick={() => setDarkMode(!darkMode)}
className="flex items-center px-2 py-1 rounded-md bg-gray-200 dark:bg-gray-700 dark:text-gray-200 text-gray-800 hover:bg-gray-300 dark:hover:bg-gray-600"
>
{darkMode ? (
<SunIcon className="h-6 w-6 text-yellow-400" />
) : (
<MoonIcon className="h-6 w-6 text-blue-500" />
)}
<span className="ml-2">{darkMode ? 'Light Mode' : 'Dark Mode'}</span>
</button>
{/* Mobile Menu Button */}
<button
onClick={() => setIsOpen(!isOpen)}
type="button"
className="text-gray-800 dark:text-white md:hidden"
aria-controls="mobile-menu"
aria-expanded="false"
>
<span className="sr-only">Open main menu</span>
<svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d={isOpen ? "M6 18L18 6M6 6l12 12" : "M4 6h16M4 12h16M4 18h16"} />
</svg>
</button>
</div>
</div>
</div>
{/* Mobile Menu Dropdown */}
<Transition
show={isOpen}
enter="transition ease-out duration-200 transform"
enterFrom="opacity-0 -translate-y-2"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150 transform"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 -translate-y-2"
>
<div className="md:hidden bg-gray-200 dark:bg-gray-700" id="mobile-menu">
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
<a href="#home" className="block px-3 py-2 rounded-md text-gray-800 dark:text-white hover:bg-purple-600">
Home
</a>
<a href="#features" className="block px-3 py-2 rounded-md text-gray-800 dark:text-white hover:bg-purple-600">
Features
</a>
<a href="#contact" className="block px-3 py-2 rounded-md text-gray-800 dark:text-white hover:bg-purple-600">
Contact
</a>
<a href="#get-started" className="block px-3 py-2 rounded-md bg-yellow-300 text-gray-800 text-center">
Get Started
</a>
</div>
</div>
</Transition>
</nav>
);
};
export default Navbar;

View File

@@ -1,13 +1,3 @@
body { @tailwind base;
margin: 0; @tailwind components;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', @tailwind utilities;
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View File

@@ -3,7 +3,7 @@ import ReactDOM from 'react-dom/client';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
import { Helmet } from 'react-helmet' //import { Helmet } from 'react-helmet'
const root = ReactDOM.createRoot( const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement document.getElementById('root') as HTMLElement

View File

@@ -0,0 +1,11 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: 'class', // Enable dark mode with a class
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}

6
package-lock.json generated Normal file
View File

@@ -0,0 +1,6 @@
{
"name": "Geradores",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

1
package.json Normal file
View File

@@ -0,0 +1 @@
{}