新增登录页面
This commit is contained in:
5
pom.xml
5
pom.xml
@@ -164,6 +164,11 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
package com.mini.capi.api;
|
package com.mini.capi.biz;
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class startApp {
|
public class LoginController {
|
||||||
|
|
||||||
@GetMapping("/")
|
|
||||||
|
@GetMapping("/login")
|
||||||
|
public String showLoginPage() {
|
||||||
|
return "login";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/swagger")
|
||||||
public String redirectToSwagger() {
|
public String redirectToSwagger() {
|
||||||
return "redirect:/swagger-ui/index.html";
|
return "redirect:/swagger-ui/index.html";
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,6 @@ public class WebMvcConfig implements WebMvcConfigurer{
|
|||||||
@Override
|
@Override
|
||||||
public void addViewControllers(ViewControllerRegistry registry) {
|
public void addViewControllers(ViewControllerRegistry registry) {
|
||||||
// 访问根路径 "/" 时,自动重定向到 Swagger UI
|
// 访问根路径 "/" 时,自动重定向到 Swagger UI
|
||||||
registry.addRedirectViewController("/", "/swagger-ui/index.html");
|
registry.addRedirectViewController("/", "/login");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
src/main/resources/static/images/login-brand.png
Normal file
BIN
src/main/resources/static/images/login-brand.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
413
src/main/resources/templates/login.html
Normal file
413
src/main/resources/templates/login.html
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>智慧门户 - 登录</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- 配置Tailwind -->
|
||||||
|
<script>
|
||||||
|
tailwind.config = {
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: '#165DFF',
|
||||||
|
secondary: '#36BFFA',
|
||||||
|
accent: '#FFD166',
|
||||||
|
darkBlue: '#0F172A',
|
||||||
|
lightBlue: '#E0F2FE',
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
inter: ['Inter', 'system-ui', 'sans-serif'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style type="text/tailwindcss">
|
||||||
|
@layer utilities {
|
||||||
|
.content-auto {
|
||||||
|
content-visibility: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-gradient-tech {
|
||||||
|
background: linear-gradient(135deg, #0F172A 0%, #1E40AF 50%, #3B82F6 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-glass {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-shadow {
|
||||||
|
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cube {
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
animation: rotate 15s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float {
|
||||||
|
animation: float 6s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pulse {
|
||||||
|
animation: pulse 4s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-backdrop {
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
-webkit-backdrop-filter: blur(5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 动画定义 */
|
||||||
|
@keyframes rotate {
|
||||||
|
0% {
|
||||||
|
transform: rotateX(0deg) rotateY(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotateX(360deg) rotateY(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes float {
|
||||||
|
0% {
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(-20px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
opacity: 0.6;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0.6;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeOut {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-element {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(59, 130, 246, 0.15);
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-modal {
|
||||||
|
animation: fadeIn 0.3s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-modal.hide {
|
||||||
|
animation: fadeOut 0.3s ease-in forwards;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="font-inter min-h-screen flex items-center justify-center p-4 md:p-0 overflow-hidden">
|
||||||
|
<!-- 背景和装饰元素 -->
|
||||||
|
<div class="fixed inset-0 bg-gradient-tech z-0"></div>
|
||||||
|
<div class="geo-element w-32 h-32 top-1/4 left-1/6 float" style="animation-delay: 0s;"></div>
|
||||||
|
<div class="geo-element w-16 h-16 bottom-1/3 right-1/5 float" style="animation-delay: 1s;"></div>
|
||||||
|
<div class="geo-element w-24 h-24 top-2/3 left-1/4 float" style="animation-delay: 2s;"></div>
|
||||||
|
<div class="geo-element w-20 h-20 bottom-1/4 right-1/3 float" style="animation-delay: 1.5s;"></div>
|
||||||
|
<div class="fixed inset-0 z-0 opacity-30">
|
||||||
|
<div class="absolute inset-0"
|
||||||
|
style="background-image: radial-gradient(rgba(255,255,255,0.3) 1px, transparent 1px); background-size: 30px 30px;"></div>
|
||||||
|
</div>
|
||||||
|
<div class="fixed top-1/3 right-1/4 w-32 h-32 cube z-0">
|
||||||
|
<div class="absolute inset-0 bg-primary/20 rounded-lg transform rotate-x-0 rotate-y-0"></div>
|
||||||
|
<div class="absolute inset-0 bg-accent/20 rounded-lg transform rotate-x-90 rotate-y-0"></div>
|
||||||
|
<div class="absolute inset-0 bg-secondary/20 rounded-lg transform rotate-x-0 rotate-y-90"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 错误提示弹窗 (默认隐藏) -->
|
||||||
|
<div id="errorModal" class="fixed inset-0 z-50 flex items-center justify-center hidden">
|
||||||
|
<!-- 遮罩层 -->
|
||||||
|
<div class="absolute inset-0 bg-darkBlue/70 modal-backdrop" id="modalBackdrop"></div>
|
||||||
|
<!-- 弹窗内容 -->
|
||||||
|
<div class="relative bg-white/10 backdrop-blur-xl border border-white/20 rounded-xl p-6 w-full max-w-md shadow-2xl error-modal">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<div class="w-16 h-16 mx-auto bg-red-500/20 rounded-full flex items-center justify-center mb-4">
|
||||||
|
<i class="fa fa-exclamation-triangle text-red-400 text-2xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-bold text-white mb-2">登录失败</h3>
|
||||||
|
<p class="text-white/80" id="modalErrorMessage">账号或密码错误,请重新输入</p>
|
||||||
|
</div>
|
||||||
|
<button id="closeModal"
|
||||||
|
class="w-full mt-4 bg-accent hover:bg-accent/90 text-darkBlue font-medium py-2.5 px-4 rounded-lg transition-all duration-300">
|
||||||
|
确定
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 登录卡片 -->
|
||||||
|
<div class="relative w-full max-w-5xl bg-white/10 backdrop-blur-xl rounded-2xl shadow-2xl overflow-hidden flex flex-col md:flex-row z-10 border border-white/20">
|
||||||
|
<!-- 左侧品牌区域 -->
|
||||||
|
<div class="p-6 md:p-10 lg:p-12 flex-1 flex flex-col justify-between relative">
|
||||||
|
<div class="absolute -top-10 -left-10 w-40 h-40 bg-accent/10 rounded-full blur-3xl"></div>
|
||||||
|
<div class="absolute -bottom-20 -right-10 w-60 h-60 bg-primary/20 rounded-full blur-3xl"></div>
|
||||||
|
<div class="relative">
|
||||||
|
<p class="text-white/80 text-base md:text-lg max-w-md">
|
||||||
|
一站式智能管理平台,融合前沿技术,为您提供高效、安全、便捷的服务体验
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="mt-10 md:mt-20 space-y-6 relative">
|
||||||
|
<div class="bg-glass p-4 rounded-xl border border-white/10 hover:border-white/30 transition-all duration-300 transform hover:-translate-y-1">
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<div class="w-12 h-12 rounded-full bg-accent/20 flex items-center justify-center text-accent pulse">
|
||||||
|
<i class="fa fa-shield text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-lg text-white">安全可靠</h3>
|
||||||
|
<p class="text-white/70 text-sm">多重加密保障数据安全</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-glass p-4 rounded-xl border border-white/10 hover:border-white/30 transition-all duration-300 transform hover:-translate-y-1">
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<div class="w-12 h-12 rounded-full bg-secondary/20 flex items-center justify-center text-secondary pulse">
|
||||||
|
<i class="fa fa-bolt text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-lg text-white">高效便捷</h3>
|
||||||
|
<p class="text-white/70 text-sm">智能服务提升工作效率</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-glass p-4 rounded-xl border border-white/10 hover:border-white/30 transition-all duration-300 transform hover:-translate-y-1">
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<div class="w-12 h-12 rounded-full bg-primary/20 flex items-center justify-center text-primary pulse">
|
||||||
|
<i class="fa fa-cubes text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-lg text-white">智能互联</h3>
|
||||||
|
<p class="text-white/70 text-sm">全方位数据互通互联</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-10 md:mt-16 text-center md:text-left text-white/60 text-sm relative">
|
||||||
|
<p>© 2023 智慧门户 版权所有</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧登录表单区域 -->
|
||||||
|
<div class="flex-1 p-6 md:p-10 lg:p-12 bg-white/10 backdrop-blur-xl border-l border-white/20 flex flex-col justify-center">
|
||||||
|
<div class="max-w-md mx-auto w-full">
|
||||||
|
<div class="text-center md:text-left mb-10 relative">
|
||||||
|
<div class="absolute top-0 right-0 md:right-0">
|
||||||
|
<img th:src="@{/images/login-brand.png}" alt="logo">
|
||||||
|
</div>
|
||||||
|
<h1 class="text-[clamp(2rem,5vw,3rem)] font-bold mb-4 text-white text-shadow">智慧门户</h1>
|
||||||
|
<p class="text-white/70">欢迎登录系统</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form id="loginForm" class="space-y-6">
|
||||||
|
<!-- 用户名输入 -->
|
||||||
|
<div class="space-y-3">
|
||||||
|
<label for="username" class="block text-sm font-medium text-white/80">账号</label>
|
||||||
|
<div class="relative">
|
||||||
|
<div class="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
|
||||||
|
<i class="fa fa-user text-white/50"></i>
|
||||||
|
</div>
|
||||||
|
<input type="text" id="username" name="username"
|
||||||
|
class="block w-full pl-12 pr-4 py-3 bg-white/10 border border-white/20 rounded-lg focus:ring-2 focus:ring-accent/50 focus:border-accent text-white placeholder-white/40 transition-all duration-300 outline-none"
|
||||||
|
placeholder="请输入账号" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 密码输入 -->
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<label for="password" class="block text-sm font-medium text-white/80">密码</label>
|
||||||
|
<a href="#" class="text-sm text-accent hover:text-accent/80 transition-colors">忘记密码?</a>
|
||||||
|
</div>
|
||||||
|
<div class="relative">
|
||||||
|
<div class="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
|
||||||
|
<i class="fa fa-lock text-white/50"></i>
|
||||||
|
</div>
|
||||||
|
<input type="password" id="password" name="password"
|
||||||
|
class="block w-full pl-12 pr-12 py-3 bg-white/10 border border-white/20 rounded-lg focus:ring-2 focus:ring-accent/50 focus:border-accent text-white placeholder-white/40 transition-all duration-300 outline-none"
|
||||||
|
placeholder="请输入密码" required>
|
||||||
|
<button type="button" id="togglePassword"
|
||||||
|
class="absolute inset-y-0 right-0 pr-4 flex items-center text-white/50 hover:text-white transition-colors">
|
||||||
|
<i class="fa fa-eye-slash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 记住密码 -->
|
||||||
|
<div class="flex items-center">
|
||||||
|
<input id="remember" name="remember" type="checkbox"
|
||||||
|
class="h-5 w-5 text-accent focus:ring-accent border-white/30 rounded transition-colors bg-white/10">
|
||||||
|
<label for="remember" class="ml-3 block text-sm text-white/70">
|
||||||
|
记住我 30 天
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 登录按钮 -->
|
||||||
|
<button type="submit"
|
||||||
|
class="w-full bg-accent hover:bg-accent/90 text-darkBlue font-medium py-3 px-4 rounded-lg transition-all duration-300 transform hover:scale-[1.02] active:scale-[0.98] focus:outline-none focus:ring-2 focus:ring-accent/50 focus:ring-offset-2 focus:ring-offset-white/10">
|
||||||
|
登录
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 密码显示/隐藏切换
|
||||||
|
const togglePassword = document.getElementById('togglePassword');
|
||||||
|
const password = document.getElementById('password');
|
||||||
|
togglePassword.addEventListener('click', () => {
|
||||||
|
const type = password.getAttribute('type') === 'password' ? 'text' : 'password';
|
||||||
|
password.setAttribute('type', type);
|
||||||
|
const icon = togglePassword.querySelector('i');
|
||||||
|
if (type === 'password') {
|
||||||
|
icon.classList.remove('fa-eye');
|
||||||
|
icon.classList.add('fa-eye-slash');
|
||||||
|
} else {
|
||||||
|
icon.classList.remove('fa-eye-slash');
|
||||||
|
icon.classList.add('fa-eye');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 错误弹窗相关元素
|
||||||
|
const errorModal = document.getElementById('errorModal');
|
||||||
|
const closeModal = document.getElementById('closeModal');
|
||||||
|
const modalBackdrop = document.getElementById('modalBackdrop');
|
||||||
|
const modalErrorMessage = document.getElementById('modalErrorMessage');
|
||||||
|
|
||||||
|
// 显示错误弹窗
|
||||||
|
function showErrorModal(message = '账号或密码错误,请重新输入') {
|
||||||
|
modalErrorMessage.textContent = message;
|
||||||
|
errorModal.classList.remove('hidden');
|
||||||
|
// 阻止页面滚动
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏错误弹窗
|
||||||
|
function hideErrorModal() {
|
||||||
|
errorModal.querySelector('.error-modal').classList.add('hide');
|
||||||
|
setTimeout(() => {
|
||||||
|
errorModal.classList.add('hidden');
|
||||||
|
errorModal.querySelector('.error-modal').classList.remove('hide');
|
||||||
|
// 恢复页面滚动
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭弹窗事件
|
||||||
|
closeModal.addEventListener('click', hideErrorModal);
|
||||||
|
modalBackdrop.addEventListener('click', hideErrorModal);
|
||||||
|
// 按ESC键关闭弹窗
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape' && !errorModal.classList.contains('hidden')) {
|
||||||
|
hideErrorModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单提交处理
|
||||||
|
const loginForm = document.getElementById('loginForm');
|
||||||
|
loginForm.addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// 获取表单数据
|
||||||
|
const username = document.getElementById('username').value;
|
||||||
|
const password = document.getElementById('password').value;
|
||||||
|
const remember = document.getElementById('remember').checked;
|
||||||
|
|
||||||
|
// 模拟登录加载状态
|
||||||
|
const submitButton = loginForm.querySelector('button[type="submit"]');
|
||||||
|
const originalText = submitButton.innerHTML;
|
||||||
|
submitButton.disabled = true;
|
||||||
|
submitButton.innerHTML = '<i class="fa fa-spinner fa-spin mr-2"></i> 登录中...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 发送登录请求到后端
|
||||||
|
const response = await fetch('userLogin', { // 替换为实际后端登录接口
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
remember
|
||||||
|
}),
|
||||||
|
credentials: 'include'
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok && result.success) {
|
||||||
|
// 登录成功,跳转到首页
|
||||||
|
window.location.href = '/index'; // 替换为实际首页路径
|
||||||
|
} else {
|
||||||
|
// 登录失败,显示错误弹窗
|
||||||
|
const errorMsg = result.message || '账号或密码错误,请重新输入';
|
||||||
|
showErrorModal(errorMsg);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 网络错误等异常情况
|
||||||
|
console.error('登录请求失败:', error);
|
||||||
|
showErrorModal('网络异常,请稍后重试');
|
||||||
|
} finally {
|
||||||
|
// 恢复按钮状态
|
||||||
|
submitButton.disabled = false;
|
||||||
|
submitButton.innerHTML = originalText;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 输入框交互效果
|
||||||
|
const inputs = document.querySelectorAll('input');
|
||||||
|
inputs.forEach(input => {
|
||||||
|
input.addEventListener('focus', () => {
|
||||||
|
input.parentElement.classList.add('scale-[1.02]');
|
||||||
|
});
|
||||||
|
input.addEventListener('blur', () => {
|
||||||
|
input.parentElement.classList.remove('scale-[1.02]');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user