Merge pull request #108 from nagisa77/codex/create-input-components-for-auth-pages

Refactor auth inputs and avatar style
This commit is contained in:
Tim
2025-07-08 10:27:56 +08:00
committed by GitHub
4 changed files with 155 additions and 70 deletions

View File

@@ -0,0 +1,63 @@
<template>
<div class="base-input">
<i v-if="icon" :class="['base-input-icon', icon]"></i>
<component
:is="textarea ? 'textarea' : 'input'"
class="base-input-text"
:type="type"
v-model="innerValue"
v-bind="$attrs"
/>
</div>
</template>
<script>
export default {
name: 'BaseInput',
inheritAttrs: false,
props: {
modelValue: { type: [String, Number], default: '' },
icon: { type: String, default: '' },
type: { type: String, default: 'text' },
textarea: { type: Boolean, default: false }
},
emits: ['update:modelValue'],
computed: {
innerValue: {
get() {
return this.modelValue
},
set(val) {
this.$emit('update:modelValue', val)
}
}
}
}
</script>
<style scoped>
.base-input {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
width: calc(100% - 40px);
padding: 15px 20px;
border-radius: 10px;
border: 1px solid #ccc;
gap: 10px;
margin-bottom: 20px;
}
.base-input-icon {
opacity: 0.5;
font-size: 16px;
}
.base-input-text {
border: none;
outline: none;
width: 100%;
font-size: 16px;
}
</style>

View File

@@ -8,25 +8,18 @@
</div>
<div class="email-login-page-content">
<div class="login-page-input">
<i class="login-page-input-icon fas fa-envelope"></i>
<input
class="login-page-input-text"
v-model="username"
type="text"
placeholder="邮箱/用户名"
>
</div>
<BaseInput
icon="fas fa-envelope"
v-model="username"
placeholder="邮箱/用户名"
/>
<div class="login-page-input">
<i class="login-page-input-icon fas fa-lock"></i>
<input
class="login-page-input-text"
v-model="password"
type="password"
placeholder="密码"
>
</div>
<BaseInput
icon="fas fa-lock"
v-model="password"
type="password"
placeholder="密码"
/>
<div v-if="!isWaitingForLogin" class="login-page-button-primary" @click="submitLogin">
@@ -58,8 +51,10 @@
import { API_BASE_URL, toast } from '../main'
import { setToken } from '../utils/auth'
import { googleSignIn } from '../utils/google'
import BaseInput from '../components/BaseInput.vue'
export default {
name: 'LoginPageView',
components: { BaseInput },
data() {
return {
username: '',

View File

@@ -3,16 +3,26 @@
<div class="settings-title">设置</div>
<div class="profile-section">
<div class="avatar-row">
<img :src="avatar" class="avatar-preview" />
<input type="file" @change="onAvatarChange" />
<!-- label 充当点击区域内部隐藏 input -->
<label class="avatar-container">
<img :src="avatar" class="avatar-preview" />
<!-- 半透明蒙层hover 时出现 -->
<div class="avatar-overlay">更换头像</div>
<input
type="file"
class="avatar-input"
accept="image/*"
@change="onAvatarChange"
/>
</label>
</div>
<div class="form-row">
<label>用户名</label>
<input v-model="username" type="text" />
<BaseInput v-model="username" />
</div>
<div class="form-row">
<label>自我介绍</label>
<textarea v-model="introduction" rows="3" />
<BaseInput v-model="introduction" textarea rows="3" />
</div>
</div>
<div v-if="role === 'ADMIN'" class="admin-section">
@@ -42,8 +52,10 @@
<script>
import { API_BASE_URL, toast } from '../main'
import { getToken, fetchCurrentUser } from '../utils/auth'
import BaseInput from '../components/BaseInput.vue'
export default {
name: 'SettingsPageView',
components: { BaseInput },
data() {
return {
username: '',
@@ -163,4 +175,36 @@ export default {
display: flex;
gap: 10px;
}
/* 容器:定位 + 光标 */
.avatar-container {
position: relative;
display: inline-block;
cursor: pointer;
}
/* 隐藏默认文件选择按钮 */
.avatar-input {
display: none;
}
/* 蒙层初始透明hover 时渐显 */
.avatar-overlay {
position: absolute;
inset: 0;
border-radius: 40px;
background: rgba(0, 0, 0, 0.4);
color: #fff;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.2s ease-in-out;
}
/* hover 触发 */
.avatar-container:hover .avatar-overlay {
opacity: 1;
}
</style>

View File

@@ -8,51 +8,36 @@
</div>
<div v-if="emailStep === 0" class="email-signup-page-content">
<div class="signup-page-input">
<i class="signup-page-input-icon fas fa-envelope"></i>
<input
class="signup-page-input-text"
v-model="email"
@input="emailError = ''"
type="text"
placeholder="邮箱"
>
</div>
<BaseInput
icon="fas fa-envelope"
v-model="email"
@input="emailError = ''"
placeholder="邮箱"
/>
<div v-if="emailError" class="error-message">{{ emailError }}</div>
<div class="signup-page-input">
<i class="signup-page-input-icon fas fa-user"></i>
<input
class="signup-page-input-text"
v-model="username"
@input="usernameError = ''"
type="text"
placeholder="用户名"
>
</div>
<BaseInput
icon="fas fa-user"
v-model="username"
@input="usernameError = ''"
placeholder="用户名"
/>
<div v-if="usernameError" class="error-message">{{ usernameError }}</div>
<div class="signup-page-input">
<i class="signup-page-input-icon fas fa-lock"></i>
<input
class="signup-page-input-text"
v-model="password"
@input="passwordError = ''"
type="password"
placeholder="密码"
>
</div>
<BaseInput
icon="fas fa-lock"
v-model="password"
@input="passwordError = ''"
type="password"
placeholder="密码"
/>
<div v-if="passwordError" class="error-message">{{ passwordError }}</div>
<div class="signup-page-input">
<i class="signup-page-input-icon fas fa-user"></i>
<input
class="signup-page-input-text"
v-model="nickname"
type="text"
placeholder="昵称 (可选)"
>
</div>
<BaseInput
icon="fas fa-user"
v-model="nickname"
placeholder="昵称 (可选)"
/>
<div v-if="!isWaitingForEmailSent" class="signup-page-button-primary" @click="sendVerification">
<div class="signup-page-button-text">验证邮箱</div>
@@ -69,15 +54,11 @@
</div>
<div v-if="emailStep === 1" class="email-signup-page-content">
<div class="signup-page-input">
<i class="signup-page-input-icon fas fa-envelope"></i>
<input
class="signup-page-input-text"
v-model="code"
type="text"
placeholder="邮箱验证码"
>
</div>
<BaseInput
icon="fas fa-envelope"
v-model="code"
placeholder="邮箱验证码"
/>
<div v-if="!isWaitingForEmailVerified" class="signup-page-button-primary" @click="verifyCode">
<div class="signup-page-button-text">注册</div>
</div>
@@ -102,8 +83,10 @@
<script>
import { API_BASE_URL, toast } from '../main'
import { googleSignIn } from '../utils/google'
import BaseInput from '../components/BaseInput.vue'
export default {
name: 'SignupPageView',
components: { BaseInput },
data() {
return {