feat(login): CASSIC 红金风登录页 + 玻璃按钮欢迎页
需求:
1. 默认访问 /metalinfo 未登录时跳到 CASSIC 风格登录页
2. 登录页支持两种模式: 账号密码登录 / 统一身份登录(CAS)
3. 登录成功跳转 /welcome (原蓝色登录页布局,但右侧表单换成玻璃风"立即体验"按钮)
变更:
- 新增 chat_web_front/src/views/welcome/index.vue
- 复用现有蓝色 Waves + projectLogo + "聚尖端之力" 文案
- 玻璃磨砂按钮(backdrop-filter blur),圆角胶囊 + 圆形箭头
- 点击 → router.push('/chat')
- 重写 chat_web_front/src/views/login/index.vue
- CASSIC 红金背景图(cassicLoginBg.jpg, 1920x1080 by /Users/jayliu/gangyan/ui)
- "登录注册中心" 标题 + 红色短分隔条
- 账号/密码/验证码 三段式表单 (el-icon User/Lock/Stamp)
- "短信验证登录" 链接切换到 SMS 模式
- 主红登录按钮 + 次级"统一身份登录(CASSIC)"白底红边按钮
- 登录成功后 router.push('/welcome')
- CAS 回调 cas_token 处理保留
- chat_web_front/src/router/index.ts:
- / → 默认重定向改为 /welcome (原来到 /chat)
- 新增 /welcome 路由
- 复制 ui/微信图片_20260423163044_262_1531.jpg 到
src/assets/images/login/cassicLoginBg.jpg
未做:
- SMS 验证码后端接口 (loginByTel) 仅留前端倒计时占位
- 图形验证码后端 (showCaptcha 默认关)
- 老素材 loginBg.png 仍由 welcome 页使用,未删
测试:
- 访问 /metalinfo → 未登录跳 /login (CASSIC 红金)
- 账号密码登录 / CAS 登录 → 跳 /welcome
- /welcome 点"立即体验" → /chat
This commit is contained in:
BIN
chat_web_front/src/assets/images/login/cassicLoginBg.jpg
Normal file
BIN
chat_web_front/src/assets/images/login/cassicLoginBg.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
@@ -7,13 +7,18 @@ const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
name: '/',
|
||||
redirect: '/chat'
|
||||
redirect: '/welcome'
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'Login',
|
||||
component: () => import('@/views/login/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/welcome',
|
||||
name: 'Welcome',
|
||||
component: () => import('@/views/welcome/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/chat',
|
||||
name: 'Chat',
|
||||
|
||||
@@ -1,215 +1,351 @@
|
||||
<template>
|
||||
<div class="loginPage">
|
||||
<Waves></Waves>
|
||||
<div>
|
||||
<img :src="projectLogo" alt="" class="loginLogo" />
|
||||
</div>
|
||||
<div class="loginContent">
|
||||
<div class="loginTitle">
|
||||
<div>
|
||||
聚尖端之力,创多维平台
|
||||
<br />
|
||||
<span class="loginInfo">
|
||||
聚合科技动能,扩展创新疆界,引领行业跃迁升级
|
||||
</span>
|
||||
<div class="cassicLogin">
|
||||
<!-- 背景:CASSIC logo + 红金渐变 + 波纹粒子(图片直接做底) -->
|
||||
<div class="bgImage"></div>
|
||||
|
||||
<!-- 中央登录卡 -->
|
||||
<div class="loginCard">
|
||||
<h2 class="title">登录注册中心</h2>
|
||||
<div class="titleBar"></div>
|
||||
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
hide-required-asterisk
|
||||
class="form"
|
||||
@submit.prevent
|
||||
>
|
||||
<!-- 账号 -->
|
||||
<el-form-item prop="tel">
|
||||
<el-input
|
||||
v-model.trim="form.tel"
|
||||
:placeholder="loginMode === 'sms' ? '请输入手机号' : '请输入账号'"
|
||||
size="large"
|
||||
>
|
||||
<template #prefix>
|
||||
<span class="iconBox"><el-icon><User /></el-icon></span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 密码 -->
|
||||
<el-form-item v-if="loginMode === 'password'" prop="password">
|
||||
<el-input
|
||||
v-model.trim="form.password"
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
size="large"
|
||||
show-password
|
||||
>
|
||||
<template #prefix>
|
||||
<span class="iconBox"><el-icon><Lock /></el-icon></span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 验证码(图形 / 短信) -->
|
||||
<el-form-item prop="captcha" v-if="loginMode === 'sms' || showCaptcha">
|
||||
<div class="captchaRow">
|
||||
<el-input
|
||||
v-model.trim="form.captcha"
|
||||
:placeholder="loginMode === 'sms' ? '请输入短信验证码' : '请输入验证码'"
|
||||
size="large"
|
||||
>
|
||||
<template #prefix>
|
||||
<span class="iconBox"><el-icon><Stamp /></el-icon></span>
|
||||
</template>
|
||||
</el-input>
|
||||
<button
|
||||
type="button"
|
||||
class="captchaBtn"
|
||||
:disabled="smsCountdown > 0"
|
||||
@click="handleCaptcha"
|
||||
>
|
||||
{{ smsCountdown > 0 ? `${smsCountdown}s` : (loginMode === 'sms' ? '获取验证码' : '看不清') }}
|
||||
</button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 切换模式 -->
|
||||
<div class="switchModeRow">
|
||||
<a class="modeLink" @click="toggleMode">
|
||||
{{ loginMode === 'password' ? '短信验证登录' : '账号密码登录' }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loginOperate">
|
||||
<img
|
||||
:src="projectLogo2"
|
||||
class="logoImg"
|
||||
alt=""
|
||||
/>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
label-position="top"
|
||||
label-width="auto"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
style="width: 20vw; margin-top: 5%"
|
||||
hide-required-asterisk
|
||||
|
||||
<!-- 主登录按钮 -->
|
||||
<el-button
|
||||
class="primaryBtn"
|
||||
:loading="submitting"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
<el-form-item label="手机号" prop="tel">
|
||||
<el-input v-model.trim="ruleForm.tel" />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model.trim="ruleForm.password" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item prop="checked">
|
||||
<el-checkbox v-model="ruleForm.checked" label="" size="large" />
|
||||
<span
|
||||
>勾选即代表您阅读并同意<a
|
||||
target="_blank"
|
||||
href="http://www.metalinfo.cn/agreement.html?pageId=c03923c64e6b4d0896488212054b1742"
|
||||
style="color: #0969da"
|
||||
>《用户协议》</a
|
||||
></span
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
style="width: 100%; margin-top: 20px"
|
||||
@click="submitForm(ruleFormRef)"
|
||||
:disabled="isDisabled"
|
||||
>
|
||||
{{ loginTip }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
style="width: 100%; background: #FF2500; color: #fff; border-color: #FF2500;"
|
||||
@click="goCasLogin"
|
||||
>
|
||||
通过统一身份登录
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
登 录
|
||||
</el-button>
|
||||
|
||||
<!-- 统一身份登录 -->
|
||||
<el-button class="casBtn" @click="goCasLogin">
|
||||
统一身份登录(CASSIC)
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang='ts'>
|
||||
import { computed, ref, onMounted, reactive } from "vue";
|
||||
import projectLogo from "@/assets/images/login/projectLogo-white.svg";
|
||||
import projectLogo2 from "@/assets/images/login/projectLogo.svg";
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import type { FormInstance, FormRules } from "element-plus";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { User, Lock, Stamp } from "@element-plus/icons-vue";
|
||||
import { fetchVerify } from "@/api";
|
||||
import { useAuthStore } from "@/store";
|
||||
import { useRouter } from "vue-router";
|
||||
import Waves from "../../components/Waves.vue";
|
||||
|
||||
interface RuleForm {
|
||||
interface LoginForm {
|
||||
tel: string;
|
||||
password: string;
|
||||
checked: boolean;
|
||||
captcha: string;
|
||||
loginType: number;
|
||||
}
|
||||
interface Token {
|
||||
token: string;
|
||||
refreshToken: string;
|
||||
expiresIn: number;
|
||||
}
|
||||
const ruleForm = reactive<RuleForm>({
|
||||
|
||||
const form = reactive<LoginForm>({
|
||||
tel: "",
|
||||
password: "",
|
||||
checked: true,
|
||||
captcha: "",
|
||||
loginType: 3,
|
||||
});
|
||||
const ruleFormRef = ref<FormInstance>();
|
||||
const authStore = useAuthStore();
|
||||
const router = useRouter();
|
||||
const isDisabled = ref<Boolean>(false);
|
||||
const loginTip = ref<string>("登录");
|
||||
|
||||
const validateChecked = (rule: any, value: any, callback: any) => {
|
||||
if (!value) {
|
||||
callback(new Error("请勾选“用户协议”"));
|
||||
const formRef = ref<FormInstance>();
|
||||
const router = useRouter();
|
||||
const authStore = useAuthStore();
|
||||
const submitting = ref(false);
|
||||
const loginMode = ref<"password" | "sms">("password"); // password = 账号密码登录;sms = 短信验证登录
|
||||
const showCaptcha = ref(false); // 账号密码模式下,可选图形验证码(暂未启用,留位)
|
||||
const smsCountdown = ref(0);
|
||||
|
||||
const rules = reactive<FormRules<LoginForm>>({
|
||||
tel: [{ required: true, message: "请输入账号 / 手机号", trigger: "blur" }],
|
||||
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||
});
|
||||
|
||||
const toggleMode = () => {
|
||||
loginMode.value = loginMode.value === "password" ? "sms" : "password";
|
||||
form.captcha = "";
|
||||
};
|
||||
|
||||
let countdownTimer: number | null = null;
|
||||
const handleCaptcha = () => {
|
||||
if (loginMode.value === "sms") {
|
||||
if (!form.tel) {
|
||||
ElMessage.warning("请先输入手机号");
|
||||
return;
|
||||
}
|
||||
// 触发短信发送(后端接口待联调;先做倒计时占位)
|
||||
smsCountdown.value = 60;
|
||||
countdownTimer = window.setInterval(() => {
|
||||
smsCountdown.value -= 1;
|
||||
if (smsCountdown.value <= 0 && countdownTimer) {
|
||||
clearInterval(countdownTimer);
|
||||
countdownTimer = null;
|
||||
}
|
||||
}, 1000);
|
||||
ElMessage.info("短信验证码功能尚未接入后端,先用账号密码模式登录");
|
||||
} else {
|
||||
callback();
|
||||
ElMessage.info("图形验证码暂未启用");
|
||||
}
|
||||
};
|
||||
const rules = reactive<FormRules<RuleForm>>({
|
||||
tel: [{ required: true, message: "请输入手机号", trigger: "blur" }],
|
||||
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||
checked: {
|
||||
required: true,
|
||||
message: "请勾选“用户协议”",
|
||||
trigger: "blur",
|
||||
validator: validateChecked,
|
||||
},
|
||||
});
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
isDisabled.value = true;
|
||||
loginTip.value = "登录中...";
|
||||
handleVerify();
|
||||
} else {
|
||||
console.log("error submit!", fields);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return;
|
||||
await formRef.value.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
submitting.value = true;
|
||||
try {
|
||||
const res = await fetchVerify<{ token: string }>(form);
|
||||
if (res.code === 200) {
|
||||
authStore.setToken(res.data.token);
|
||||
router.push("/welcome");
|
||||
} else {
|
||||
ElMessage.error(res.msg || "登录失败");
|
||||
}
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleVerify = async () => {
|
||||
try {
|
||||
fetchVerify<Token>(ruleForm).then((res) => {
|
||||
if (res.code === 200) {
|
||||
authStore.setToken(res.data.token);
|
||||
router.push("/chat");
|
||||
} else {
|
||||
isDisabled.value = false;
|
||||
loginTip.value = "登录";
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
}
|
||||
};
|
||||
|
||||
// 跳后端 CAS 入口;后端 302 跳 CAS 服务器
|
||||
const goCasLogin = () => {
|
||||
window.location.href = `/chat_web_backend/cas/login`;
|
||||
};
|
||||
|
||||
// 处理 CAS 回调:URL 含 cas_token 参数 → 存 token 后跳首页
|
||||
// CAS 回调:URL 含 cas_token → 存 token + 跳 welcome
|
||||
onMounted(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const casToken = params.get("cas_token");
|
||||
if (casToken) {
|
||||
authStore.setToken(casToken);
|
||||
window.history.replaceState({}, document.title, window.location.pathname + window.location.hash.split("?")[0]);
|
||||
router.push("/chat");
|
||||
window.history.replaceState(
|
||||
{},
|
||||
document.title,
|
||||
window.location.pathname + window.location.hash.split("?")[0]
|
||||
);
|
||||
router.push("/welcome");
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.loginPage {
|
||||
.cassicLogin {
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-image: url("../../assets/images/login/loginBg.png");
|
||||
background-size: cover;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.loginLogo {
|
||||
|
||||
.bgImage {
|
||||
position: absolute;
|
||||
height: 6.1vh;
|
||||
margin: 2rem;
|
||||
inset: 0;
|
||||
background-image: url("../../assets/images/login/cassicLoginBg.jpg");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
z-index: 0;
|
||||
}
|
||||
.loginContent {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
|
||||
.loginCard {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 460px;
|
||||
padding: 40px 40px 36px;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
box-shadow: 0 12px 40px rgba(120, 0, 0, 0.18);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.loginTitle {
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
font-size: 7vh;
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #c10b08;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
.loginInfo {
|
||||
font-weight: 300;
|
||||
font-size: 2vh;
|
||||
|
||||
.titleBar {
|
||||
width: 36px;
|
||||
height: 3px;
|
||||
background: #c10b08;
|
||||
border-radius: 2px;
|
||||
margin: 12px auto 28px;
|
||||
}
|
||||
.loginOperate {
|
||||
background: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 0.75rem;
|
||||
align-items: center;
|
||||
padding: 4vh;
|
||||
.logoImg {
|
||||
height: 5vh;
|
||||
|
||||
.form {
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 0 1px #f3d2cf inset;
|
||||
background: #fff;
|
||||
padding: 4px 12px;
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper.is-focus) {
|
||||
box-shadow: 0 0 0 1px #c10b08 inset;
|
||||
}
|
||||
}
|
||||
::v-deep .is-required .el-form-item__label::after {
|
||||
content: "*";
|
||||
color: #ff0000;
|
||||
margin-left: 4px;
|
||||
|
||||
.iconBox {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 4px;
|
||||
background: #c10b08;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
margin-right: 4px;
|
||||
i {
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.captchaRow {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 10px;
|
||||
align-items: stretch;
|
||||
.el-input {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.captchaBtn {
|
||||
flex: 0 0 110px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #f3d2cf;
|
||||
color: #c10b08;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.captchaBtn:hover:not(:disabled) {
|
||||
background: #e8b9b6;
|
||||
}
|
||||
.captchaBtn:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.switchModeRow {
|
||||
margin: 4px 0 18px;
|
||||
}
|
||||
.modeLink {
|
||||
font-size: 13px;
|
||||
color: #c10b08;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.primaryBtn {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #c10b08;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
letter-spacing: 8px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: #a30907;
|
||||
}
|
||||
}
|
||||
|
||||
.casBtn {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
margin-top: 12px;
|
||||
margin-left: 0;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #c10b08;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
color: #c10b08;
|
||||
font-size: 15px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
border-color: #a30907;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
111
chat_web_front/src/views/welcome/index.vue
Normal file
111
chat_web_front/src/views/welcome/index.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div class="welcomePage">
|
||||
<Waves></Waves>
|
||||
<img :src="projectLogo" alt="" class="welcomeLogo" />
|
||||
<div class="welcomeContent">
|
||||
<div class="welcomeTitle">
|
||||
<div>
|
||||
聚尖端之力,创多维平台
|
||||
<br />
|
||||
<span class="welcomeInfo">
|
||||
聚合科技动能,扩展创新疆界,引领行业跃迁升级
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="enterAction">
|
||||
<button class="glassBtn" @click="goChat">
|
||||
<span>立即体验</span>
|
||||
<i class="arrow">→</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from "vue-router";
|
||||
import projectLogo from "@/assets/images/login/projectLogo-white.svg";
|
||||
import Waves from "../../components/Waves.vue";
|
||||
|
||||
const router = useRouter();
|
||||
const goChat = () => {
|
||||
router.push("/chat");
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.welcomePage {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-image: url("../../assets/images/login/loginBg.png");
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.welcomeLogo {
|
||||
position: absolute;
|
||||
height: 6.1vh;
|
||||
margin: 2rem;
|
||||
}
|
||||
.welcomeContent {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
z-index: 1;
|
||||
}
|
||||
.welcomeTitle {
|
||||
font-weight: 700;
|
||||
font-size: 7vh;
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.welcomeInfo {
|
||||
font-weight: 300;
|
||||
font-size: 2vh;
|
||||
}
|
||||
.enterAction {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.glassBtn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 18px 44px;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
backdrop-filter: blur(14px);
|
||||
-webkit-backdrop-filter: blur(14px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.35);
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s ease;
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.25),
|
||||
0 8px 32px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
.glassBtn:hover {
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
border-color: rgba(255, 255, 255, 0.6);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.glassBtn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.glassBtn .arrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
font-style: normal;
|
||||
font-size: 18px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user