Commit 6f2e33b4 by Ivan

feat: 文案翻译

parent b89d601f
......@@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base
inertia_share do
{
auth: authenticated?.user&.as_json(only: [ :id, :name, :email_address, :roles ])
auth: authenticated?&.user&.as_json(only: [ :id, :name, :email_address, :roles ])
}
end
end
class SessionsController < ApplicationController
allow_unauthenticated_access only: %i[ new create ]
rate_limit to: 10, within: 3.minutes, only: :create, with: -> {
flash.now[:alert] = "Too many login attempts. Try again later."
rate_limit to: 10, within: 3.minutes, only: :create, with: -> {
flash.now[:alert] = "操作过频,请稍后重试"
render inertia: "sessions/New", props: { flash: flash.to_h }
}
......@@ -23,7 +23,7 @@ class SessionsController < ApplicationController
redirect_to after_authentication_url
else
# For Inertia.js, we need to render the component with flash messages
flash.now[:alert] = "Try another email address or password."
flash.now[:alert] = "账户或密码错误"
render inertia: "sessions/New", props: {
flash: flash.to_h
}
......@@ -32,7 +32,7 @@ class SessionsController < ApplicationController
def destroy
terminate_session
redirect_to new_session_path, notice: "You have been logged out."
redirect_to new_session_path, notice: "你已登出"
end
def index
......@@ -57,18 +57,18 @@ class SessionsController < ApplicationController
@session = current_user.sessions.find(params[:id])
if @session.is_current?
redirect_to sessions_path, alert: "You cannot terminate your current session."
redirect_to sessions_path, alert: "你不能终止当前会话。"
else
@session.destroy
redirect_to sessions_path, notice: "Session terminated successfully."
redirect_to sessions_path, notice: "会话已终止。"
end
rescue ActiveRecord::RecordNotFound
redirect_to sessions_path, alert: "Session not found."
redirect_to sessions_path, alert: "会话未找到。"
end
def terminate_all
current_user.sessions.where.not(id: current_session.id).destroy_all
redirect_to sessions_path, notice: "All other sessions have been terminated."
redirect_to sessions_path, notice: "所有其他会话已终止。"
end
def security
......@@ -80,7 +80,7 @@ class SessionsController < ApplicationController
def update_security
if current_user.update(security_params)
redirect_to security_sessions_path, notice: "Security settings updated successfully."
redirect_to security_sessions_path, notice: "安全设置已更新。"
else
render inertia: "sessions/Security", props: {
security_settings: current_user.security_settings,
......
......@@ -2,7 +2,7 @@ import { useState } from 'react'
import { Link } from '@inertiajs/react'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
export default function Layout({ children, user }) {
export default function Layout({ children, user, title }) {
const [isMenuOpen, setIsMenuOpen] = useState(false)
return (
......@@ -13,7 +13,7 @@ export default function Layout({ children, user }) {
<div className="flex">
<div className="flex-shrink-0 flex items-center">
<Link href="/" className="text-xl font-bold text-indigo-600">
Image Manager
文件管理
</Link>
</div>
<nav className="hidden sm:ml-6 sm:flex sm:space-x-8">
......@@ -21,28 +21,22 @@ export default function Layout({ children, user }) {
href="/"
className="border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium"
>
Home
</Link>
<Link
href="/images/search"
className="border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium"
>
Search
主页
</Link>
{user && (
<Link
href="/images/new"
className="border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium"
>
Upload
上传
</Link>
)}
{user?.role === 'admin' && (
{user?.roles.includes('admin') && (
<Link
href="/admin"
className="border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium"
>
Admin
管理员
</Link>
)}
</nav>
......@@ -68,7 +62,7 @@ export default function Layout({ children, user }) {
</DropdownMenu.Item>
<DropdownMenu.Item className="text-sm text-gray-700 px-4 py-2 rounded hover:bg-gray-100">
<Link href="/images" className="block w-full text-left">
My Images
我的文件
</Link>
</DropdownMenu.Item>
<DropdownMenu.Separator className="h-px bg-gray-200 my-1" />
......@@ -79,7 +73,7 @@ export default function Layout({ children, user }) {
as="button"
className="block w-full text-left"
>
Sign out
登出
</Link>
</DropdownMenu.Item>
</DropdownMenu.Content>
......@@ -91,13 +85,13 @@ export default function Layout({ children, user }) {
href="/session/new"
className="text-gray-500 hover:text-gray-700 px-3 py-2 rounded-md text-sm font-medium"
>
Sign in
登录
</Link>
<Link
href="/users/new"
className="bg-indigo-600 text-white hover:bg-indigo-700 px-3 py-2 rounded-md text-sm font-medium"
>
Sign up
注册
</Link>
</div>
)}
......@@ -107,7 +101,7 @@ export default function Layout({ children, user }) {
onClick={() => setIsMenuOpen(!isMenuOpen)}
className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"
>
<span className="sr-only">Open main menu</span>
<span className="sr-only">打开菜单</span>
<svg
className={`${isMenuOpen ? 'hidden' : 'block'} h-6 w-6`}
xmlns="http://www.w3.org/2000/svg"
......@@ -150,20 +144,14 @@ export default function Layout({ children, user }) {
href="/"
className="bg-indigo-50 border-indigo-500 text-indigo-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium"
>
Home
</Link>
<Link
href="/images/search"
className="border-transparent text-gray-500 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium"
>
Search
主页
</Link>
{user && (
<Link
href="/images/new"
className="border-transparent text-gray-500 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium"
>
Upload
上传
</Link>
)}
{user?.roles?.includes('admin') && (
......@@ -171,7 +159,7 @@ export default function Layout({ children, user }) {
href="/admin"
className="border-transparent text-gray-500 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium"
>
Admin
管理员
</Link>
)}
</div>
......@@ -197,7 +185,7 @@ export default function Layout({ children, user }) {
href="/images"
className="block px-4 py-2 text-base font-medium text-gray-500 hover:text-gray-800 hover:bg-gray-100"
>
My Images
我的文件
</Link>
<Link
href="/session"
......@@ -205,7 +193,7 @@ export default function Layout({ children, user }) {
as="button"
className="block w-full text-left px-4 py-2 text-base font-medium text-gray-500 hover:text-gray-800 hover:bg-gray-100"
>
Sign out
登出
</Link>
</div>
</div>
......@@ -216,13 +204,13 @@ export default function Layout({ children, user }) {
href="/session/new"
className="text-gray-500 hover:text-gray-700 px-3 py-2 text-base font-medium"
>
Sign in
登录
</Link>
<Link
href="/users/new"
className="bg-indigo-600 text-white hover:bg-indigo-700 px-3 py-2 rounded-md text-base font-medium"
>
Sign up
注册
</Link>
</div>
</div>
......@@ -237,7 +225,7 @@ export default function Layout({ children, user }) {
<footer className="bg-white border-t border-gray-200 py-8">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<p className="text-center text-gray-500 text-sm">
&copy; {new Date().getFullYear()} Image Manager. All rights reserved.
&copy; {new Date().getFullYear()}
</p>
</div>
</footer>
......
import { useState } from 'react'
import { Head, Link, useForm } from '@inertiajs/react'
import * as Form from '@radix-ui/react-form'
export default function ForgotPassword({ status, errors = {} }) {
const { data, setData, post, processing } = useForm({
email_address: '',
})
const handleSubmit = (e) => {
e.preventDefault()
post('/forgot-password')
}
return (
<div className="min-h-screen flex flex-col justify-center py-12 sm:px-6 lg:px-8 bg-gray-50">
<Head title="Forgot Password" />
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
Forgot your password?
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
Enter your email address and we'll send you a link to reset your password.
</p>
</div>
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
{status && (
<div className="mb-4 font-medium text-sm text-green-600">
{status}
</div>
)}
<Form.Root className="space-y-6" onSubmit={handleSubmit}>
<Form.Field name="email_address" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Email address
</Form.Label>
<Form.Control asChild>
<input
id="email_address"
name="email_address"
type="email"
autoComplete="email"
required
value={data.email_address}
onChange={(e) => setData('email_address', e.target.value)}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</Form.Control>
{errors.email_address && (
<Form.Message className="text-sm text-red-600">
{errors.email_address}
</Form.Message>
)}
</Form.Field>
<div>
<Form.Submit asChild>
<button
type="submit"
disabled={processing}
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50"
>
{processing ? 'Sending...' : 'Send Password Reset Link'}
</button>
</Form.Submit>
</div>
<div className="flex items-center justify-center">
<div className="text-sm">
<Link
href="/login"
className="font-medium text-indigo-600 hover:text-indigo-500"
>
Back to login
</Link>
</div>
</div>
</Form.Root>
</div>
</div>
</div>
)
}
import { useState } from 'react'
import { Head, Link, useForm } from '@inertiajs/react'
import * as Form from '@radix-ui/react-form'
export default function Login({ errors = {} }) {
const { data, setData, post, processing } = useForm({
email_address: '',
password: '',
remember: false,
})
const handleSubmit = (e) => {
e.preventDefault()
post('/login')
}
return (
<div className="min-h-screen flex flex-col justify-center py-12 sm:px-6 lg:px-8 bg-gray-50">
<Head title="Log in" />
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
Log in to your account
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
Or{' '}
<Link
href="/register"
className="font-medium text-indigo-600 hover:text-indigo-500"
>
create a new account
</Link>
</p>
</div>
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
<Form.Root className="space-y-6" onSubmit={handleSubmit}>
<Form.Field name="email_address" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Email address
</Form.Label>
<Form.Control asChild>
<input
id="email_address"
name="email_address"
type="email"
autoComplete="email"
required
value={data.email_address}
onChange={(e) => setData('email_address', e.target.value)}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</Form.Control>
{errors.email_address && (
<Form.Message className="text-sm text-red-600">
{errors.email_address}
</Form.Message>
)}
</Form.Field>
<Form.Field name="password" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Password
</Form.Label>
<Form.Control asChild>
<input
id="password"
name="password"
type="password"
autoComplete="current-password"
required
value={data.password}
onChange={(e) => setData('password', e.target.value)}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</Form.Control>
{errors.password && (
<Form.Message className="text-sm text-red-600">
{errors.password}
</Form.Message>
)}
</Form.Field>
<div className="flex items-center justify-between">
<div className="flex items-center">
<input
id="remember"
name="remember"
type="checkbox"
checked={data.remember}
onChange={(e) => setData('remember', e.target.checked)}
className="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded"
/>
<label
htmlFor="remember"
className="ml-2 block text-sm text-gray-900"
>
Remember me
</label>
</div>
<div className="text-sm">
<Link
href="/forgot-password"
className="font-medium text-indigo-600 hover:text-indigo-500"
>
Forgot your password?
</Link>
</div>
</div>
<div>
<Form.Submit asChild>
<button
type="submit"
disabled={processing}
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50"
>
{processing ? 'Logging in...' : 'Log in'}
</button>
</Form.Submit>
</div>
</Form.Root>
</div>
</div>
</div>
)
}
import { useState } from 'react'
import { Head, Link, useForm } from '@inertiajs/react'
import * as Form from '@radix-ui/react-form'
export default function Register({ errors = {} }) {
const { data, setData, post, processing } = useForm({
name: '',
email_address: '',
password: '',
password_confirmation: '',
})
const handleSubmit = (e) => {
e.preventDefault()
post('/register')
}
return (
<div className="min-h-screen flex flex-col justify-center py-12 sm:px-6 lg:px-8 bg-gray-50">
<Head title="Register" />
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
Create a new account
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
Or{' '}
<Link
href="/login"
className="font-medium text-indigo-600 hover:text-indigo-500"
>
log in to your existing account
</Link>
</p>
</div>
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
<Form.Root className="space-y-6" onSubmit={handleSubmit}>
<Form.Field name="name" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Name
</Form.Label>
<Form.Control asChild>
<input
id="name"
name="name"
type="text"
autoComplete="name"
required
value={data.name}
onChange={(e) => setData('name', e.target.value)}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</Form.Control>
{errors.name && (
<Form.Message className="text-sm text-red-600">
{errors.name}
</Form.Message>
)}
</Form.Field>
<Form.Field name="email_address" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Email address
</Form.Label>
<Form.Control asChild>
<input
id="email_address"
name="email_address"
type="email"
autoComplete="email"
required
value={data.email_address}
onChange={(e) => setData('email_address', e.target.value)}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</Form.Control>
{errors.email_address && (
<Form.Message className="text-sm text-red-600">
{errors.email_address}
</Form.Message>
)}
</Form.Field>
<Form.Field name="password" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Password
</Form.Label>
<Form.Control asChild>
<input
id="password"
name="password"
type="password"
autoComplete="new-password"
required
value={data.password}
onChange={(e) => setData('password', e.target.value)}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</Form.Control>
{errors.password && (
<Form.Message className="text-sm text-red-600">
{errors.password}
</Form.Message>
)}
</Form.Field>
<Form.Field name="password_confirmation" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Confirm Password
</Form.Label>
<Form.Control asChild>
<input
id="password_confirmation"
name="password_confirmation"
type="password"
autoComplete="new-password"
required
value={data.password_confirmation}
onChange={(e) => setData('password_confirmation', e.target.value)}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</Form.Control>
</Form.Field>
<div>
<Form.Submit asChild>
<button
type="submit"
disabled={processing}
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50"
>
{processing ? 'Creating account...' : 'Create account'}
</button>
</Form.Submit>
</div>
</Form.Root>
</div>
</div>
</div>
)
}
import { useState } from 'react'
import { Head, Link, useForm } from '@inertiajs/react'
import * as Form from '@radix-ui/react-form'
export default function ResetPassword({ token, email, errors = {} }) {
const { data, setData, post, processing } = useForm({
token: token,
email_address: email,
password: '',
password_confirmation: '',
})
const handleSubmit = (e) => {
e.preventDefault()
post('/reset-password')
}
return (
<div className="min-h-screen flex flex-col justify-center py-12 sm:px-6 lg:px-8 bg-gray-50">
<Head title="Reset Password" />
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
Reset your password
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
Enter a new password for your account
</p>
</div>
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
<Form.Root className="space-y-6" onSubmit={handleSubmit}>
<Form.Field name="email_address" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Email address
</Form.Label>
<Form.Control asChild>
<input
id="email_address"
name="email_address"
type="email"
autoComplete="email"
readOnly
value={data.email_address}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm bg-gray-50 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</Form.Control>
{errors.email_address && (
<Form.Message className="text-sm text-red-600">
{errors.email_address}
</Form.Message>
)}
</Form.Field>
<Form.Field name="password" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
New Password
</Form.Label>
<Form.Control asChild>
<input
id="password"
name="password"
type="password"
autoComplete="new-password"
required
value={data.password}
onChange={(e) => setData('password', e.target.value)}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</Form.Control>
{errors.password && (
<Form.Message className="text-sm text-red-600">
{errors.password}
</Form.Message>
)}
</Form.Field>
<Form.Field name="password_confirmation" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Confirm New Password
</Form.Label>
<Form.Control asChild>
<input
id="password_confirmation"
name="password_confirmation"
type="password"
autoComplete="new-password"
required
value={data.password_confirmation}
onChange={(e) => setData('password_confirmation', e.target.value)}
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</Form.Control>
{errors.password_confirmation && (
<Form.Message className="text-sm text-red-600">
{errors.password_confirmation}
</Form.Message>
)}
</Form.Field>
<div>
<Form.Submit asChild>
<button
type="submit"
disabled={processing}
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50"
>
{processing ? 'Resetting...' : 'Reset Password'}
</button>
</Form.Submit>
</div>
<div className="flex items-center justify-center">
<div className="text-sm">
<Link
href="/login"
className="font-medium text-indigo-600 hover:text-indigo-500"
>
Back to login
</Link>
</div>
</div>
</Form.Root>
</div>
</div>
</div>
)
}
......@@ -9,9 +9,9 @@ export default function Index({ images, filters, pagination, auth }) {
const [allImages, setAllImages] = useState(images || [])
const [page, setPage] = useState(pagination?.current_page || 1)
const [maxVisiblePage, setMaxVisiblePage] = useState(0)
const [loading, setLoading] = useState(false)
const [hasMore, setHasMore] = useState(pagination?.current_page < pagination?.total_pages)
const [filterCount, setFilterCount] = useState(0)
const [loadedPageMap, setLoadedPageMap] = useState({})
const bottomObserver = useRef()
const [searchParams, setSearchParams] = useState({
......@@ -30,7 +30,7 @@ export default function Index({ images, filters, pagination, auth }) {
const handleSearch = (e) => {
e.preventDefault()
setLoadedPageMap({})
maxVisiblePage(0)
setMaxVisiblePage(0)
setAllImages([])
loadPage(1)
......@@ -65,8 +65,7 @@ export default function Index({ images, filters, pagination, auth }) {
// Prepend new images to existing ones
setPage(response.props.pagination.current_page)
setHasMore(maxVisiblePage < response.props.pagination.total_pages)
console.log('response', response);
setFilterCount(Object.values(searchParams).filter(i => i).length)
setLoadedPageMap({...loadedPageMap, [response.props.pagination.current_page]: response.props.images})
setLoading(false)
},
......@@ -117,31 +116,31 @@ export default function Index({ images, filters, pagination, auth }) {
return (
<Layout user={auth}>
<Head title="My Images" />
<Head title="我的文件" />
<div className="bg-white shadow overflow-hidden sm:rounded-lg">
<div className="px-4 py-5 sm:px-6 flex justify-between items-center">
<div>
<h1 className="text-2xl font-bold text-gray-900">My Images</h1>
<h1 className="text-2xl font-bold text-gray-900">我的文件</h1>
<p className="mt-1 max-w-2xl text-sm text-gray-500">
Manage your uploaded images
管理已上传的文件
</p>
</div>
<div className="flex space-x-2">
<button
onClick={() => setIsFilterOpen(!isFilterOpen)}
className="inline-flex items-center px-3 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
className={`inline-flex items-center px-3 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 ${filterCount ? '!bg-indigo-700 !text-white' : ''}`}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
</svg>
{isFilterOpen ? 'Hide Filters' : 'Show Filters'}
{isFilterOpen ? '隐藏过滤' : '显示过滤'}{ filterCount ? `(${Object.values(searchParams).filter(i => i).length})` : ''}
</button>
{auth && (
<Link
href="/images/new"
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Upload New Image
上传新文件
</Link>
)}
</div>
......@@ -158,7 +157,7 @@ export default function Index({ images, filters, pagination, auth }) {
<div className="sm:col-span-3">
<Form.Field name="title_cont">
<Form.Label className="block text-sm font-medium text-gray-700">
Title
名称
</Form.Label>
<Form.Control asChild>
<input
......@@ -167,7 +166,7 @@ export default function Index({ images, filters, pagination, auth }) {
value={searchParams.title_cont}
onChange={handleInputChange}
className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md"
placeholder="Search by title"
placeholder="按名称搜索"
/>
</Form.Control>
</Form.Field>
......@@ -176,7 +175,7 @@ export default function Index({ images, filters, pagination, auth }) {
<div className="sm:col-span-3">
<Form.Field name="tags_name_cont">
<Form.Label className="block text-sm font-medium text-gray-700">
Tags
标签
</Form.Label>
<Form.Control asChild>
<input
......@@ -185,7 +184,7 @@ export default function Index({ images, filters, pagination, auth }) {
value={searchParams.tags_name_cont}
onChange={handleInputChange}
className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md"
placeholder="Search by tag"
placeholder="按标签搜索"
/>
</Form.Control>
</Form.Field>
......@@ -194,7 +193,7 @@ export default function Index({ images, filters, pagination, auth }) {
<div className="sm:col-span-3">
<Form.Field name="created_at_gteq">
<Form.Label className="block text-sm font-medium text-gray-700">
From Date
开始日期
</Form.Label>
<Form.Control asChild>
<input
......@@ -211,7 +210,7 @@ export default function Index({ images, filters, pagination, auth }) {
<div className="sm:col-span-3">
<Form.Field name="created_at_lteq">
<Form.Label className="block text-sm font-medium text-gray-700">
To Date
结束日期
</Form.Label>
<Form.Control asChild>
<input
......@@ -226,12 +225,25 @@ export default function Index({ images, filters, pagination, auth }) {
</div>
</div>
<div className="flex justify-end">
<div className="flex justify-end space-x-2">
<button
className="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
onClick={() => {
setSearchParams({
title_cont: '',
tags_name_cont: '',
created_at_gteq: '',
created_at_lteq: '',
})
}}
>
清空
</button>
<button
type="submit"
className="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Search
搜索
</button>
</div>
</Form.Root>
......@@ -244,7 +256,7 @@ export default function Index({ images, filters, pagination, auth }) {
<div className="col-span-full text-center py-4">
<div className="inline-block h-8 w-8 animate-spin rounded-full border-4 border-solid border-current border-r-transparent align-[-0.125em] motion-reduce:animate-[spin_1.5s_linear_infinite]" role="status">
<span className="!absolute !-m-px !h-px !w-px !overflow-hidden !whitespace-nowrap !border-0 !p-0 ![clip:rect(0,0,0,0)]">
Loading...
加载中...
</span>
</div>
</div>
......@@ -341,7 +353,7 @@ export default function Index({ images, filters, pagination, auth }) {
href="/images/new"
className="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Upload New Image
上传新文件
</Link>
</div>
</div>
......
......@@ -33,12 +33,12 @@ export default function New({ auth, errors = {} }) {
return (
<Layout user={auth.user}>
<Head title="Upload New Image" />
<Head title="上传新文件" />
<div className="bg-white shadow overflow-hidden sm:rounded-lg">
<div className="px-4 py-5 sm:px-6">
<h1 className="text-2xl font-bold text-gray-900">Upload New Image</h1>
<h1 className="text-2xl font-bold text-gray-900">上传新文件</h1>
<p className="mt-1 max-w-2xl text-sm text-gray-500">
Upload a new image for review
上传并等待审核
</p>
</div>
<div className="border-t border-gray-200 px-4 py-5 sm:px-6">
......
......@@ -20,15 +20,15 @@ export default function SessionsNew({ flash }) {
<Head title="Log in" />
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
Log in to your account
登录以使用
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
Or{' '}
{' '}
<Link
href="/users/new"
className="font-medium text-indigo-600 hover:text-indigo-500"
>
create a new account
创建新账户
</Link>
</p>
</div>
......@@ -44,7 +44,7 @@ export default function SessionsNew({ flash }) {
<Form.Root className="space-y-6" onSubmit={handleSubmit}>
<Form.Field name="email_address" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Email address
邮箱地址
</Form.Label>
<Form.Control asChild>
<input
......@@ -67,7 +67,7 @@ export default function SessionsNew({ flash }) {
<Form.Field name="password" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Password
密码
</Form.Label>
<Form.Control asChild>
<input
......@@ -89,7 +89,7 @@ export default function SessionsNew({ flash }) {
</Form.Field>
<div className="flex items-center justify-between">
<div className="flex items-center">
{/* <div className="flex items-center">
<input
id="remember"
name="remember"
......@@ -102,18 +102,18 @@ export default function SessionsNew({ flash }) {
htmlFor="remember"
className="ml-2 block text-sm text-gray-900"
>
Remember me
记住我
</label>
</div>
</div> */}
<div className="text-sm">
{/* <div className="text-sm">
<Link
href="/passwords/new"
className="font-medium text-indigo-600 hover:text-indigo-500"
>
Forgot your password?
忘记密码?
</Link>
</div>
</div> */}
</div>
<div>
......@@ -123,13 +123,13 @@ export default function SessionsNew({ flash }) {
disabled={processing}
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50"
>
{processing ? 'Logging in...' : 'Log in'}
{processing ? '登录中...' : '登录'}
</button>
</Form.Submit>
</div>
</Form.Root>
<div className="mt-6">
{/* <div className="mt-6">
<div className="relative">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-300" />
......@@ -158,7 +158,7 @@ export default function SessionsNew({ flash }) {
<span>GitHub</span>
</button>
</div>
</div>
</div> */}
</div>
</div>
</div>
......
......@@ -21,15 +21,15 @@ export default function UsersNew({ flash, errors = {} }) {
<Head title="Sign up" />
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
Create a new account
创建新用户
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
Or{' '}
已有账号?{' '}
<Link
href="/session/new"
className="font-medium text-indigo-600 hover:text-indigo-500"
>
log in to your account
登录
</Link>
</p>
</div>
......@@ -45,7 +45,7 @@ export default function UsersNew({ flash, errors = {} }) {
<Form.Root className="space-y-6" onSubmit={handleSubmit}>
<Form.Field name="name" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Full name
用户名
</Form.Label>
<Form.Control asChild>
<input
......@@ -68,7 +68,7 @@ export default function UsersNew({ flash, errors = {} }) {
<Form.Field name="email_address" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Email address
邮箱
</Form.Label>
<Form.Control asChild>
<input
......@@ -91,7 +91,7 @@ export default function UsersNew({ flash, errors = {} }) {
<Form.Field name="password" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Password
密码
</Form.Label>
<Form.Control asChild>
<input
......@@ -114,7 +114,7 @@ export default function UsersNew({ flash, errors = {} }) {
<Form.Field name="password_confirmation" className="space-y-1">
<Form.Label className="block text-sm font-medium text-gray-700">
Confirm password
确认密码
</Form.Label>
<Form.Control asChild>
<input
......@@ -142,13 +142,13 @@ export default function UsersNew({ flash, errors = {} }) {
disabled={processing}
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50"
>
{processing ? 'Creating account...' : 'Sign up'}
{processing ? '创建中...' : '创建'}
</button>
</Form.Submit>
</div>
</Form.Root>
<div className="mt-6">
{/* <div className="mt-6">
<div className="relative">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-300" />
......@@ -177,7 +177,7 @@ export default function UsersNew({ flash, errors = {} }) {
<span>GitHub</span>
</button>
</div>
</div>
</div> */}
</div>
</div>
</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment