feat(frontend): i18n expansion, admin/profile i18n, grid/list view fix, empty state

- Add 5 new locales (hi, ar, ru, ja, ko) — now 14 total
- Admin panel: 117 i18n keys, confirm modal, animated tabs, no inline handlers
- Profile page: 58 i18n keys with data-i18n attributes
- Fix i18n safeT() shadowing bug and translationsLoaded timing
- Fix grid/list view: list header no longer shows in grid mode on login
- Fix classList.toggle hidden sync for view switching across all nav functions
- Revert .hidden important that broke login page rendering
- Add files empty state (no_files + empty_hint) with translations
- Fix language selector dropdown scroll and styling
- Fix admin panel scroll with sticky tabs
This commit is contained in:
Diocrafts
2026-03-09 00:08:34 +01:00
parent f409a9edd7
commit df336da679
43 changed files with 6645 additions and 2043 deletions
+15 -49
View File
@@ -20,12 +20,18 @@ use crate::application::ports::auth_ports::TokenServicePort;
#[derive(Clone, Copy, Debug)]
pub struct CookieAuthenticated;
// Structure for use in Axum extractors
// Newtype over Arc<CurrentUser> for zero-allocation extraction.
// `Deref<Target = CurrentUser>` lets handlers access `.id`, `.username`,
// `.email`, `.role` transparently — no signature changes needed.
#[derive(Clone, Debug)]
pub struct AuthUser {
pub id: Uuid,
pub username: String,
pub role: String,
pub struct AuthUser(pub Arc<CurrentUser>);
impl std::ops::Deref for AuthUser {
type Target = CurrentUser;
#[inline]
fn deref(&self) -> &CurrentUser {
&self.0
}
}
/// Reusable extractor that gets the user_id of the authenticated user.
@@ -38,7 +44,8 @@ pub struct AuthUser {
#[derive(Clone, Debug)]
pub struct CurrentUserId(pub Uuid);
// Implement FromRequestParts for AuthUser — allows using `auth_user: AuthUser` in handlers
// Implement FromRequestParts for AuthUser — allows using `auth_user: AuthUser` in handlers.
// Cost: 1 atomic increment (~1 ns) instead of 3 String clones (~100 ns + 3 mallocs).
impl<S> FromRequestParts<S> for AuthUser
where
S: Send + Sync,
@@ -49,29 +56,8 @@ where
parts
.extensions
.get::<Arc<CurrentUser>>()
.map(|cu| AuthUser {
id: cu.id,
username: cu.username.clone(),
role: cu.role.clone(),
})
.ok_or(AuthError::UserNotFound)
}
}
// Implement FromRequestParts for CurrentUser — full user extractor from extensions
// The middleware inserts Arc<CurrentUser>; this extractor cheaply clones the Arc
// (~1 ns atomic increment) instead of deep-cloning 4 Strings (~60-100 ns).
impl<S> FromRequestParts<S> for CurrentUser
where
S: Send + Sync,
{
type Rejection = AuthError;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
parts
.extensions
.get::<Arc<CurrentUser>>()
.map(|arc| (**arc).clone())
.cloned()
.map(AuthUser)
.ok_or(AuthError::UserNotFound)
}
}
@@ -113,27 +99,7 @@ where
}
}
/// Optional auth user extractor – never fails.
/// Yields `Some(AuthUser)` when auth middleware ran, `None` otherwise.
#[derive(Clone, Debug)]
pub struct OptionalAuthUser(pub Option<AuthUser>);
impl<S> FromRequestParts<S> for OptionalAuthUser
where
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
Ok(OptionalAuthUser(parts.extensions.get::<Arc<CurrentUser>>().map(
|cu| AuthUser {
id: cu.id,
username: cu.username.clone(),
role: cu.role.clone(),
},
)))
}
}
// Error for authentication operations
#[derive(Debug, thiserror::Error)]