From 655708cbe243282c55828d1c66ae656eee82d441 Mon Sep 17 00:00:00 2001
From: talel
Date: Wed, 8 Jul 2026 16:48:15 +0100
Subject: [PATCH 01/17] before all jwt
---
vagrant/dev/nginx/bbbeasy.conf | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/vagrant/dev/nginx/bbbeasy.conf b/vagrant/dev/nginx/bbbeasy.conf
index 3486b74f..ee189306 100644
--- a/vagrant/dev/nginx/bbbeasy.conf
+++ b/vagrant/dev/nginx/bbbeasy.conf
@@ -124,8 +124,8 @@ server {
proxy_read_timeout 300s;
}
- # Deny access to dot-files.
- location ~ /\. {
+ # Deny access to dot-files, except the Vite/Yarn PnP virtual folders needed by dev mode.
+ location ~ /\.(?!yarn/|vite/) {
deny all;
access_log off;
log_not_found off;
From 68668997ca874c4cda250bb00e667237cd5ee204 Mon Sep 17 00:00:00 2001
From: talel
Date: Sun, 12 Jul 2026 16:05:06 +0100
Subject: [PATCH 02/17] BugFixed
---
.gitignore | 3 +
bbbeasy-backend/app/src/Core/Session.php | 18 +--
.../tests/src/Actions/Account/LoginTest.php | 4 +-
.../tests/src/Actions/Rooms/StartTest.php | 4 +-
.../tests/src/Actions/Rooms/ViewTest.php | 4 +-
bbbeasy-frontend/.yarnrc.yml | 2 +-
bbbeasy-frontend/src/App.tsx | 2 +-
.../src/components/PublicRoute.tsx | 2 +-
.../src/components/layout/AppSider.tsx | 2 +-
bbbeasy-frontend/src/lib/AxiosInstance.ts | 26 ++--
bbbeasy-frontend/src/services/auth.service.ts | 123 ++++++++++++++----
bbbeasy-frontend/src/services/menu.service.ts | 4 +-
bbbeasy-frontend/vite.config.ts | 6 +-
vagrant/dev/nginx/bbbeasy.conf | 1 +
14 files changed, 127 insertions(+), 74 deletions(-)
diff --git a/.gitignore b/.gitignore
index 839d854c..d46f1352 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,6 @@ output/**/*.*
.env
.history/
+
+# Local JWT secret used only for development
+bbbeasy-backend/tmp/jwt.secret
diff --git a/bbbeasy-backend/app/src/Core/Session.php b/bbbeasy-backend/app/src/Core/Session.php
index 5612e067..d2bd3809 100644
--- a/bbbeasy-backend/app/src/Core/Session.php
+++ b/bbbeasy-backend/app/src/Core/Session.php
@@ -89,7 +89,6 @@ public function exists($key): bool
public function set($key, $value): void
{
$this->runtimeValues[$key] = $value;
- $this->f3->set('SESSION.' . $key, $value);
}
/**
@@ -278,20 +277,7 @@ private function serializeUser(User $user): array
private function syncSessionState(): void
{
- if (!$this->currentUser instanceof User) {
- return;
- }
-
- $user = $this->serializeUser($this->currentUser);
- $user['loggedIn'] = true;
-
- $this->f3->set('SESSION.user', $user);
- $this->f3->set('SESSION.user.loggedIn', true);
- $this->f3->set('SESSION.user.id', $user['id']);
- $this->f3->set('SESSION.user.role', $user['role']);
- $this->f3->set('SESSION.user.roleId', $this->currentUser->role->id);
- $this->f3->set('SESSION.user.username', $user['username']);
- $this->f3->set('SESSION.user.email', $user['email']);
+ // JWT-only mode keeps the authenticated user in request memory only.
}
/**
@@ -386,7 +372,7 @@ private function isRevoked(string $jti): bool
return true;
}
- return null !== \Cache::instance()->get($this->revokedTokenCacheKey($jti));
+ return false !== \Cache::instance()->get($this->revokedTokenCacheKey($jti));
}
private function revokedTokenCacheKey(string $jti): string
diff --git a/bbbeasy-backend/tests/src/Actions/Account/LoginTest.php b/bbbeasy-backend/tests/src/Actions/Account/LoginTest.php
index f0b8b5ac..2dfdb835 100644
--- a/bbbeasy-backend/tests/src/Actions/Account/LoginTest.php
+++ b/bbbeasy-backend/tests/src/Actions/Account/LoginTest.php
@@ -158,7 +158,7 @@ public function testAuthenticateExistingUser($f3)
$test->expect(isset($payload['sub']) && (int) $payload['sub'] === (int) $user->id, 'JWT subject matches the authenticated user');
$test->expect(isset($payload['exp']) && \is_string($expiresAt) && strtotime($expiresAt) > $now, 'JWT expiry is set in the future');
$test->expect(isset($responseBody['session']['expiresAt']) && $responseBody['session']['expiresAt'] === $expiresAt, 'Login returns a concrete token expiration date');
- $test->expect($f3->exists('SESSION.user'), 'Sessions is aware that the user us logged in');
+ $test->expect(null !== \Registry::get('session')->get('user'), 'JWT session keeps the authenticated user in memory');
UserFaker::logout();
@@ -179,7 +179,7 @@ public function testValidAuthentication($f3)
$user = UserFaker::create(UserRole::ADMINISTRATOR);
$data = ['email' => $user->email, 'password' => UserRole::ADMINISTRATOR . UserRole::ADMINISTRATOR];
$f3->mock(self::LOGIN_ROUTE, null, null, $this->postJsonData($data));
- $test->expect($f3->exists('SESSION.user'), 'User with id "' . $user->id . '" is now logged in');
+ $test->expect(null !== \Registry::get('session')->get('user'), 'User with id "' . $user->id . '" is now logged in');
return $test->results();
}
diff --git a/bbbeasy-backend/tests/src/Actions/Rooms/StartTest.php b/bbbeasy-backend/tests/src/Actions/Rooms/StartTest.php
index 102b23e5..3fdb5d8c 100644
--- a/bbbeasy-backend/tests/src/Actions/Rooms/StartTest.php
+++ b/bbbeasy-backend/tests/src/Actions/Rooms/StartTest.php
@@ -25,6 +25,7 @@
use Fake\PresetFaker;
use Fake\RoomFaker;
use Models\User;
+use Registry;
use Test\Scenario;
/**
@@ -66,7 +67,8 @@ public function testValidRoom($f3)
$test = $this->newTest();
$loggedUser = new User();
- $loggedUser->load(['id = ?', [$f3->get('SESSION.user.id')]]);
+ $currentUser = Registry::get('session')->get('user');
+ $loggedUser->load(['id = ?', [$currentUser['id']]]);
$preset = PresetFaker::create($loggedUser);
$room = RoomFaker::create($loggedUser, $preset);
$f3->mock(self::START_ROOM_ROUTE . $room->id, null, null);
diff --git a/bbbeasy-backend/tests/src/Actions/Rooms/ViewTest.php b/bbbeasy-backend/tests/src/Actions/Rooms/ViewTest.php
index 8c0a445c..4b1a391c 100644
--- a/bbbeasy-backend/tests/src/Actions/Rooms/ViewTest.php
+++ b/bbbeasy-backend/tests/src/Actions/Rooms/ViewTest.php
@@ -25,6 +25,7 @@
use Fake\PresetFaker;
use Fake\RoomFaker;
use Models\User;
+use Registry;
use Test\Scenario;
/**
@@ -66,7 +67,8 @@ public function testValidLink($f3)
$test = $this->newTest();
$loggedUser = new User();
- $loggedUser->load(['id = ?', [$f3->get('SESSION.user.id')]]);
+ $currentUser = Registry::get('session')->get('user');
+ $loggedUser->load(['id = ?', [$currentUser['id']]]);
$preset = PresetFaker::create($loggedUser);
$room = RoomFaker::create($loggedUser, $preset, 'abcdef-123456');
$f3->mock(self::VIEW_ROOM_ROUTE . $room->short_link, null, null);
diff --git a/bbbeasy-frontend/.yarnrc.yml b/bbbeasy-frontend/.yarnrc.yml
index fec60c2d..00d86f56 100644
--- a/bbbeasy-frontend/.yarnrc.yml
+++ b/bbbeasy-frontend/.yarnrc.yml
@@ -3,7 +3,7 @@ approvedGitRepositories:
enableScripts: true
-nodeLinker: node-modules
+nodeLinker: pnp
npmMinimalAgeGate: 0
diff --git a/bbbeasy-frontend/src/App.tsx b/bbbeasy-frontend/src/App.tsx
index 009d3c00..eafd52a1 100644
--- a/bbbeasy-frontend/src/App.tsx
+++ b/bbbeasy-frontend/src/App.tsx
@@ -125,7 +125,7 @@ const App: React.FC = ({ routes, isSider, logs }) => {
setCurrentSession(session);
setIsLogged(true);
- const allowedGroups = Object.keys(user.permissions);
+ const allowedGroups = Object.keys(user.permissions ?? {});
if (allowedGroups.length > 0) {
if (AuthService.isAllowedGroup(allowedGroups, 'logs')) {
Logger.info(logs);
diff --git a/bbbeasy-frontend/src/components/PublicRoute.tsx b/bbbeasy-frontend/src/components/PublicRoute.tsx
index 2330e543..724fa503 100644
--- a/bbbeasy-frontend/src/components/PublicRoute.tsx
+++ b/bbbeasy-frontend/src/components/PublicRoute.tsx
@@ -31,7 +31,7 @@ const PublicRoute = ({ children, restricted }) => {
// restricted = true meaning restricted route else public route
if (currentUser != null && currentSession != null && restricted) {
- const menuSider = MenuService.getMenuSider(currentUser.permissions);
+ const menuSider = MenuService.getMenuSider(currentUser.permissions ?? {});
const defaultRoute = menuSider.defaultRoute;
if (defaultRoute != '') {
return ;
diff --git a/bbbeasy-frontend/src/components/layout/AppSider.tsx b/bbbeasy-frontend/src/components/layout/AppSider.tsx
index 6b8b4dbc..a9a7c101 100644
--- a/bbbeasy-frontend/src/components/layout/AppSider.tsx
+++ b/bbbeasy-frontend/src/components/layout/AppSider.tsx
@@ -78,7 +78,7 @@ const AppSider = (props: Props) => {
useEffect(() => {
const user: UserType = AuthService.getCurrentUser();
- const menuSider = MenuService.getMenuSider(user.permissions);
+ const menuSider = MenuService.getMenuSider(user?.permissions ?? {});
setMenuItems(menuSider.items);
setNewMenuItems(menuSider.news);
diff --git a/bbbeasy-frontend/src/lib/AxiosInstance.ts b/bbbeasy-frontend/src/lib/AxiosInstance.ts
index abdddf8d..628f4d13 100644
--- a/bbbeasy-frontend/src/lib/AxiosInstance.ts
+++ b/bbbeasy-frontend/src/lib/AxiosInstance.ts
@@ -17,30 +17,22 @@
*/
import axios, { AxiosRequestHeaders } from 'axios';
+import AuthService from '../services/auth.service';
export const axiosInstance = axios.create();
axiosInstance.interceptors.request.use((config) => {
try {
- const sessionStr = localStorage.getItem('session');
- if (sessionStr) {
- const session = JSON.parse(sessionStr);
- if (session?.expiresAt && Date.parse(session.expiresAt) < Date.now()) {
- localStorage.removeItem('user');
- localStorage.removeItem('session');
- return config;
- }
-
- if (session?.accessToken && session?.tokenType) {
- config.headers = (config.headers || {}) as AxiosRequestHeaders;
- Object.assign(config.headers, {
- Authorization: `${session.tokenType} ${session.accessToken}`,
- });
- }
+ const session = AuthService.getCurrentSession();
+ if (session?.accessToken) {
+ config.headers = (config.headers || {}) as AxiosRequestHeaders;
+ Object.assign(config.headers, {
+ Authorization: `${session.tokenType ?? 'Bearer'} ${session.accessToken}`,
+ });
}
} catch (error) {
- console.warn('Failed to process session from localStorage:', error);
- localStorage.removeItem('session');
+ console.warn('Failed to process auth state from localStorage:', error);
+ AuthService.clearAuth();
}
return config;
diff --git a/bbbeasy-frontend/src/services/auth.service.ts b/bbbeasy-frontend/src/services/auth.service.ts
index 375e0065..17926b0e 100644
--- a/bbbeasy-frontend/src/services/auth.service.ts
+++ b/bbbeasy-frontend/src/services/auth.service.ts
@@ -21,7 +21,70 @@ import { apiRoutes } from '../routing/backend-config';
import { UserType } from '../types/UserType';
import { SessionType } from '../types/SessionType';
+type AuthState = {
+ user?: UserType;
+ session?: SessionType;
+};
+
class AuthService {
+ private readonly authStorageKey = 'auth';
+
+ private readStoredAuth(): AuthState {
+ const authStr = localStorage.getItem(this.authStorageKey);
+ if (authStr) {
+ try {
+ const authData = JSON.parse(authStr);
+ return authData && typeof authData === 'object' ? authData : {};
+ } catch {
+ localStorage.removeItem(this.authStorageKey);
+ }
+ }
+
+ return {};
+ }
+
+ private migrateLegacyAuth(): AuthState {
+ const legacyUserStr = localStorage.getItem('user');
+ const legacySessionStr = localStorage.getItem('session');
+ if (!legacyUserStr && !legacySessionStr) {
+ return {};
+ }
+
+ try {
+ const authState: AuthState = {
+ user: legacyUserStr ? (JSON.parse(legacyUserStr) as UserType) : undefined,
+ session: legacySessionStr ? (JSON.parse(legacySessionStr) as SessionType) : undefined,
+ };
+ localStorage.setItem(this.authStorageKey, JSON.stringify(authState));
+ localStorage.removeItem('user');
+ localStorage.removeItem('session');
+
+ return authState;
+ } catch {
+ localStorage.removeItem('user');
+ localStorage.removeItem('session');
+ return {};
+ }
+ }
+
+ private readAuth(): AuthState {
+ const storedAuth = this.readStoredAuth();
+ if (storedAuth.user || storedAuth.session) {
+ return storedAuth;
+ }
+
+ return this.migrateLegacyAuth();
+ }
+
+ private writeAuth(nextAuth: AuthState): void {
+ if (!nextAuth.user && !nextAuth.session) {
+ localStorage.removeItem(this.authStorageKey);
+ return;
+ }
+
+ localStorage.setItem(this.authStorageKey, JSON.stringify(nextAuth));
+ }
+
register(data: object) {
return axiosInstance.post(apiRoutes.REGISTER_URL, {
data,
@@ -61,57 +124,59 @@ class AuthService {
}
addCurrentUser(user: UserType) {
- localStorage.setItem('user', JSON.stringify(user));
+ const auth = this.readAuth();
+ this.writeAuth({
+ user,
+ session: auth.session,
+ });
}
addCurrentSession(session: SessionType) {
- localStorage.setItem('session', JSON.stringify(session));
+ const auth = this.readAuth();
+ this.writeAuth({
+ user: auth.user,
+ session,
+ });
}
- getCurrentUser() {
- const userStr: string = localStorage.getItem('user');
- if (userStr) {
- try {
- return JSON.parse(userStr);
- } catch {
- this.clearAuth();
- }
+ getCurrentUser(): UserType | null {
+ const auth = this.readAuth();
+ if (auth.user) {
+ return auth.user;
}
+
return null;
}
- getCurrentSession() {
- const sessionStr: string = localStorage.getItem('session');
- if (sessionStr) {
- try {
- const session: SessionType = JSON.parse(sessionStr);
- if (session.expiresAt && Date.parse(session.expiresAt) < Date.now()) {
- this.clearAuth();
- return null;
- }
-
- return session;
- } catch {
+ getCurrentSession(): SessionType | null {
+ const auth = this.readAuth();
+ if (auth.session) {
+ if (auth.session.expiresAt && Date.parse(auth.session.expiresAt) < Date.now()) {
this.clearAuth();
+ return null;
}
+
+ return auth.session;
}
+
return null;
}
getAccessToken(): string | null {
- const currentSession: SessionType = this.getCurrentSession();
+ const currentSession = this.getCurrentSession();
return currentSession ? currentSession.accessToken : null;
}
clearAuth() {
+ localStorage.removeItem(this.authStorageKey);
localStorage.removeItem('user');
localStorage.removeItem('session');
}
updateCurrentUser(username: string, email: string, avatar: string) {
- const userStr: string = localStorage.getItem('user');
- if (userStr) {
- const userObj: UserType = JSON.parse(userStr);
+ const auth = this.readAuth();
+ if (auth.user) {
+ const userObj: UserType = auth.user;
userObj.username = username;
userObj.email = email;
userObj.avatar = avatar;
@@ -121,8 +186,10 @@ class AuthService {
}
getActionsPermissionsByGroup(group: string): string[] {
- const currentUser: UserType = this.getCurrentUser();
- if (currentUser) return currentUser.permissions[group];
+ const currentUser = this.getCurrentUser();
+ if (currentUser?.permissions && currentUser.permissions[group]) {
+ return currentUser.permissions[group] as string[];
+ }
return [];
}
diff --git a/bbbeasy-frontend/src/services/menu.service.ts b/bbbeasy-frontend/src/services/menu.service.ts
index cbcb9de7..d331f4d1 100644
--- a/bbbeasy-frontend/src/services/menu.service.ts
+++ b/bbbeasy-frontend/src/services/menu.service.ts
@@ -111,7 +111,7 @@ const addSettings = (keys: string[], items: MenuType[]) => {
};
class MenuService {
- getMenuSider(userPermissions: object): MenuSiderType {
+ getMenuSider(userPermissions: Record = {}): MenuSiderType {
const items: MenuType[] = [];
const news: string[] = [];
let defaultRoute = '';
@@ -120,7 +120,7 @@ class MenuService {
const keys = Object.keys(userPermissions);
const addActionExist = (key: string) => {
- if (userPermissions[key].includes('add')) {
+ if (Array.isArray(userPermissions[key]) && userPermissions[key].includes('add')) {
news.push(key);
}
};
diff --git a/bbbeasy-frontend/vite.config.ts b/bbbeasy-frontend/vite.config.ts
index d9b90695..3e83f882 100644
--- a/bbbeasy-frontend/vite.config.ts
+++ b/bbbeasy-frontend/vite.config.ts
@@ -43,11 +43,11 @@ export default defineConfig(({ mode }) => {
sourcemap: env.GENERATE_SOURCEMAP !== 'false',
emptyOutDir: true,
},
- server: {
+ server: {
host: true,
port: 3300,
- strictPort: true,
- allowedHosts: ['bbbeasy.test', 'localhost', '127.0.0.1'],
+ strictPort: true,
+ allowedHosts: ['bbbeasy.test', 'localhost', '127.0.0.1',"snooper-foe-cosigner.ngrok-free.dev"],
open: env.NODE_ENV === 'development' ? 'http://bbbeasy.test/' : false,
proxy: {
'/api': {
diff --git a/vagrant/dev/nginx/bbbeasy.conf b/vagrant/dev/nginx/bbbeasy.conf
index ee189306..860e63ef 100644
--- a/vagrant/dev/nginx/bbbeasy.conf
+++ b/vagrant/dev/nginx/bbbeasy.conf
@@ -69,6 +69,7 @@ server {
fastcgi_index index.php;
fastcgi_read_timeout 60;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
+ fastcgi_param HTTP_AUTHORIZATION $http_authorization;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
access_log /var/log/nginx/bbbeasy-backend-access.log;
From f61db01cecf6cd835abf6c2210d530e23b1bf8c7 Mon Sep 17 00:00:00 2001
From: talel
Date: Mon, 20 Jul 2026 15:05:42 +0100
Subject: [PATCH 03/17] fixed
---
bbbeasy-frontend/src/App.tsx | 12 ++++---
bbbeasy-frontend/src/components/Presets.tsx | 14 +++++++-
.../src/components/layout/AppHeader.tsx | 34 +++++++++++--------
3 files changed, 39 insertions(+), 21 deletions(-)
diff --git a/bbbeasy-frontend/src/App.tsx b/bbbeasy-frontend/src/App.tsx
index eafd52a1..2deaae3c 100644
--- a/bbbeasy-frontend/src/App.tsx
+++ b/bbbeasy-frontend/src/App.tsx
@@ -53,9 +53,10 @@ interface IProps {
}
const App: React.FC = ({ routes, isSider, logs }) => {
- const [currentUser, setCurrentUser] = React.useState(null);
- const [currentSession, setCurrentSession] = React.useState(null);
- const [isLogged, setIsLogged] = React.useState(false);
+ const [currentUser, setCurrentUser] = React.useState(() => AuthService.getCurrentUser());
+ const [currentSession, setCurrentSession] = React.useState(() => AuthService.getCurrentSession());
+ const [isLogged, setIsLogged] = React.useState(() => Boolean(AuthService.getCurrentUser() && AuthService.getCurrentSession()));
+ const isAuthenticated = Boolean(AuthService.getCurrentUser() && AuthService.getCurrentSession());
const [dataRooms, setDataRooms] = React.useState([]);
const [dataLabels, setDataLabels] = React.useState([]);
@@ -70,6 +71,7 @@ const App: React.FC = ({ routes, isSider, logs }) => {
() => ({ isLogged, setIsLogged, currentUser, setCurrentUser, currentSession, setCurrentSession }),
[isLogged, currentUser, currentSession]
);
+ const authViewKey = isLogged ? 'authenticated' : 'anonymous';
const customTheme = {
token: {
@@ -152,9 +154,9 @@ const App: React.FC = ({ routes, isSider, logs }) => {
direction={LocaleService.direction}
componentSize="large"
>
-
+
- {isLogged && isSider && }
+ {isAuthenticated && isSider && }
diff --git a/bbbeasy-frontend/src/components/Presets.tsx b/bbbeasy-frontend/src/components/Presets.tsx
index 28bb6a4b..bd35abea 100644
--- a/bbbeasy-frontend/src/components/Presets.tsx
+++ b/bbbeasy-frontend/src/components/Presets.tsx
@@ -111,10 +111,19 @@ const PresetsCol: React.FC = ({
const [isModalVisible, setIsModalVisible] = React.useState(false);
const [isEditing, setIsEditing] = useState(false);
const [errorsEdit, setErrorsEdit] = React.useState({});
+ const [originalPreset, setOriginalPreset] = React.useState(null);
const isDefault = preset['name'] == 'default';
const deleteEnabled = deleteClickHandler != null && !isDefault;
const { token } = theme.useToken();
+ const clonePreset = (presetToClone: MyPresetType): MyPresetType => ({
+ ...presetToClone,
+ categories: presetToClone.categories.map((category) => ({
+ ...category,
+ subcategories: category.subcategories.map((subCategory) => ({ ...subCategory })),
+ })),
+ });
+
const props = {
beforeUpload: (file) => {
const isPNG = file.type === 'image/png' || file.type === 'image/jpeg' || file.type === 'image/jpg';
@@ -153,7 +162,10 @@ const PresetsCol: React.FC = ({
const showModal = (title: string, _titleTrans: string, content: SubCategoryType[]) => {
setIsModalVisible(true);
setModalTitle(title);
- setModalContent(content);
+ setOriginalPreset(clonePreset(preset));
+ setModalContent(content.map((item) => ({ ...item })));
+ setFile(null);
+ setFileList(null);
const indexLogo = content.findIndex((item) => item.type === 'file');
if (indexLogo > -1 && content[indexLogo].value != '') {
diff --git a/bbbeasy-frontend/src/components/layout/AppHeader.tsx b/bbbeasy-frontend/src/components/layout/AppHeader.tsx
index 54b16275..1e502035 100644
--- a/bbbeasy-frontend/src/components/layout/AppHeader.tsx
+++ b/bbbeasy-frontend/src/components/layout/AppHeader.tsx
@@ -78,18 +78,21 @@ const AppHeader = () => {
const isRoomsSearch = location.pathname.includes('rooms');
const [logo, setLogo] = React.useState('');
const isLoginPage = location.pathname.includes('login');
- if (isLoginPage) {
- setIsLogged(false);
- }
- settingsService
- .collect_settings()
- .then((response) => {
- const settings: SettingsType = response.data;
- setLogo(settings.logo);
- })
- .catch((error) => {
- console.log(error);
- });
+ const storedUser = AuthService.getCurrentUser();
+ const storedSession = AuthService.getCurrentSession();
+ const isAuthenticated = Boolean(storedUser && storedSession);
+
+ useEffect(() => {
+ settingsService
+ .collect_settings()
+ .then((response) => {
+ const settings: SettingsType = response.data;
+ setLogo(settings.logo);
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ }, []);
const logout = () => {
AuthService.logout()
.catch((error) => {
@@ -187,6 +190,7 @@ const AppHeader = () => {
);
+ const activeUser = currentUser ?? storedUser;
const menuProfile = {
items: [
{
@@ -194,9 +198,9 @@ const AppHeader = () => {
className: 'username-item',
label: (
<>
- {currentUser?.username}
+ {activeUser?.username}
- {currentUser?.email}
+ {activeUser?.email}
>
),
},
@@ -220,7 +224,7 @@ const AppHeader = () => {
return (
<>
- {!isLogged ? (
+ {!isAuthenticated || isLoginPage ? (
Date: Sat, 8 Aug 2026 15:17:51 +0100
Subject: [PATCH 04/17] impv1
---
bbbeasy-frontend/src/App-installer.css | 79 +++++++++++++++++++++++++-
bbbeasy-frontend/src/App-webapp.css | 75 ++++++++++++++++++++++--
2 files changed, 146 insertions(+), 8 deletions(-)
diff --git a/bbbeasy-frontend/src/App-installer.css b/bbbeasy-frontend/src/App-installer.css
index 94b0ae2e..124a5033 100644
--- a/bbbeasy-frontend/src/App-installer.css
+++ b/bbbeasy-frontend/src/App-installer.css
@@ -323,6 +323,49 @@ body.rtl {
margin: 25px 20px;
z-index: 2;
}
+.site-sider {
+ background: #07192c !important;
+}
+.site-sider .logo {
+ background: #07192c !important;
+}
+.site-sider .menu-sider .site-menu {
+ color: #ffffff !important;
+}
+.site-sider .site-menu .ant-menu-item,
+.site-sider .site-menu .ant-menu-submenu-title,
+.site-sider .site-menu .ant-menu-title-content,
+.site-sider .site-menu .ant-menu-item a,
+.site-sider .site-menu .ant-menu-submenu-title a,
+.site-sider .site-menu .anticon,
+.site-sider .sider-new-btn {
+ color: #ffffff !important;
+}
+.site-sider .sider-new-btn {
+ background: #1677ff !important;
+ border-color: #1677ff !important;
+}
+.site-sider .sider-new-btn:hover,
+.site-sider .sider-new-btn:focus {
+ background: #4096ff !important;
+ color: #ffffff !important;
+ border-color: #4096ff !important;
+}
+.site-sider .site-menu .ant-menu-submenu-title .ant-menu-title-content,
+.site-sider .site-menu .ant-menu-item .ant-menu-title-content {
+ color: #ffffff !important;
+}
+.site-sider .site-menu .ant-menu-item-selected,
+.site-sider .site-menu .ant-menu-submenu-selected > .ant-menu-submenu-title {
+ background: rgba(255, 255, 255, 0.08) !important;
+}
+.site-sider .site-menu .ant-menu-item:hover,
+.site-sider .site-menu .ant-menu-submenu-title:hover,
+.site-sider .site-menu .ant-menu-item:focus,
+.site-sider .site-menu .ant-menu-submenu-title:focus {
+ background: rgba(255, 255, 255, 0.12) !important;
+ color: #ffffff !important;
+}
.site-footer {
min-height: 50px;
z-index: 1;
@@ -367,11 +410,14 @@ body.rtl {
}
/*********************************************/
.color-primary {
- border-color: #fbbc0b !important;
+ background: #1677ff !important;
+ border-color: #1677ff !important;
+ color: #ffffff !important;
}
.color-primary:hover {
- color: #ffcf33 !important;
- border-color: #ffcf33 !important;
+ background: #4096ff !important;
+ border-color: #4096ff !important;
+ color: #ffffff !important;
}
.color-blue {
color: #fff !important;
@@ -443,6 +489,33 @@ body.rtl {
.button-container .ant-form-item-control-input-content {
display: flex;
}
+.modal-submit-btn .ant-btn-primary {
+ background: #1677ff !important;
+ border-color: #1677ff !important;
+ color: #ffffff !important;
+}
+.modal-submit-btn .ant-btn-primary:hover,
+.modal-submit-btn .ant-btn-primary:focus {
+ background: #4096ff !important;
+ border-color: #4096ff !important;
+ color: #ffffff !important;
+}
+
+.ant-page-header .ant-btn-primary,
+.site-page-header .ant-btn-primary {
+ background: #1677ff !important;
+ border-color: #1677ff !important;
+ color: #ffffff !important;
+}
+
+.ant-page-header .ant-btn-primary:hover,
+.ant-page-header .ant-btn-primary:focus,
+.site-page-header .ant-btn-primary:hover,
+.site-page-header .ant-btn-primary:focus {
+ background: #4096ff !important;
+ border-color: #4096ff !important;
+ color: #ffffff !important;
+}
.final-step-btn {
width: 81%;
display: block;
diff --git a/bbbeasy-frontend/src/App-webapp.css b/bbbeasy-frontend/src/App-webapp.css
index b6e1e805..d380bae4 100644
--- a/bbbeasy-frontend/src/App-webapp.css
+++ b/bbbeasy-frontend/src/App-webapp.css
@@ -323,11 +323,14 @@ body.rtl {
color: #fbbc0b !important;
}
.color-primary {
- border-color: #fbbc0b !important;
+ background: #1677ff !important;
+ border-color: #1677ff !important;
+ color: #ffffff !important;
}
.color-primary:hover {
- color: #ffcf33 !important;
- border-color: #ffcf33 !important;
+ background: #4096ff !important;
+ border-color: #4096ff !important;
+ color: #ffffff !important;
}
.color-blue {
color: #fff !important;
@@ -568,7 +571,7 @@ fieldset {
z-index: 2;
}
.site-sider {
- background: var(--bbbeasy-bg-layout) !important;
+ background: #07192c !important;
flex: 0 0 var(--bbbeasy-sider-width) !important;
max-width: var(--bbbeasy-sider-width) !important;
min-width: var(--bbbeasy-sider-width) !important;
@@ -595,7 +598,7 @@ fieldset {
.site-sider .logo {
position: relative;
z-index: 1;
- background: var(--bbbeasy-bg-layout);
+ background: #07192c;
width: 240px;
margin: 10px;
margin-left: 24px;
@@ -626,10 +629,45 @@ fieldset {
.site-sider .menu-sider .site-menu {
height: 100%;
background: transparent !important;
+ color: #ffffff !important;
}
.ant-menu-sub.ant-menu-inline {
background: transparent !important;
}
+.site-sider .site-menu .ant-menu-item,
+.site-sider .site-menu .ant-menu-submenu-title,
+.site-sider .site-menu .ant-menu-title-content,
+.site-sider .site-menu .ant-menu-item a,
+.site-sider .site-menu .ant-menu-submenu-title a,
+.site-sider .site-menu .anticon,
+.site-sider .sider-new-btn {
+ color: #ffffff !important;
+}
+.site-sider .sider-new-btn {
+ background: #1677ff !important;
+ border-color: #1677ff !important;
+}
+.site-sider .sider-new-btn:hover,
+.site-sider .sider-new-btn:focus {
+ background: #4096ff !important;
+ color: #ffffff !important;
+ border-color: #4096ff !important;
+}
+.site-sider .site-menu .ant-menu-submenu-title .ant-menu-title-content,
+.site-sider .site-menu .ant-menu-item .ant-menu-title-content {
+ color: #ffffff !important;
+}
+.site-sider .site-menu .ant-menu-item-selected,
+.site-sider .site-menu .ant-menu-submenu-selected > .ant-menu-submenu-title {
+ background: rgba(255, 255, 255, 0.08) !important;
+}
+.site-sider .site-menu .ant-menu-item:hover,
+.site-sider .site-menu .ant-menu-submenu-title:hover,
+.site-sider .site-menu .ant-menu-item:focus,
+.site-sider .site-menu .ant-menu-submenu-title:focus {
+ background: rgba(255, 255, 255, 0.12) !important;
+ color: #ffffff !important;
+}
.site-footer {
min-height: 50px;
z-index: 1;
@@ -1150,6 +1188,33 @@ fieldset {
.button-container .ant-form-item-control-input-content {
display: flex;
}
+.modal-submit-btn .ant-btn-primary {
+ background: #1677ff !important;
+ border-color: #1677ff !important;
+ color: #ffffff !important;
+}
+.modal-submit-btn .ant-btn-primary:hover,
+.modal-submit-btn .ant-btn-primary:focus {
+ background: #4096ff !important;
+ border-color: #4096ff !important;
+ color: #ffffff !important;
+}
+
+.ant-page-header .ant-btn-primary,
+.site-page-header .ant-btn-primary {
+ background: #1677ff !important;
+ border-color: #1677ff !important;
+ color: #ffffff !important;
+}
+
+.ant-page-header .ant-btn-primary:hover,
+.ant-page-header .ant-btn-primary:focus,
+.site-page-header .ant-btn-primary:hover,
+.site-page-header .ant-btn-primary:focus {
+ background: #4096ff !important;
+ border-color: #4096ff !important;
+ color: #ffffff !important;
+}
.install-form .ant-card-body {
display: flex;
flex-wrap: wrap;
From 8a87585449a834f03dfe48f0f7372c859818a82a Mon Sep 17 00:00:00 2001
From: talel
Date: Sat, 8 Aug 2026 15:55:25 +0100
Subject: [PATCH 05/17] impv2
---
bbbeasy-frontend/src/App-webapp.css | 438 +++++++++++++++++-
.../src/components/LandingPage.tsx | 62 ++-
2 files changed, 479 insertions(+), 21 deletions(-)
diff --git a/bbbeasy-frontend/src/App-webapp.css b/bbbeasy-frontend/src/App-webapp.css
index d380bae4..373b7c08 100644
--- a/bbbeasy-frontend/src/App-webapp.css
+++ b/bbbeasy-frontend/src/App-webapp.css
@@ -684,31 +684,445 @@ fieldset {
}
/******************LANDING******************/
.landing-content {
- margin: 45px;
- padding: 4%;
- border: 3px solid #fbbc0b !important;
- border-radius: 25px;
+ position: relative;
+ margin: 0;
+ min-height: calc(100vh - 74px);
+ overflow: hidden;
+ background:
+ radial-gradient(circle at 78% -10%, rgba(59, 130, 246, 0.35), transparent 28%),
+ radial-gradient(circle at -8% 100%, rgba(34, 211, 238, 0.16), transparent 26%),
+ linear-gradient(160deg, #050a1f 0%, #0a1238 46%, #0f1a4a 100%);
+}
+
+.landing-content::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-image:
+ linear-gradient(rgba(96, 165, 250, 0.07) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(96, 165, 250, 0.07) 1px, transparent 1px);
+ background-size: 48px 48px;
+ mask-image: radial-gradient(ellipse at center, black 40%, transparent 80%);
+ animation: landingGridShift 25s linear infinite;
+ pointer-events: none;
+}
+
+.landing-content::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background:
+ radial-gradient(circle at 15% 20%, rgba(59, 130, 246, 0.12), transparent 15%),
+ radial-gradient(circle at 86% 76%, rgba(34, 211, 238, 0.1), transparent 18%),
+ radial-gradient(circle at 52% 52%, rgba(99, 102, 241, 0.15), transparent 28%);
+ pointer-events: none;
+}
+
+.landing-content > .ant-row {
+ position: relative;
+ z-index: 2;
+ max-width: 1440px;
+ margin: 0 auto;
+ min-height: calc(100vh - 74px);
+ padding: 110px 5% 54px;
+ align-items: center;
+ gap: 32px;
+}
+
+.landing-content > .ant-row > .ant-col:first-child {
+ flex: 0 0 48%;
+ max-width: 48%;
+ position: relative;
+ z-index: 2;
+}
+
+.landing-content > .ant-row > .ant-col:last-child {
+ flex: 0 0 52%;
+ max-width: 52%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.landing-content .hero-content {
+ color: #e6ecff;
+}
+
+.landing-content .tag {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 8px 16px;
+ border-radius: 999px;
+ margin-bottom: 24px;
+ border: 1px solid rgba(96, 165, 250, 0.3);
+ background: rgba(59, 130, 246, 0.1);
+ color: #60a5fa;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 12px;
+ letter-spacing: 1.5px;
+ text-transform: uppercase;
+}
+
+.landing-content .tag .dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: #22d3ee;
+ box-shadow: 0 0 12px #22d3ee;
+ animation: tagPulse 1.6s infinite;
}
-.landing-content button {
- width: 30%;
+
+.landing-content h1 {
+ color: #eef4ff !important;
+ font-size: clamp(3.8rem, 4.8vw, 5.9rem) !important;
+ line-height: 0.96 !important;
+ letter-spacing: -0.05em;
+ margin-bottom: 18px !important;
+ text-shadow: 0 10px 30px rgba(59, 130, 246, 0.16);
+}
+
+.landing-content p,
+.landing-content strong {
+ color: #eef4ff !important;
+}
+
+.landing-content .mb-30 {
+ max-width: 620px;
+ margin-bottom: 0 !important;
+ color: rgba(230, 236, 255, 0.8);
+ font-size: 18px;
+ line-height: 1.65;
}
+
.landing-btns {
- gap: 15px;
display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+ margin-top: 34px;
+}
+
+.landing-content .ant-btn {
+ min-width: 138px;
+ height: 52px;
+ border-radius: 14px;
+ font-size: 16px;
+ font-weight: 600;
+ border: none;
+ box-shadow: 0 14px 28px rgba(0, 0, 0, 0.18);
}
-.landing-img {
- width: 85%;
+
+.landing-content .ant-btn-primary {
+ color: #0a1530 !important;
+ background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%) !important;
}
+
+.landing-content .color-primary {
+ color: #ffffff !important;
+ background: linear-gradient(135deg, #1d4ed8 0%, #3b82f6 55%, #22d3ee 100%) !important;
+}
+
+.landing-content .ant-btn:hover,
+.landing-content .ant-btn:focus {
+ transform: translateY(-2px);
+}
+
+.landing-content .hero-visual {
+ position: relative;
+ width: 100%;
+ max-width: 640px;
+ min-height: 380px;
+}
+
+.landing-content .mockup-card {
+ position: relative;
+ border-radius: 24px;
+ border: 1px solid rgba(96, 165, 250, 0.18);
+ background: rgba(15, 26, 74, 0.42);
+ backdrop-filter: blur(16px);
+ box-shadow: 0 28px 60px rgba(2, 6, 23, 0.45);
+ overflow: hidden;
+}
+
+.landing-content .main-card {
+ width: 100%;
+ min-height: 360px;
+ padding: 28px;
+ animation: landingFloat 6s ease-in-out infinite;
+}
+
+.landing-content .main-card::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background:
+ radial-gradient(circle at 80% 18%, rgba(96, 165, 250, 0.18), transparent 18%),
+ radial-gradient(circle at 12% 84%, rgba(34, 211, 238, 0.12), transparent 20%),
+ linear-gradient(135deg, rgba(7, 13, 36, 0.16), rgba(15, 26, 74, 0.02));
+ pointer-events: none;
+}
+
+.landing-content .mockup-head {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ justify-content: space-between;
+ gap: 16px;
+ align-items: center;
+ margin-bottom: 26px;
+ flex-wrap: wrap;
+}
+
+.landing-content .mock-tag,
+.landing-content .mock-count {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 16px;
+ border-radius: 999px;
+ border: 1px solid rgba(96, 165, 250, 0.28);
+ background: rgba(5, 10, 31, 0.55);
+ color: #9ad6ff;
+ font-size: 12px;
+ font-weight: 600;
+ letter-spacing: 0.08em;
+}
+
+.landing-content .mockup-grid {
+ position: relative;
+ z-index: 1;
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 12px;
+}
+
+.landing-content .mock-participant {
+ min-height: 150px;
+ border-radius: 16px;
+ background: rgba(7, 13, 36, 0.72);
+ border: 1px solid rgba(96, 165, 250, 0.12);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ overflow: hidden;
+}
+
+.landing-content .mock-participant::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(34, 211, 238, 0.04));
+}
+
+.landing-content .mock-avatar {
+ position: relative;
+ z-index: 1;
+ width: 44px;
+ height: 44px;
+ border-radius: 50%;
+ display: grid;
+ place-items: center;
+ font-weight: 800;
+ color: #071327;
+ background: linear-gradient(135deg, #38bdf8, #22d3ee);
+ box-shadow: 0 10px 26px rgba(34, 211, 238, 0.3);
+}
+
+.landing-content .mock-avatar.mock-orange {
+ background: linear-gradient(135deg, #fb923c, #f97316);
+}
+
+.landing-content .mock-avatar.mock-purple {
+ background: linear-gradient(135deg, #a855f7, #ec4899);
+}
+
+.landing-content .mock-avatar.mock-green {
+ background: linear-gradient(135deg, #2dd4bf, #22c55e);
+}
+
+.landing-content .mock-name {
+ position: absolute;
+ left: 10px;
+ bottom: 10px;
+ z-index: 1;
+ padding: 2px 8px;
+ border-radius: 999px;
+ background: rgba(0, 0, 0, 0.45);
+ color: #e6ecff;
+ font-size: 11px;
+}
+
+.landing-content .mockup-footer {
+ position: relative;
+ z-index: 1;
+ margin-top: 16px;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+}
+
+.landing-content .mockup-footer span {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 14px;
+ border-radius: 999px;
+ background: rgba(5, 10, 31, 0.6);
+ border: 1px solid rgba(34, 211, 238, 0.3);
+ color: #bdeeff;
+ font-size: 13px;
+}
+
+.features {
+ position: relative;
+ z-index: 2;
+ max-width: 1440px;
+ margin: 0 auto;
+ padding: 0 5% 100px;
+}
+
+.section-head {
+ text-align: center;
+ margin-bottom: 42px;
+}
+
+.section-head h2 {
+ color: #eef4ff;
+ font-size: 48px;
+ font-weight: 800;
+ letter-spacing: -0.02em;
+ margin-bottom: 10px;
+}
+
+.section-head p {
+ color: #8a97c7;
+ font-size: 16px;
+}
+
+.gradient-text {
+ background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 55%, #22d3ee 100%);
+ -webkit-background-clip: text;
+ background-clip: text;
+ color: transparent;
+}
+
+.features .card-feat {
+ background: rgba(15, 26, 74, 0.42);
+ border: 1px solid rgba(96, 165, 250, 0.18);
+ border-radius: 20px;
+ padding: 28px 24px;
+ backdrop-filter: blur(14px);
+ box-shadow: 0 18px 40px rgba(2, 6, 23, 0.24);
+ transition: transform 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
+}
+
+.features .card-feat:hover {
+ transform: translateY(-8px);
+ border-color: rgba(96, 165, 250, 0.46);
+ box-shadow: 0 24px 50px rgba(59, 130, 246, 0.24);
+}
+
.features .bbbeasy-btn {
font-size: 22px !important;
- clip-path: polygon(48% 0, 52% 0, 95% 25%, 95% 75%, 52% 100%, 48% 100%, 5% 75%, 5% 25%) !important;
- margin-bottom: 14px;
+ margin-bottom: 18px;
border-radius: 50%;
- background: #fbbc0b;
+ background: linear-gradient(135deg, #3b82f6 0%, #22d3ee 100%);
+ box-shadow: 0 10px 24px rgba(59, 130, 246, 0.28);
+ clip-path: polygon(48% 0, 52% 0, 95% 25%, 95% 75%, 52% 100%, 48% 100%, 5% 75%, 5% 25%) !important;
}
+
.bbbeasy-icon {
line-height: inherit !important;
}
+
+.features .card-feat p {
+ color: #e6ecff;
+ font-size: 14px;
+ line-height: 1.5;
+}
+
+@keyframes landingGridShift {
+ from {
+ background-position: 0 0, 0 0;
+ }
+ to {
+ background-position: 48px 48px, 48px 48px;
+ }
+}
+
+@keyframes landingFloat {
+ 0%,
+ 100% {
+ transform: translateY(0);
+ }
+ 50% {
+ transform: translateY(-10px);
+ }
+}
+
+@keyframes tagPulse {
+ 0%,
+ 100% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.35;
+ }
+}
+
+@media (max-width: 1200px) {
+ .landing-content > .ant-row {
+ padding-top: 96px;
+ }
+
+ .landing-content > .ant-row > .ant-col:first-child,
+ .landing-content > .ant-row > .ant-col:last-child {
+ flex: 0 0 100%;
+ max-width: 100%;
+ }
+
+ .landing-content .hero-visual {
+ max-width: 720px;
+ margin-top: 20px;
+ }
+}
+
+@media (max-width: 768px) {
+ .landing-content > .ant-row {
+ padding: 90px 20px 40px;
+ }
+
+ .landing-content h1 {
+ font-size: clamp(2.8rem, 13vw, 4.4rem) !important;
+ }
+
+ .landing-content .mb-30 {
+ font-size: 16px;
+ }
+
+ .landing-content .hero-visual {
+ min-height: 320px;
+ }
+
+ .landing-content .mockup-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .features {
+ padding: 0 20px 80px;
+ }
+}
+
+@keyframes landingFloat {
+ 0%,
+ 100% {
+ transform: translateY(0px);
+ }
+ 50% {
+ transform: translateY(-10px);
+ }
+}
/********************LOGIN/REGISTER********************/
.section-top {
padding: 50px 0 !important;
diff --git a/bbbeasy-frontend/src/components/LandingPage.tsx b/bbbeasy-frontend/src/components/LandingPage.tsx
index f72e990b..4d1bb154 100644
--- a/bbbeasy-frontend/src/components/LandingPage.tsx
+++ b/bbbeasy-frontend/src/components/LandingPage.tsx
@@ -21,7 +21,7 @@ import { useNavigate } from 'react-router-dom';
import { Trans, withTranslation } from 'react-i18next';
import { Row, Col, Typography, Avatar, Button } from 'antd';
-import { AppstoreAddOutlined, BgColorsOutlined, PlayCircleOutlined, ControlOutlined } from '@ant-design/icons';
+import { AppstoreAddOutlined, BgColorsOutlined, PlayCircleOutlined, ControlOutlined, ReadOutlined, AudioOutlined, SafetyOutlined } from '@ant-design/icons';
import DynamicIcon from './DynamicIcon';
import settingsService from 'services/settings.service';
@@ -37,7 +37,11 @@ const LandingPage = () => {
return (
<>
-
+
+
+
+
+
Welcome to {{ platformName: platformName }}
@@ -47,6 +51,7 @@ const LandingPage = () => {
{' '}
+ . Solution professionnelle et sécurisée pour vos visioconférences.
-
-
+
+
+
+
+ Classe virtuelle BBBEasy
+
+ 128 Participants Connectés
+
+
+
+ JD
+ John Doe
+
+
+ SM
+ Sarah M.
+
+
+ AK
+ Alex K.
+
+
+ ML
+ Maria L.
+
+
+
+
+ HD Audio
+
+
+ End-to-end Encryption
+
+
+
+
+
+ Powerful Features
+
+
Everything you need to run seamless online sessions
+
-
+
} className="ant-btn-primary bbbeasy-btn" />
-
+
} className="ant-btn-primary bbbeasy-btn" />
-
+
} className="ant-btn-primary bbbeasy-btn" />
-
+
} className="ant-btn-primary bbbeasy-btn" />
-
+
}
From 8645b60e4f713e559f52ac14ca1dbce232240095 Mon Sep 17 00:00:00 2001
From: talel
Date: Sun, 9 Aug 2026 13:07:40 +0100
Subject: [PATCH 06/17] before_anim
---
bbbeasy-frontend/src/App-installer.css | 17 +-
bbbeasy-frontend/src/App-webapp.css | 790 ++++++++++++++----
.../src/components/LandingPage.tsx | 186 +++--
3 files changed, 776 insertions(+), 217 deletions(-)
diff --git a/bbbeasy-frontend/src/App-installer.css b/bbbeasy-frontend/src/App-installer.css
index 124a5033..33ced0b2 100644
--- a/bbbeasy-frontend/src/App-installer.css
+++ b/bbbeasy-frontend/src/App-installer.css
@@ -286,17 +286,19 @@ body.rtl {
}
.site-header {
z-index: 1;
- background: var(--bbbeasy-bg-layout) !important;
+ background: linear-gradient(135deg, rgba(5, 12, 35, 0.98) 0%, rgba(7, 25, 44, 0.98) 45%, rgba(9, 31, 62, 0.98) 100%) !important;
+ border-bottom: 1px solid rgba(96, 165, 250, 0.12);
+ box-shadow: 0 10px 28px rgba(2, 6, 23, 0.22);
}
.site-header .lang-btn {
border-color: transparent;
box-shadow: none;
- color: var(--bbbeasy-darken-gray);
+ color: #dbe9ff;
padding: 0;
}
.site-header .lang-btn:hover,
.site-header .lang-btn.ant-dropdown-open {
- color: #fbbc0b !important;
+ color: #38bdf8 !important;
outline: unset !important;
}
.site-header-inner {
@@ -314,10 +316,17 @@ body.rtl {
height: auto;
max-height: 64px;
max-width: 64px;
+ filter: drop-shadow(0 0 12px rgba(59, 130, 246, 0.28));
}
.site-header-inner button {
background: transparent !important;
- color: var(--bbbeasy-darken-gray) !important;
+ color: #edf4ff !important;
+ transition: color 0.25s ease, transform 0.25s ease, opacity 0.25s ease;
+}
+.site-header-inner button:hover,
+.site-header-inner button:focus {
+ color: #38bdf8 !important;
+ transform: translateY(-1px);
}
.site-content {
margin: 25px 20px;
diff --git a/bbbeasy-frontend/src/App-webapp.css b/bbbeasy-frontend/src/App-webapp.css
index 373b7c08..8d74f650 100644
--- a/bbbeasy-frontend/src/App-webapp.css
+++ b/bbbeasy-frontend/src/App-webapp.css
@@ -441,20 +441,60 @@ fieldset {
.page-layout-content-rtl {
min-height: var(--bbbeasy-page-height) !important;
display: flex !important;
+ background:
+ radial-gradient(circle at 18% 0%, rgba(59, 130, 246, 0.2), transparent 24%),
+ radial-gradient(circle at 88% 12%, rgba(34, 211, 238, 0.14), transparent 18%),
+ linear-gradient(180deg, #06122e 0%, #07192c 32%, #091f3e 100%);
}
.site-header {
z-index: 1;
- background: var(--bbbeasy-bg-layout) !important;
+ position: relative;
+ overflow: hidden;
+ background:
+ linear-gradient(135deg, rgba(5, 12, 35, 0.98) 0%, rgba(7, 25, 44, 0.98) 45%, rgba(9, 31, 62, 0.98) 100%) !important;
+ border-bottom: 1px solid rgba(96, 165, 250, 0.12);
+ box-shadow: 0 10px 28px rgba(2, 6, 23, 0.22);
+}
+.page-layout-content .site-header,
+.page-layout-content-rtl .site-header {
+ background:
+ linear-gradient(135deg, rgba(5, 12, 35, 0.98) 0%, rgba(7, 25, 44, 0.98) 45%, rgba(9, 31, 62, 0.98) 100%) !important;
+ border-bottom: 1px solid rgba(96, 165, 250, 0.12);
+ box-shadow: 0 10px 28px rgba(2, 6, 23, 0.22);
+ backdrop-filter: blur(16px);
+}
+.site-header::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background:
+ radial-gradient(circle at 14% 50%, rgba(34, 211, 238, 0.18), transparent 16%),
+ radial-gradient(circle at 82% 18%, rgba(59, 130, 246, 0.18), transparent 16%);
+ pointer-events: none;
+ opacity: 0.9;
+}
+.site-header::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-image:
+ linear-gradient(rgba(96, 165, 250, 0.06) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(96, 165, 250, 0.06) 1px, transparent 1px);
+ background-size: 44px 44px;
+ opacity: 0.35;
+ pointer-events: none;
+ animation: headerGridShift 28s linear infinite;
}
.site-header .lang-btn {
border-color: transparent;
box-shadow: none;
- color: var(--bbbeasy-darken-gray);
+ color: #dbe9ff;
padding: 0;
+ font-weight: 500;
}
.site-header .lang-btn:hover,
.site-header .lang-btn.ant-dropdown-open {
- color: #fbbc0b !important;
+ color: #38bdf8 !important;
outline: unset !important;
}
.site-header-inner {
@@ -462,19 +502,29 @@ fieldset {
display: flex;
justify-content: space-between;
align-items: center;
+ width: 100%;
margin: 0 !important;
top: 50%;
-ms-transform: translateY(-50%);
transform: translateY(-50%);
+ z-index: 1;
}
.header-logo-image {
height: auto;
max-height: 64px;
max-width: 64px;
+ filter: drop-shadow(0 0 12px rgba(59, 130, 246, 0.28));
+ animation: logoPulse 4.5s ease-in-out infinite;
}
.site-header-inner button {
background: transparent !important;
- color: var(--bbbeasy-darken-gray) !important;
+ color: #edf4ff !important;
+ transition: color 0.25s ease, transform 0.25s ease, opacity 0.25s ease;
+}
+.site-header-inner button:hover,
+.site-header-inner button:focus {
+ color: #38bdf8 !important;
+ transform: translateY(-1px);
}
.search-input {
border-radius: 15px !important;
@@ -486,22 +536,32 @@ fieldset {
.search-input input,
.search-input.ant-input-affix-wrapper:hover,
.search-input.ant-input-affix-wrapper:focus {
- background: white !important;
+ background: rgba(8, 18, 46, 0.9) !important;
+ color: #eef4ff !important;
+ border: 1px solid rgba(96, 165, 250, 0.16);
+ box-shadow: 0 12px 24px rgba(2, 6, 23, 0.16);
}
.search-input.ant-input-affix-wrapper-focused {
- background: white !important;
- border: 1px solid #ffcf33 !important;
+ background: rgba(9, 22, 58, 0.98) !important;
+ border: 1px solid rgba(56, 189, 248, 0.72) !important;
+ box-shadow: 0 0 0 4px rgba(56, 189, 248, 0.08);
}
.search-input input {
padding: 0 15px !important;
}
.search-input .anticon-search {
- color: var(--bbbeasy-medimum-gray);
+ color: #7fbef7;
}
.site-header .profil-btn {
- color: var(--bbbeasy-darken-gray) !important;
+ color: #edf4ff !important;
clip-path: polygon(48% 0, 52% 0, 95% 25%, 95% 75%, 52% 100%, 48% 100%, 5% 75%, 5% 25%);
border-radius: 50% !important;
+ transition: transform 0.25s ease, color 0.25s ease, box-shadow 0.25s ease;
+}
+.site-header .profil-btn:hover,
+.site-header .profil-btn:focus {
+ color: #38bdf8 !important;
+ transform: translateY(-1px);
}
.profil-btn-dropdown .ant-dropdown-menu-item {
padding: 5px 20px !important;
@@ -569,6 +629,21 @@ fieldset {
.site-content {
margin: 25px 20px;
z-index: 2;
+ background: transparent !important;
+}
+.page-layout-content .page-layout-body,
+.page-layout-content-rtl .page-layout-body {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ background:
+ radial-gradient(circle at 18% 0%, rgba(59, 130, 246, 0.2), transparent 24%),
+ radial-gradient(circle at 88% 12%, rgba(34, 211, 238, 0.14), transparent 18%),
+ linear-gradient(180deg, #06122e 0%, #07192c 32%, #091f3e 100%) !important;
+}
+.page-layout-content .site-content,
+.page-layout-content-rtl .site-content {
+ background: transparent !important;
}
.site-sider {
background: #07192c !important;
@@ -668,87 +743,134 @@ fieldset {
background: rgba(255, 255, 255, 0.12) !important;
color: #ffffff !important;
}
-.site-footer {
+.page-layout-content .site-footer,
+.page-layout-content-rtl .site-footer {
min-height: 50px;
z-index: 1;
padding: 0 50px !important;
display: flex;
justify-content: space-between;
align-items: center;
+ background: linear-gradient(135deg, rgba(5, 12, 35, 0.98) 0%, rgba(7, 25, 44, 0.98) 45%, rgba(9, 31, 62, 0.98) 100%) !important;
+ border-top: 1px solid rgba(96, 165, 250, 0.12);
+ box-shadow: 0 -10px 28px rgba(2, 6, 23, 0.22);
}
-.site-footer .ant-typography {
- color: #989898 !important;
-}
-.site-footer button {
+.page-layout-content .site-footer,
+.page-layout-content-rtl .site-footer,
+.site-footer {
+ background:
+ linear-gradient(135deg, rgba(5, 12, 35, 0.98) 0%, rgba(7, 25, 44, 0.98) 45%, rgba(9, 31, 62, 0.98) 100%) !important;
+ border-top: 1px solid rgba(96, 165, 250, 0.12);
+ box-shadow: 0 -10px 28px rgba(2, 6, 23, 0.22);
+}
+.page-layout-content .site-footer .ant-typography,
+.page-layout-content-rtl .site-footer .ant-typography {
+ color: #dbe9ff !important;
+}
+.page-layout-content .site-footer .ant-typography .ant-btn,
+.page-layout-content .site-footer .ant-typography button,
+.page-layout-content-rtl .site-footer .ant-typography .ant-btn,
+.page-layout-content-rtl .site-footer .ant-typography button {
+ color: #7fbef7 !important;
+}
+.page-layout-content .site-footer button,
+.page-layout-content-rtl .site-footer button {
padding: 0 5px !important;
}
/******************LANDING******************/
-.landing-content {
+.landing-shell {
position: relative;
- margin: 0;
- min-height: calc(100vh - 74px);
+ margin: -25px -20px 0;
+ padding: 0 20px 140px;
overflow: hidden;
+ isolation: isolate;
background:
- radial-gradient(circle at 78% -10%, rgba(59, 130, 246, 0.35), transparent 28%),
- radial-gradient(circle at -8% 100%, rgba(34, 211, 238, 0.16), transparent 26%),
- linear-gradient(160deg, #050a1f 0%, #0a1238 46%, #0f1a4a 100%);
+ radial-gradient(circle at 14% 10%, rgba(59, 130, 246, 0.42), transparent 18%),
+ radial-gradient(circle at 84% 18%, rgba(34, 211, 238, 0.2), transparent 18%),
+ radial-gradient(circle at 56% 52%, rgba(99, 102, 241, 0.18), transparent 24%),
+ linear-gradient(180deg, #030812 0%, #071329 42%, #081d3d 100%);
+ background-size: 150% 150%;
+ animation: landingShellDrift 28s ease-in-out infinite;
}
-.landing-content::before {
+.landing-shell::before {
content: '';
position: absolute;
inset: 0;
background-image:
- linear-gradient(rgba(96, 165, 250, 0.07) 1px, transparent 1px),
- linear-gradient(90deg, rgba(96, 165, 250, 0.07) 1px, transparent 1px);
- background-size: 48px 48px;
- mask-image: radial-gradient(ellipse at center, black 40%, transparent 80%);
- animation: landingGridShift 25s linear infinite;
+ linear-gradient(rgba(96, 165, 250, 0.1) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(96, 165, 250, 0.1) 1px, transparent 1px);
+ background-size: 52px 52px;
+ mask-image: radial-gradient(ellipse at center, black 30%, transparent 84%);
+ animation: landingGridShift 24s linear infinite;
pointer-events: none;
+ opacity: 0.68;
}
-.landing-content::after {
+.landing-shell::after {
content: '';
position: absolute;
inset: 0;
background:
- radial-gradient(circle at 15% 20%, rgba(59, 130, 246, 0.12), transparent 15%),
- radial-gradient(circle at 86% 76%, rgba(34, 211, 238, 0.1), transparent 18%),
- radial-gradient(circle at 52% 52%, rgba(99, 102, 241, 0.15), transparent 28%);
+ radial-gradient(circle at 8% 18%, rgba(56, 189, 248, 0.34), transparent 5%),
+ radial-gradient(circle at 14% 26%, rgba(96, 165, 250, 0.22), transparent 4%),
+ radial-gradient(circle at 22% 12%, rgba(34, 211, 238, 0.26), transparent 4%),
+ radial-gradient(circle at 38% 22%, rgba(96, 165, 250, 0.18), transparent 5%),
+ radial-gradient(circle at 52% 14%, rgba(34, 211, 238, 0.24), transparent 4%),
+ radial-gradient(circle at 68% 18%, rgba(96, 165, 250, 0.2), transparent 4%),
+ radial-gradient(circle at 84% 26%, rgba(34, 211, 238, 0.22), transparent 4%),
+ radial-gradient(circle at 90% 68%, rgba(59, 130, 246, 0.2), transparent 12%),
+ radial-gradient(circle at 58% 86%, rgba(99, 102, 241, 0.18), transparent 16%);
pointer-events: none;
+ mix-blend-mode: screen;
+ animation: landingSparkles 18s linear infinite;
}
-.landing-content > .ant-row {
+.landing-shell .landing-content {
position: relative;
z-index: 2;
max-width: 1440px;
margin: 0 auto;
min-height: calc(100vh - 74px);
- padding: 110px 5% 54px;
+ padding: 96px 0 52px;
align-items: center;
- gap: 32px;
+ gap: 34px;
+ background: transparent;
+ overflow: visible;
+ flex-wrap: nowrap;
}
-.landing-content > .ant-row > .ant-col:first-child {
- flex: 0 0 48%;
- max-width: 48%;
+.landing-shell .landing-content::before,
+.landing-shell .landing-content::after {
+ content: none;
+}
+
+.landing-shell .landing-content > .ant-col:first-child {
+ flex: 0 0 47%;
+ max-width: 47%;
position: relative;
z-index: 2;
}
-.landing-content > .ant-row > .ant-col:last-child {
- flex: 0 0 52%;
- max-width: 52%;
+.landing-shell .landing-content > .ant-col:last-child {
+ flex: 0 0 500px;
+ max-width: 500px;
display: flex;
align-items: center;
justify-content: center;
+ padding-left: 0;
+}
+
+.landing-content {
+ color: #e6ecff;
}
-.landing-content .hero-content {
+.landing-shell .hero-content {
color: #e6ecff;
+ animation: heroTextIn 0.9s ease both;
}
-.landing-content .tag {
+.landing-shell .tag {
display: inline-flex;
align-items: center;
gap: 8px;
@@ -762,9 +884,11 @@ fieldset {
font-size: 12px;
letter-spacing: 1.5px;
text-transform: uppercase;
+ box-shadow: 0 10px 22px rgba(2, 6, 23, 0.22);
+ animation: tagGlow 3s ease-in-out infinite;
}
-.landing-content .tag .dot {
+.landing-shell .tag .dot {
width: 7px;
height: 7px;
border-radius: 50%;
@@ -773,7 +897,7 @@ fieldset {
animation: tagPulse 1.6s infinite;
}
-.landing-content h1 {
+.landing-shell .landing-content h1 {
color: #eef4ff !important;
font-size: clamp(3.8rem, 4.8vw, 5.9rem) !important;
line-height: 0.96 !important;
@@ -782,12 +906,12 @@ fieldset {
text-shadow: 0 10px 30px rgba(59, 130, 246, 0.16);
}
-.landing-content p,
-.landing-content strong {
+.landing-shell .landing-content p,
+.landing-shell .landing-content strong {
color: #eef4ff !important;
}
-.landing-content .mb-30 {
+.landing-shell .landing-content .mb-30 {
max-width: 620px;
margin-bottom: 0 !important;
color: rgba(230, 236, 255, 0.8);
@@ -802,7 +926,7 @@ fieldset {
margin-top: 34px;
}
-.landing-content .ant-btn {
+.landing-shell .landing-content .ant-btn {
min-width: 138px;
height: 52px;
border-radius: 14px;
@@ -810,97 +934,148 @@ fieldset {
font-weight: 600;
border: none;
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.18);
+ transition: transform 0.25s ease, box-shadow 0.25s ease, filter 0.25s ease;
}
-.landing-content .ant-btn-primary {
+.landing-shell .landing-content .ant-btn-primary {
color: #0a1530 !important;
background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%) !important;
}
-.landing-content .color-primary {
+.landing-shell .landing-content .color-primary {
color: #ffffff !important;
background: linear-gradient(135deg, #1d4ed8 0%, #3b82f6 55%, #22d3ee 100%) !important;
}
-.landing-content .ant-btn:hover,
-.landing-content .ant-btn:focus {
- transform: translateY(-2px);
+.landing-shell .landing-content .ant-btn:hover,
+.landing-shell .landing-content .ant-btn:focus {
+ transform: translateY(-3px);
+ box-shadow: 0 18px 32px rgba(2, 6, 23, 0.28);
+ filter: brightness(1.02);
}
-.landing-content .hero-visual {
+.landing-shell .hero-visual {
position: relative;
- width: 100%;
- max-width: 640px;
- min-height: 380px;
+ width: 500px;
+ height: 440px;
+ min-height: 440px;
+ animation: heroCardIn 1s ease both 0.12s;
+ margin-left: 0;
+ transform: translateX(-68px);
+ isolation: isolate;
+ overflow: visible;
}
-.landing-content .mockup-card {
- position: relative;
- border-radius: 24px;
- border: 1px solid rgba(96, 165, 250, 0.18);
- background: rgba(15, 26, 74, 0.42);
- backdrop-filter: blur(16px);
- box-shadow: 0 28px 60px rgba(2, 6, 23, 0.45);
+.landing-shell .hero-visual::before {
+ content: '';
+ position: absolute;
+ inset: -70px -90px -70px -90px;
+ z-index: 0;
+ background:
+ radial-gradient(circle at 50% 35%, rgba(56, 189, 248, 0.24), transparent 26%),
+ radial-gradient(circle at 82% 22%, rgba(59, 130, 246, 0.22), transparent 20%),
+ radial-gradient(circle at 30% 78%, rgba(34, 211, 238, 0.12), transparent 24%);
+ filter: blur(34px);
+ opacity: 0.95;
+ transform: translate3d(0, 0, 0);
+ animation: visualHalo 8s ease-in-out infinite;
+ pointer-events: none;
+}
+
+.landing-shell .mockup-card {
+ position: absolute;
+ inset: 0;
+ z-index: 1;
+ border-radius: 20px;
+ border: 1px solid rgba(96, 165, 250, 0.22);
+ background: rgba(15, 26, 74, 0.45);
+ backdrop-filter: blur(20px);
+ -webkit-backdrop-filter: blur(20px);
+ box-shadow: 0 30px 70px -20px rgba(2, 6, 23, 0.8);
overflow: hidden;
}
-.landing-content .main-card {
+.landing-shell .mc-main {
width: 100%;
- min-height: 360px;
- padding: 28px;
+ height: 100%;
+ padding: 20px;
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ box-sizing: border-box;
animation: landingFloat 6s ease-in-out infinite;
}
-.landing-content .main-card::before {
+.landing-shell .mc-main::before {
content: '';
position: absolute;
inset: 0;
background:
- radial-gradient(circle at 80% 18%, rgba(96, 165, 250, 0.18), transparent 18%),
- radial-gradient(circle at 12% 84%, rgba(34, 211, 238, 0.12), transparent 20%),
- linear-gradient(135deg, rgba(7, 13, 36, 0.16), rgba(15, 26, 74, 0.02));
+ linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(34, 211, 238, 0.05));
pointer-events: none;
}
-.landing-content .mockup-head {
+.landing-shell .mockup-head {
position: relative;
z-index: 1;
display: flex;
justify-content: space-between;
gap: 16px;
align-items: center;
- margin-bottom: 26px;
+ margin-bottom: 18px;
flex-wrap: wrap;
}
-.landing-content .mock-tag,
-.landing-content .mock-count {
+.landing-shell .mock-tag,
+.landing-shell .mock-count {
display: inline-flex;
align-items: center;
gap: 8px;
- padding: 10px 16px;
- border-radius: 999px;
- border: 1px solid rgba(96, 165, 250, 0.28);
- background: rgba(5, 10, 31, 0.55);
- color: #9ad6ff;
- font-size: 12px;
+ padding: 5px 10px;
+ border-radius: 6px;
+ border: 1px solid rgba(34, 211, 238, 0.2);
+ background: rgba(34, 211, 238, 0.1);
+ color: #22d3ee;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 11px;
font-weight: 600;
- letter-spacing: 0.08em;
+ letter-spacing: 0.03em;
}
-.landing-content .mockup-grid {
+.landing-shell .rec-indicator {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ color: #ff5a7a;
+ font-size: 10px;
+ font-family: 'JetBrains Mono', monospace;
+ font-weight: 600;
+}
+
+.landing-shell .rec-dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ background: #ff5a7a;
+ box-shadow: 0 0 10px #ff5a7a;
+ animation: pulse 1s infinite;
+}
+
+.landing-shell .mockup-grid {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
+ grid-template-rows: repeat(2, minmax(0, 1fr));
gap: 12px;
+ flex: 1;
}
-.landing-content .mock-participant {
- min-height: 150px;
- border-radius: 16px;
- background: rgba(7, 13, 36, 0.72);
- border: 1px solid rgba(96, 165, 250, 0.12);
+.landing-shell .participant {
+ min-height: 0;
+ border-radius: 12px;
+ background: rgba(7, 13, 36, 0.6);
+ border: 1px solid rgba(96, 165, 250, 0.15);
display: flex;
align-items: center;
justify-content: center;
@@ -908,70 +1083,143 @@ fieldset {
overflow: hidden;
}
-.landing-content .mock-participant::before {
+.landing-shell .participant::before {
content: '';
position: absolute;
inset: 0;
- background: linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(34, 211, 238, 0.04));
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(34, 211, 238, 0.05));
}
-.landing-content .mock-avatar {
+.landing-shell .avatar {
position: relative;
z-index: 1;
- width: 44px;
- height: 44px;
+ width: 45px;
+ height: 45px;
border-radius: 50%;
display: grid;
place-items: center;
- font-weight: 800;
- color: #071327;
- background: linear-gradient(135deg, #38bdf8, #22d3ee);
- box-shadow: 0 10px 26px rgba(34, 211, 238, 0.3);
+ font-weight: 700;
+ color: #050a1f;
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
+ animation: avatarFloat 4.8s ease-in-out infinite;
}
-.landing-content .mock-avatar.mock-orange {
+.landing-shell .mock-blue {
+ background: linear-gradient(135deg, #3b82f6, #22d3ee);
+}
+
+.landing-shell .mock-orange {
background: linear-gradient(135deg, #fb923c, #f97316);
}
-.landing-content .mock-avatar.mock-purple {
+.landing-shell .mock-purple {
background: linear-gradient(135deg, #a855f7, #ec4899);
}
-.landing-content .mock-avatar.mock-green {
+.landing-shell .mock-green {
background: linear-gradient(135deg, #2dd4bf, #22c55e);
}
-.landing-content .mock-name {
+.landing-shell .name-tag {
position: absolute;
- left: 10px;
- bottom: 10px;
+ left: 8px;
+ bottom: 8px;
z-index: 1;
- padding: 2px 8px;
- border-radius: 999px;
- background: rgba(0, 0, 0, 0.45);
- color: #e6ecff;
- font-size: 11px;
+ padding: 3px 8px;
+ border-radius: 4px;
+ background: rgba(0, 0, 0, 0.6);
+ color: #fff;
+ font-size: 10px;
}
-.landing-content .mockup-footer {
+.landing-shell .mic-icon {
position: relative;
z-index: 1;
- margin-top: 16px;
- display: flex;
- flex-wrap: wrap;
- gap: 12px;
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ font-size: 9px;
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ background: rgba(0, 0, 0, 0.4);
+ display: grid;
+ place-items: center;
+ color: #fff;
}
-.landing-content .mockup-footer span {
- display: inline-flex;
+.landing-shell .mic-off {
+ background: rgba(255, 90, 122, 0.6);
+}
+
+.landing-shell .floating-ui {
+ position: absolute;
+ inset: auto;
+ z-index: 2;
+ padding: 12px 18px;
+ border-radius: 14px;
+ display: flex;
align-items: center;
- gap: 8px;
- padding: 10px 14px;
- border-radius: 999px;
- background: rgba(5, 10, 31, 0.6);
- border: 1px solid rgba(34, 211, 238, 0.3);
- color: #bdeeff;
+ gap: 10px;
font-size: 13px;
+ font-weight: 500;
+ color: #fff;
+ background: rgba(15, 26, 74, 0.9);
+ box-shadow: 0 10px 30px rgba(59, 130, 246, 0.3);
+}
+
+.landing-shell .fu-1 {
+ top: -25px;
+ right: 20px;
+ border: 1px solid #60a5fa;
+ animation: floatUi 5s ease-in-out infinite;
+}
+
+.landing-shell .fu-2 {
+ bottom: -20px;
+ left: 20px;
+ border: 1px solid #22d3ee;
+ box-shadow: 0 10px 30px rgba(34, 211, 238, 0.3);
+ animation: floatUi 5s ease-in-out infinite reverse;
+}
+
+.landing-shell .wave-bars {
+ display: flex;
+ gap: 2px;
+ align-items: center;
+ height: 16px;
+}
+
+.landing-shell .wave-bars span {
+ width: 3px;
+ background: #22d3ee;
+ border-radius: 2px;
+ animation: wave 1s ease-in-out infinite;
+}
+
+.landing-shell .wave-bars span:nth-child(1) {
+ height: 40%;
+ animation-delay: 0s;
+}
+
+.landing-shell .wave-bars span:nth-child(2) {
+ height: 80%;
+ animation-delay: 0.1s;
+}
+
+.landing-shell .wave-bars span:nth-child(3) {
+ height: 60%;
+ animation-delay: 0.2s;
+}
+
+.landing-shell .wave-bars span:nth-child(4) {
+ height: 100%;
+ animation-delay: 0.3s;
+}
+
+.landing-shell .wave-bars span:nth-child(5) {
+ height: 50%;
+ animation-delay: 0.4s;
}
.features {
@@ -979,17 +1227,55 @@ fieldset {
z-index: 2;
max-width: 1440px;
margin: 0 auto;
- padding: 0 5% 100px;
+ padding: 0 0 0;
+}
+
+.features-block {
+ position: relative;
+ z-index: 2;
+ max-width: 1440px;
+ margin: 0 auto;
+ padding: 0 0 40px;
+}
+
+.features-row {
+ margin-bottom: 24px;
+}
+
+.features-row-last {
+ max-width: 25%;
+ margin-left: 0;
+}
+
+.card-feat-last {
+ min-width: 290px;
+}
+
+@media (min-width: 992px) {
+ .features-row {
+ flex-wrap: nowrap;
+ }
+
+ .features-row > .ant-col {
+ flex: 1 1 0 !important;
+ max-width: none !important;
+ }
+
+ .card-feat-last {
+ min-width: 0;
+ }
}
.section-head {
text-align: center;
- margin-bottom: 42px;
+ margin: 12px auto 42px;
+ max-width: 820px;
+ animation: heroTextIn 0.9s ease both 0.18s;
}
.section-head h2 {
color: #eef4ff;
- font-size: 48px;
+ font-size: clamp(42px, 4vw, 58px);
font-weight: 800;
letter-spacing: -0.02em;
margin-bottom: 10px;
@@ -1008,15 +1294,24 @@ fieldset {
}
.features .card-feat {
- background: rgba(15, 26, 74, 0.42);
- border: 1px solid rgba(96, 165, 250, 0.18);
- border-radius: 20px;
+ background: rgba(9, 18, 46, 0.6);
+ border: 1px solid rgba(96, 165, 250, 0.16);
+ border-radius: 22px;
padding: 28px 24px;
backdrop-filter: blur(14px);
box-shadow: 0 18px 40px rgba(2, 6, 23, 0.24);
- transition: transform 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
+ transition: transform 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease, translate 0.3s ease;
+ min-height: 212px;
+ opacity: 0;
+ animation: cardRise 0.8s ease forwards;
}
+.features .card-feat:nth-child(1) { animation-delay: 0.08s; }
+.features .card-feat:nth-child(2) { animation-delay: 0.16s; }
+.features .card-feat:nth-child(3) { animation-delay: 0.24s; }
+.features .card-feat:nth-child(4) { animation-delay: 0.32s; }
+.features .card-feat:nth-child(5) { animation-delay: 0.42s; }
+
.features .card-feat:hover {
transform: translateY(-8px);
border-color: rgba(96, 165, 250, 0.46);
@@ -1038,8 +1333,22 @@ fieldset {
.features .card-feat p {
color: #e6ecff;
- font-size: 14px;
- line-height: 1.5;
+ font-size: 15px;
+ line-height: 1.55;
+ margin-top: 10px;
+}
+
+.features .card-feat:nth-child(3) {
+ transform: translateY(8px);
+}
+
+.features .card-feat:nth-child(4) {
+ transform: translateY(8px);
+}
+
+.features .card-feat:nth-child(3):hover,
+.features .card-feat:nth-child(4):hover {
+ transform: translateY(0);
}
@keyframes landingGridShift {
@@ -1051,6 +1360,70 @@ fieldset {
}
}
+@keyframes landingShellDrift {
+ 0%,
+ 100% {
+ background-position: 0% 0%;
+ }
+ 50% {
+ background-position: 100% 14%;
+ }
+}
+
+@keyframes landingSparkles {
+ 0% {
+ transform: translate3d(0, 0, 0);
+ opacity: 0.7;
+ }
+ 50% {
+ transform: translate3d(0, -8px, 0);
+ opacity: 1;
+ }
+ 100% {
+ transform: translate3d(0, 0, 0);
+ opacity: 0.7;
+ }
+}
+
+@keyframes heroTextIn {
+ from {
+ opacity: 0;
+ transform: translateY(18px);
+ filter: blur(4px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ filter: blur(0);
+ }
+}
+
+@keyframes heroCardIn {
+ from {
+ opacity: 0;
+ transform: translateX(22px) scale(0.98);
+ filter: blur(4px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0) scale(1);
+ filter: blur(0);
+ }
+}
+
+@keyframes cardRise {
+ from {
+ opacity: 0;
+ transform: translateY(18px);
+ filter: blur(4px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ filter: blur(0);
+ }
+}
+
@keyframes landingFloat {
0%,
100% {
@@ -1071,47 +1444,184 @@ fieldset {
}
}
+@keyframes tagGlow {
+ 0%,
+ 100% {
+ box-shadow: 0 10px 22px rgba(2, 6, 23, 0.22), 0 0 0 1px rgba(96, 165, 250, 0.12);
+ }
+ 50% {
+ box-shadow: 0 12px 26px rgba(2, 6, 23, 0.24), 0 0 0 1px rgba(96, 165, 250, 0.24);
+ }
+}
+
+@keyframes headerGridShift {
+ from {
+ background-position: 0 0, 0 0;
+ }
+ to {
+ background-position: 44px 44px, 44px 44px;
+ }
+}
+
+@keyframes logoPulse {
+ 0%,
+ 100% {
+ transform: translateY(0);
+ filter: drop-shadow(0 0 12px rgba(59, 130, 246, 0.28));
+ }
+ 50% {
+ transform: translateY(-1px);
+ filter: drop-shadow(0 0 18px rgba(56, 189, 248, 0.4));
+ }
+}
+
+@keyframes heroGlow {
+ 0%,
+ 100% {
+ box-shadow: 0 30px 70px rgba(2, 6, 23, 0.48);
+ }
+ 50% {
+ box-shadow: 0 34px 80px rgba(2, 6, 23, 0.56);
+ }
+}
+
+@keyframes avatarFloat {
+ 0%,
+ 100% {
+ transform: translateY(0);
+ }
+ 50% {
+ transform: translateY(-3px);
+ }
+}
+
+@keyframes pulse {
+ 0%,
+ 100% {
+ opacity: 1;
+ transform: scale(1);
+ }
+ 50% {
+ opacity: 0.55;
+ transform: scale(0.82);
+ }
+}
+
+@keyframes floatUi {
+ 0%,
+ 100% {
+ transform: translateY(0);
+ }
+ 50% {
+ transform: translateY(10px);
+ }
+}
+
+@keyframes wave {
+ 0%,
+ 100% {
+ transform: scaleY(0.5);
+ }
+ 50% {
+ transform: scaleY(1);
+ }
+}
+
+@keyframes cardSweep {
+ 0%,
+ 100% {
+ opacity: 0;
+ transform: translateX(-18%) rotate(8deg);
+ }
+ 45% {
+ opacity: 1;
+ }
+ 55% {
+ opacity: 0.8;
+ }
+ 70% {
+ opacity: 0;
+ transform: translateX(8%) rotate(8deg);
+ }
+}
+
+@keyframes visualHalo {
+ 0%,
+ 100% {
+ transform: translate3d(0, 0, 0) scale(1);
+ opacity: 0.84;
+ }
+ 50% {
+ transform: translate3d(0, -8px, 0) scale(1.04);
+ opacity: 1;
+ }
+}
+
@media (max-width: 1200px) {
- .landing-content > .ant-row {
+ .landing-shell {
+ margin: -25px -20px 0;
+ padding: 0 20px 70px;
+ }
+
+ .landing-shell .landing-content {
padding-top: 96px;
+ flex-direction: column;
+ flex-wrap: wrap;
}
- .landing-content > .ant-row > .ant-col:first-child,
- .landing-content > .ant-row > .ant-col:last-child {
+ .landing-shell .landing-content > .ant-col:first-child,
+ .landing-shell .landing-content > .ant-col:last-child {
flex: 0 0 100%;
max-width: 100%;
}
- .landing-content .hero-visual {
- max-width: 720px;
+ .landing-shell .hero-visual {
+ width: min(100%, 500px);
+ height: 440px;
+ min-height: 440px;
margin-top: 20px;
+ transform: none;
+ }
+
+ .features-row-last {
+ max-width: 100%;
}
}
@media (max-width: 768px) {
- .landing-content > .ant-row {
+ .landing-shell .landing-content {
padding: 90px 20px 40px;
}
- .landing-content h1 {
+ .landing-shell .landing-content h1 {
font-size: clamp(2.8rem, 13vw, 4.4rem) !important;
}
- .landing-content .mb-30 {
+ .landing-shell .landing-content .mb-30 {
font-size: 16px;
}
- .landing-content .hero-visual {
- min-height: 320px;
+ .landing-shell .hero-visual {
+ width: min(100%, 500px);
+ height: 400px;
+ min-height: 400px;
}
- .landing-content .mockup-grid {
+ .landing-shell .mockup-grid {
grid-template-columns: 1fr;
}
.features {
padding: 0 20px 80px;
}
+
+ .features-row-last {
+ max-width: 100%;
+ }
+
+ .card-feat-last {
+ min-width: 0;
+ }
}
@keyframes landingFloat {
diff --git a/bbbeasy-frontend/src/components/LandingPage.tsx b/bbbeasy-frontend/src/components/LandingPage.tsx
index 4d1bb154..66cb22f3 100644
--- a/bbbeasy-frontend/src/components/LandingPage.tsx
+++ b/bbbeasy-frontend/src/components/LandingPage.tsx
@@ -16,12 +16,20 @@
* with BBBEasy; if not, see .
*/
-import React from 'react';
+import React, { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Trans, withTranslation } from 'react-i18next';
import { Row, Col, Typography, Avatar, Button } from 'antd';
-import { AppstoreAddOutlined, BgColorsOutlined, PlayCircleOutlined, ControlOutlined, ReadOutlined, AudioOutlined, SafetyOutlined } from '@ant-design/icons';
+import {
+ AppstoreAddOutlined,
+ BgColorsOutlined,
+ PlayCircleOutlined,
+ ControlOutlined,
+ AudioOutlined,
+ AudioMutedOutlined,
+ SecurityScanOutlined,
+} from '@ant-design/icons';
import DynamicIcon from './DynamicIcon';
import settingsService from 'services/settings.service';
@@ -30,12 +38,41 @@ const { Title, Paragraph } = Typography;
const LandingPage = () => {
const [platformName, setPlatformName] = React.useState('');
const navigate = useNavigate();
- settingsService.collect_settings().then((result) => {
- setPlatformName(result.data.platform_name);
- });
+ useEffect(() => {
+ settingsService.collect_settings().then((result) => {
+ setPlatformName(result.data.platform_name);
+ });
+ }, []);
+
+ const participants = [
+ {
+ initials: 'JD',
+ name: 'John Doe',
+ className: 'mock-blue',
+ micIcon: ,
+ },
+ {
+ initials: 'SM',
+ name: 'Sarah M.',
+ className: 'mock-orange',
+ micIcon: ,
+ },
+ {
+ initials: 'AK',
+ name: 'Alex K.',
+ className: 'mock-purple',
+ micIcon: ,
+ },
+ {
+ initials: 'ML',
+ name: 'Maria L.',
+ className: 'mock-green',
+ micIcon: ,
+ },
+ ];
return (
- <>
+
@@ -63,87 +100,90 @@ const LandingPage = () => {
-
+
-
- Classe virtuelle BBBEasy
-
-
128 Participants Connectés
+
Room: Math-Class-01
+
-
- JD
- John Doe
-
-
- SM
- Sarah M.
-
-
- AK
- Alex K.
-
-
- ML
- Maria L.
-
+ {participants.map((participant) => (
+
+
{participant.initials}
+
{participant.name}
+
{participant.micIcon}
+
+ ))}
-
-
- HD Audio
-
-
- End-to-end Encryption
-
+
+
+
+
+
+
+
+
+
+
HD Audio
+
+
+
+ End-to-end Encryption
+
Powerful Features
Everything you need to run seamless online sessions
-
-
- } className="ant-btn-primary bbbeasy-btn" />
-
-
-
-
-
- } className="ant-btn-primary bbbeasy-btn" />
-
-
-
-
-
- } className="ant-btn-primary bbbeasy-btn" />
-
-
-
-
-
- } className="ant-btn-primary bbbeasy-btn" />
-
-
-
-
-
- }
- className="ant-btn-primary bbbeasy-btn bbbeasy-icon"
- />
-
-
-
-
-
-
-
- >
+
+
+
+
+ } className="ant-btn-primary bbbeasy-btn" />
+
+
+
+
+
+ } className="ant-btn-primary bbbeasy-btn" />
+
+
+
+
+
+ } className="ant-btn-primary bbbeasy-btn" />
+
+
+
+
+
+ } className="ant-btn-primary bbbeasy-btn" />
+
+
+
+
+
+ }
+ className="ant-btn-primary bbbeasy-btn bbbeasy-icon"
+ />
+
+
+
+
+
+
+
+
+
);
};
From 16fbb4ed7f4e13fc09607828860e33645cf68978 Mon Sep 17 00:00:00 2001
From: talel
Date: Mon, 10 Aug 2026 17:06:53 +0100
Subject: [PATCH 07/17] grille
---
bbbeasy-frontend/src/App-webapp.css | 184 ++++++++++++++++------------
1 file changed, 106 insertions(+), 78 deletions(-)
diff --git a/bbbeasy-frontend/src/App-webapp.css b/bbbeasy-frontend/src/App-webapp.css
index 8d74f650..ed78a451 100644
--- a/bbbeasy-frontend/src/App-webapp.css
+++ b/bbbeasy-frontend/src/App-webapp.css
@@ -212,6 +212,7 @@
--bbbeasy-sider-width: 260px;
--bbbeasy-page-height: 100vh;
--bbbeasy-info-color: #1890ff;
+ --bbbeasy-landing-bg: linear-gradient(180deg, #050b1a 0%, #06162f 45%, #081f3e 100%);
}
body,
input,
@@ -441,49 +442,30 @@ fieldset {
.page-layout-content-rtl {
min-height: var(--bbbeasy-page-height) !important;
display: flex !important;
- background:
- radial-gradient(circle at 18% 0%, rgba(59, 130, 246, 0.2), transparent 24%),
- radial-gradient(circle at 88% 12%, rgba(34, 211, 238, 0.14), transparent 18%),
- linear-gradient(180deg, #06122e 0%, #07192c 32%, #091f3e 100%);
+ background: var(--bbbeasy-landing-bg);
}
.site-header {
z-index: 1;
position: relative;
overflow: hidden;
- background:
- linear-gradient(135deg, rgba(5, 12, 35, 0.98) 0%, rgba(7, 25, 44, 0.98) 45%, rgba(9, 31, 62, 0.98) 100%) !important;
- border-bottom: 1px solid rgba(96, 165, 250, 0.12);
- box-shadow: 0 10px 28px rgba(2, 6, 23, 0.22);
+ background-color: #050b1a !important;
+ background-image: none !important;
+ border-bottom: 0 !important;
+ box-shadow: none;
}
.page-layout-content .site-header,
.page-layout-content-rtl .site-header {
- background:
- linear-gradient(135deg, rgba(5, 12, 35, 0.98) 0%, rgba(7, 25, 44, 0.98) 45%, rgba(9, 31, 62, 0.98) 100%) !important;
- border-bottom: 1px solid rgba(96, 165, 250, 0.12);
- box-shadow: 0 10px 28px rgba(2, 6, 23, 0.22);
- backdrop-filter: blur(16px);
+ background-color: #050b1a !important;
+ background-image: none !important;
+ border-bottom: 0 !important;
+ box-shadow: none;
+ backdrop-filter: none;
}
.site-header::before {
- content: '';
- position: absolute;
- inset: 0;
- background:
- radial-gradient(circle at 14% 50%, rgba(34, 211, 238, 0.18), transparent 16%),
- radial-gradient(circle at 82% 18%, rgba(59, 130, 246, 0.18), transparent 16%);
- pointer-events: none;
- opacity: 0.9;
+ content: none;
}
.site-header::after {
- content: '';
- position: absolute;
- inset: 0;
- background-image:
- linear-gradient(rgba(96, 165, 250, 0.06) 1px, transparent 1px),
- linear-gradient(90deg, rgba(96, 165, 250, 0.06) 1px, transparent 1px);
- background-size: 44px 44px;
- opacity: 0.35;
- pointer-events: none;
- animation: headerGridShift 28s linear infinite;
+ content: none;
}
.site-header .lang-btn {
border-color: transparent;
@@ -636,17 +618,14 @@ fieldset {
flex: 1;
display: flex;
flex-direction: column;
- background:
- radial-gradient(circle at 18% 0%, rgba(59, 130, 246, 0.2), transparent 24%),
- radial-gradient(circle at 88% 12%, rgba(34, 211, 238, 0.14), transparent 18%),
- linear-gradient(180deg, #06122e 0%, #07192c 32%, #091f3e 100%) !important;
+ background: var(--bbbeasy-landing-bg) !important;
}
.page-layout-content .site-content,
.page-layout-content-rtl .site-content {
background: transparent !important;
}
.site-sider {
- background: #07192c !important;
+ background: var(--bbbeasy-landing-bg) !important;
flex: 0 0 var(--bbbeasy-sider-width) !important;
max-width: var(--bbbeasy-sider-width) !important;
min-width: var(--bbbeasy-sider-width) !important;
@@ -673,7 +652,7 @@ fieldset {
.site-sider .logo {
position: relative;
z-index: 1;
- background: #07192c;
+ background: transparent;
width: 240px;
margin: 10px;
margin-left: 24px;
@@ -751,17 +730,16 @@ fieldset {
display: flex;
justify-content: space-between;
align-items: center;
- background: linear-gradient(135deg, rgba(5, 12, 35, 0.98) 0%, rgba(7, 25, 44, 0.98) 45%, rgba(9, 31, 62, 0.98) 100%) !important;
- border-top: 1px solid rgba(96, 165, 250, 0.12);
- box-shadow: 0 -10px 28px rgba(2, 6, 23, 0.22);
+ background: var(--bbbeasy-landing-bg) !important;
+ border-top: 1px solid rgba(96, 165, 250, 0.08);
+ box-shadow: 0 -10px 28px rgba(2, 6, 23, 0.14);
}
.page-layout-content .site-footer,
.page-layout-content-rtl .site-footer,
.site-footer {
- background:
- linear-gradient(135deg, rgba(5, 12, 35, 0.98) 0%, rgba(7, 25, 44, 0.98) 45%, rgba(9, 31, 62, 0.98) 100%) !important;
- border-top: 1px solid rgba(96, 165, 250, 0.12);
- box-shadow: 0 -10px 28px rgba(2, 6, 23, 0.22);
+ background: var(--bbbeasy-landing-bg) !important;
+ border-top: 1px solid rgba(96, 165, 250, 0.08);
+ box-shadow: 0 -10px 28px rgba(2, 6, 23, 0.14);
}
.page-layout-content .site-footer .ant-typography,
.page-layout-content-rtl .site-footer .ant-typography {
@@ -784,46 +762,20 @@ fieldset {
padding: 0 20px 140px;
overflow: hidden;
isolation: isolate;
- background:
- radial-gradient(circle at 14% 10%, rgba(59, 130, 246, 0.42), transparent 18%),
- radial-gradient(circle at 84% 18%, rgba(34, 211, 238, 0.2), transparent 18%),
- radial-gradient(circle at 56% 52%, rgba(99, 102, 241, 0.18), transparent 24%),
- linear-gradient(180deg, #030812 0%, #071329 42%, #081d3d 100%);
- background-size: 150% 150%;
- animation: landingShellDrift 28s ease-in-out infinite;
+ background: var(--bbbeasy-landing-bg);
+ background-size: 100% 100%;
+ background-repeat: no-repeat;
}
.landing-shell::before {
content: '';
position: absolute;
inset: 0;
- background-image:
- linear-gradient(rgba(96, 165, 250, 0.1) 1px, transparent 1px),
- linear-gradient(90deg, rgba(96, 165, 250, 0.1) 1px, transparent 1px);
- background-size: 52px 52px;
- mask-image: radial-gradient(ellipse at center, black 30%, transparent 84%);
- animation: landingGridShift 24s linear infinite;
- pointer-events: none;
- opacity: 0.68;
+ content: none;
}
.landing-shell::after {
- content: '';
- position: absolute;
- inset: 0;
- background:
- radial-gradient(circle at 8% 18%, rgba(56, 189, 248, 0.34), transparent 5%),
- radial-gradient(circle at 14% 26%, rgba(96, 165, 250, 0.22), transparent 4%),
- radial-gradient(circle at 22% 12%, rgba(34, 211, 238, 0.26), transparent 4%),
- radial-gradient(circle at 38% 22%, rgba(96, 165, 250, 0.18), transparent 5%),
- radial-gradient(circle at 52% 14%, rgba(34, 211, 238, 0.24), transparent 4%),
- radial-gradient(circle at 68% 18%, rgba(96, 165, 250, 0.2), transparent 4%),
- radial-gradient(circle at 84% 26%, rgba(34, 211, 238, 0.22), transparent 4%),
- radial-gradient(circle at 90% 68%, rgba(59, 130, 246, 0.2), transparent 12%),
- radial-gradient(circle at 58% 86%, rgba(99, 102, 241, 0.18), transparent 16%);
- pointer-events: none;
- mix-blend-mode: screen;
- animation: landingSparkles 18s linear infinite;
+ content: none;
}
.landing-shell .landing-content {
@@ -959,9 +911,9 @@ fieldset {
width: 500px;
height: 440px;
min-height: 440px;
- animation: heroCardIn 1s ease both 0.12s;
+ animation: heroCardIn 1s ease both 0.12s, heroCardFloat 7s ease-in-out infinite 1s;
margin-left: 0;
- transform: translateX(-68px);
+ transform: translateX(-30px);
isolation: isolate;
overflow: visible;
}
@@ -982,6 +934,21 @@ fieldset {
pointer-events: none;
}
+.landing-shell .hero-visual::after {
+ content: '';
+ position: absolute;
+ inset: 18px 16px 16px 16px;
+ z-index: 0;
+ border-radius: 26px;
+ background:
+ radial-gradient(circle at 20% 20%, rgba(56, 189, 248, 0.16), transparent 18%),
+ radial-gradient(circle at 82% 18%, rgba(59, 130, 246, 0.14), transparent 16%),
+ linear-gradient(115deg, transparent 18%, rgba(255, 255, 255, 0.05) 30%, transparent 42%);
+ opacity: 0.75;
+ pointer-events: none;
+ animation: cardSweep 11s ease-in-out infinite;
+}
+
.landing-shell .mockup-card {
position: absolute;
inset: 0;
@@ -1003,7 +970,7 @@ fieldset {
flex-direction: column;
gap: 15px;
box-sizing: border-box;
- animation: landingFloat 6s ease-in-out infinite;
+ animation: landingFloat 6s ease-in-out infinite, heroGlow 8s ease-in-out infinite;
}
.landing-shell .mc-main::before {
@@ -1370,6 +1337,26 @@ fieldset {
}
}
+@keyframes landingShellBreath {
+ 0%,
+ 100% {
+ filter: saturate(1) brightness(1);
+ }
+ 50% {
+ filter: saturate(1.06) brightness(1.03);
+ }
+}
+
+@keyframes landingShellGlow {
+ 0%,
+ 100% {
+ filter: saturate(1) brightness(1);
+ }
+ 50% {
+ filter: saturate(1.08) brightness(1.04);
+ }
+}
+
@keyframes landingSparkles {
0% {
transform: translate3d(0, 0, 0);
@@ -1385,6 +1372,36 @@ fieldset {
}
}
+@keyframes landingSparkleFlow {
+ 0%,
+ 100% {
+ transform: translate3d(0, 0, 0);
+ }
+ 50% {
+ transform: translate3d(0, 6px, 0);
+ }
+}
+
+@keyframes landingGridPulse {
+ 0%,
+ 100% {
+ opacity: 0.58;
+ }
+ 50% {
+ opacity: 0.76;
+ }
+}
+
+@keyframes landingSparkleDrift {
+ 0%,
+ 100% {
+ transform: translate3d(0, 0, 0) scale(1);
+ }
+ 50% {
+ transform: translate3d(6px, -6px, 0) scale(1.02);
+ }
+}
+
@keyframes heroTextIn {
from {
opacity: 0;
@@ -1411,6 +1428,16 @@ fieldset {
}
}
+@keyframes heroCardFloat {
+ 0%,
+ 100% {
+ transform: translateX(-30px) translateY(0);
+ }
+ 50% {
+ transform: translateX(-30px) translateY(-8px);
+ }
+}
+
@keyframes cardRise {
from {
opacity: 0;
@@ -1581,6 +1608,7 @@ fieldset {
min-height: 440px;
margin-top: 20px;
transform: none;
+ animation: heroCardIn 1s ease both 0.12s;
}
.features-row-last {
From 52fd1c5f5210e2cb7235d719199177feb2b3e76c Mon Sep 17 00:00:00 2001
From: talel
Date: Mon, 10 Aug 2026 20:36:16 +0100
Subject: [PATCH 08/17] before co
---
bbbeasy-frontend/src/App-webapp.css | 780 ++++++++++++++----
.../src/components/LandingPage.tsx | 341 ++++++--
2 files changed, 883 insertions(+), 238 deletions(-)
diff --git a/bbbeasy-frontend/src/App-webapp.css b/bbbeasy-frontend/src/App-webapp.css
index ed78a451..67124938 100644
--- a/bbbeasy-frontend/src/App-webapp.css
+++ b/bbbeasy-frontend/src/App-webapp.css
@@ -805,8 +805,8 @@ fieldset {
}
.landing-shell .landing-content > .ant-col:last-child {
- flex: 0 0 500px;
- max-width: 500px;
+ flex: 0 0 640px;
+ max-width: 640px;
display: flex;
align-items: center;
justify-content: center;
@@ -908,285 +908,655 @@ fieldset {
.landing-shell .hero-visual {
position: relative;
- width: 500px;
- height: 440px;
- min-height: 440px;
- animation: heroCardIn 1s ease both 0.12s, heroCardFloat 7s ease-in-out infinite 1s;
- margin-left: 0;
- transform: translateX(-30px);
+ width: min(100%, 700px);
+ height: 520px;
+ min-height: 520px;
+ animation: heroCardIn 1s ease both 0.12s;
+ margin-left: auto;
+ margin-right: 0;
+ transform: translateX(0);
isolation: isolate;
overflow: visible;
}
.landing-shell .hero-visual::before {
- content: '';
- position: absolute;
- inset: -70px -90px -70px -90px;
- z-index: 0;
- background:
- radial-gradient(circle at 50% 35%, rgba(56, 189, 248, 0.24), transparent 26%),
- radial-gradient(circle at 82% 22%, rgba(59, 130, 246, 0.22), transparent 20%),
- radial-gradient(circle at 30% 78%, rgba(34, 211, 238, 0.12), transparent 24%);
- filter: blur(34px);
- opacity: 0.95;
- transform: translate3d(0, 0, 0);
- animation: visualHalo 8s ease-in-out infinite;
- pointer-events: none;
+ content: none;
}
.landing-shell .hero-visual::after {
- content: '';
- position: absolute;
- inset: 18px 16px 16px 16px;
- z-index: 0;
- border-radius: 26px;
- background:
- radial-gradient(circle at 20% 20%, rgba(56, 189, 248, 0.16), transparent 18%),
- radial-gradient(circle at 82% 18%, rgba(59, 130, 246, 0.14), transparent 16%),
- linear-gradient(115deg, transparent 18%, rgba(255, 255, 255, 0.05) 30%, transparent 42%);
- opacity: 0.75;
- pointer-events: none;
- animation: cardSweep 11s ease-in-out infinite;
-}
-
-.landing-shell .mockup-card {
- position: absolute;
- inset: 0;
- z-index: 1;
- border-radius: 20px;
- border: 1px solid rgba(96, 165, 250, 0.22);
- background: rgba(15, 26, 74, 0.45);
- backdrop-filter: blur(20px);
- -webkit-backdrop-filter: blur(20px);
- box-shadow: 0 30px 70px -20px rgba(2, 6, 23, 0.8);
- overflow: hidden;
+ content: none;
}
-.landing-shell .mc-main {
+.landing-shell .bbb-classroom-widget {
+ position: relative;
width: 100%;
height: 100%;
- padding: 20px;
+ animation: cardFloat 7s ease-in-out infinite;
display: flex;
flex-direction: column;
- gap: 15px;
- box-sizing: border-box;
- animation: landingFloat 6s ease-in-out infinite, heroGlow 8s ease-in-out infinite;
+ align-items: center;
+ justify-content: flex-start;
+ padding: 0;
}
-.landing-shell .mc-main::before {
+.landing-shell .classroom-frame {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ min-height: 470px;
+ padding: 18px 18px 16px;
+ border-radius: 28px;
+ border: 1px solid rgba(94, 139, 255, 0.22);
+ background:
+ radial-gradient(circle at 18% 16%, rgba(42, 124, 255, 0.18), transparent 24%),
+ radial-gradient(circle at 82% 84%, rgba(31, 179, 255, 0.14), transparent 30%),
+ linear-gradient(180deg, rgba(17, 29, 58, 0.94) 0%, rgba(10, 18, 40, 0.98) 100%);
+ box-shadow:
+ 0 34px 80px rgba(2, 6, 23, 0.6),
+ inset 0 1px 0 rgba(255, 255, 255, 0.05);
+ backdrop-filter: blur(16px);
+ -webkit-backdrop-filter: blur(16px);
+ overflow: hidden;
+}
+
+.landing-shell .classroom-frame::before {
content: '';
position: absolute;
inset: 0;
background:
- linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(34, 211, 238, 0.05));
+ linear-gradient(180deg, rgba(255, 255, 255, 0.03), transparent 20%),
+ linear-gradient(90deg, rgba(31, 179, 255, 0.05) 0%, transparent 18%, transparent 82%, rgba(31, 179, 255, 0.05) 100%);
pointer-events: none;
}
-.landing-shell .mockup-head {
+.landing-shell .classroom-topbar {
position: relative;
z-index: 1;
display: flex;
justify-content: space-between;
- gap: 16px;
align-items: center;
- margin-bottom: 18px;
+ gap: 16px;
+ margin-bottom: 16px;
flex-wrap: wrap;
}
-.landing-shell .mock-tag,
-.landing-shell .mock-count {
+.landing-shell .room-tag {
display: inline-flex;
align-items: center;
- gap: 8px;
- padding: 5px 10px;
- border-radius: 6px;
- border: 1px solid rgba(34, 211, 238, 0.2);
- background: rgba(34, 211, 238, 0.1);
- color: #22d3ee;
- font-family: 'JetBrains Mono', monospace;
+ gap: 9px;
+ min-height: 34px;
+ padding: 0 14px;
+ border-radius: 12px;
+ border: 1px solid rgba(80, 151, 255, 0.3);
+ background: rgba(19, 35, 73, 0.72);
+ color: #d9ebff;
font-size: 11px;
font-weight: 600;
- letter-spacing: 0.03em;
+ letter-spacing: 0.02em;
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
-.landing-shell .rec-indicator {
- display: flex;
+.landing-shell .audio-hd-tag {
+ display: inline-flex;
align-items: center;
- gap: 6px;
- color: #ff5a7a;
- font-size: 10px;
+ gap: 10px;
+ min-height: 40px;
+ padding: 0 14px 0 16px;
+ border-radius: 999px;
+ border: 1px solid rgba(80, 151, 255, 0.45);
+ background: linear-gradient(180deg, rgba(30, 52, 101, 0.96), rgba(20, 36, 77, 0.93));
+ color: #f8fbff;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 0.01em;
+ box-shadow:
+ 0 14px 26px rgba(4, 12, 28, 0.35),
+ inset 0 1px 0 rgba(255, 255, 255, 0.08);
+}
+
+.landing-shell .room-tag svg,
+.landing-shell .audio-hd-tag svg,
+.landing-shell .mute-icn svg,
+.landing-shell .expand-icn svg,
+.landing-shell .hand-badge svg,
+.landing-shell .act-btn svg,
+.landing-shell .media-circle svg {
+ width: 14px;
+ height: 14px;
+}
+
+.landing-shell .room-tag-prefix {
+ opacity: 0.7;
font-family: 'JetBrains Mono', monospace;
- font-weight: 600;
}
-.landing-shell .rec-dot {
- width: 10px;
- height: 10px;
- border-radius: 50%;
- background: #ff5a7a;
- box-shadow: 0 0 10px #ff5a7a;
- animation: pulse 1s infinite;
+.landing-shell .audio-hd-tag {
+ border-color: rgba(70, 135, 255, 0.72);
+}
+
+.landing-shell .audio-bars {
+ display: inline-flex;
+ align-items: center;
+ gap: 3px;
+ height: 16px;
+}
+
+.landing-shell .audio-bars span {
+ width: 3px;
+ border-radius: 999px;
+ background: linear-gradient(180deg, #5ee7ff 0%, #19d1ff 100%);
+ animation: audioWave 1.2s ease-in-out infinite;
+ transform-origin: center bottom;
+}
+
+.landing-shell .audio-bars span:nth-child(1) {
+ height: 6px;
+ animation-delay: 0s;
}
-.landing-shell .mockup-grid {
+.landing-shell .audio-bars span:nth-child(2) {
+ height: 11px;
+ animation-delay: 0.12s;
+}
+
+.landing-shell .audio-bars span:nth-child(3) {
+ height: 8px;
+ animation-delay: 0.24s;
+}
+
+.landing-shell .classroom-body {
position: relative;
z-index: 1;
+ width: 100%;
display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- grid-template-rows: repeat(2, minmax(0, 1fr));
+ grid-template-columns: 174px minmax(0, 1fr) 132px;
gap: 12px;
- flex: 1;
+ align-items: stretch;
+ height: calc(100% - 52px);
}
-.landing-shell .participant {
- min-height: 0;
- border-radius: 12px;
- background: rgba(7, 13, 36, 0.6);
- border: 1px solid rgba(96, 165, 250, 0.15);
+.landing-shell .classroom-left,
+.landing-shell .classroom-center,
+.landing-shell .classroom-right {
+ min-height: 100%;
+}
+
+.landing-shell .classroom-left {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.landing-shell .classroom-left > div {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.landing-shell .sec-title {
+ margin: 0 0 2px;
+ color: rgba(223, 233, 255, 0.58);
+ font-size: 11px;
+ font-weight: 800;
+ text-transform: uppercase;
+ letter-spacing: 0.18em;
+ text-align: center;
+}
+
+.landing-shell .classroom-center {
display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.landing-shell .classroom-right {
+ background: rgba(11, 15, 28, 0.45);
+ border: 1px solid rgba(255, 255, 255, 0.06);
+ border-radius: 18px;
+ padding: 14px 10px;
+ display: flex;
+ flex-direction: column;
align-items: center;
- justify-content: center;
+ justify-content: space-between;
+ gap: 12px;
+}
+
+.landing-shell .video-tile,
+.landing-shell .grid-tile {
position: relative;
+ border-radius: 16px;
+ background:
+ radial-gradient(circle at 50% 38%, rgba(20, 48, 104, 0.18), transparent 45%),
+ linear-gradient(180deg, rgba(24, 38, 73, 0.78) 0%, rgba(12, 22, 49, 0.96) 100%);
+ border: 1px solid rgba(69, 111, 200, 0.16);
overflow: hidden;
+ box-shadow:
+ inset 0 1px 0 rgba(255, 255, 255, 0.03),
+ 0 10px 24px rgba(2, 6, 23, 0.25);
+ min-height: 150px;
}
-.landing-shell .participant::before {
- content: '';
- position: absolute;
- inset: 0;
- background: linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(34, 211, 238, 0.05));
+.landing-shell .instructor-tile {
+ min-height: 132px;
+ background:
+ radial-gradient(circle at 50% 45%, rgba(20, 48, 104, 0.2), transparent 45%),
+ linear-gradient(180deg, rgba(24, 38, 73, 0.76) 0%, rgba(12, 22, 49, 0.94) 100%);
}
-.landing-shell .avatar {
- position: relative;
- z-index: 1;
- width: 45px;
- height: 45px;
- border-radius: 50%;
+.landing-shell .podium-tile {
+ min-height: 97px;
+}
+
+.landing-shell .grid-tile {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.landing-shell .tile-avatar {
+ border-radius: 999px;
display: grid;
place-items: center;
- font-weight: 700;
- color: #050a1f;
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
- animation: avatarFloat 4.8s ease-in-out infinite;
+ color: #09101f;
+ font-weight: 800;
+ box-shadow: 0 10px 24px rgba(3, 8, 20, 0.34);
+ z-index: 1;
+ pointer-events: none;
}
-.landing-shell .mock-blue {
- background: linear-gradient(135deg, #3b82f6, #22d3ee);
+.landing-shell .avatar-inst {
+ width: 58px;
+ height: 58px;
+ font-size: 24px;
+ background: linear-gradient(135deg, #f43f5e 0%, #be123c 100%);
}
-.landing-shell .mock-orange {
- background: linear-gradient(135deg, #fb923c, #f97316);
+.landing-shell .avatar-podium-1,
+.landing-shell .avatar-podium-2 {
+ width: 44px;
+ height: 44px;
+ font-size: 18px;
}
-.landing-shell .mock-purple {
- background: linear-gradient(135deg, #a855f7, #ec4899);
+.landing-shell .avatar-podium-1 {
+ background: linear-gradient(135deg, #f59e0b 0%, #b45309 100%);
}
-.landing-shell .mock-green {
- background: linear-gradient(135deg, #2dd4bf, #22c55e);
+.landing-shell .avatar-podium-2 {
+ background: linear-gradient(135deg, #10b981 0%, #047857 100%);
}
-.landing-shell .name-tag {
+.landing-shell .grid-avatar {
position: absolute;
- left: 8px;
- bottom: 8px;
+ top: 50%;
+ left: 50%;
+ display: grid;
+ place-items: center;
+ transform: translate(-50%, -50%);
+ font-weight: 800;
+ line-height: 1;
+}
+
+.landing-shell .grid-avatar {
+ width: 52px;
+ height: 52px;
+ border-radius: 999px;
+ font-size: 16px;
+ color: #09101f;
+ box-shadow: 0 10px 24px rgba(3, 8, 20, 0.34);
z-index: 1;
- padding: 3px 8px;
- border-radius: 4px;
- background: rgba(0, 0, 0, 0.6);
+ pointer-events: none;
+}
+
+.landing-shell .grid-avatar-ta {
+ background: linear-gradient(135deg, #6f7bf7 0%, #4338ca 100%);
color: #fff;
- font-size: 10px;
}
-.landing-shell .mic-icon {
- position: relative;
- z-index: 1;
+.landing-shell .grid-avatar-a {
+ background: linear-gradient(135deg, #3db5ff 0%, #2f7cff 100%);
+}
+
+.landing-shell .grid-avatar-b {
+ background: linear-gradient(135deg, #ff8c26 0%, #ff5f18 100%);
+}
+
+.landing-shell .grid-avatar-c {
+ background: linear-gradient(135deg, #dc5fff 0%, #b94cff 100%);
+}
+
+.landing-shell .grid-avatar-j {
+ background: linear-gradient(135deg, #37dfd6 0%, #2fd08a 100%);
+}
+
+.landing-shell .hand-badge,
+.landing-shell .tile-float {
position: absolute;
+ top: 11px;
+ right: 11px;
+ width: 18px;
+ height: 18px;
+ border-radius: 999px;
+ background: rgba(6, 10, 20, 0.76);
+ color: rgba(237, 244, 255, 0.92);
+ display: grid;
+ place-items: center;
+ box-shadow: 0 10px 18px rgba(2, 6, 23, 0.2);
+ z-index: 2;
+ font-size: 0;
+}
+
+.landing-shell .hand-badge {
top: 8px;
right: 8px;
- font-size: 9px;
- width: 20px;
- height: 20px;
- border-radius: 50%;
- background: rgba(0, 0, 0, 0.4);
+ width: 24px;
+ height: 24px;
+ border-radius: 8px;
+ background: linear-gradient(135deg, rgba(245, 158, 11, 0.96), rgba(245, 158, 11, 0.74));
+ box-shadow: 0 6px 12px rgba(245, 158, 11, 0.28);
+ animation: bounceMini 2s ease-in-out infinite;
+}
+
+.landing-shell .hand-badge svg {
+ width: 13px !important;
+ height: 13px !important;
+ color: #fff;
+}
+
+.landing-shell .tile-float.pink {
+ background: rgba(178, 76, 123, 0.82);
+ animation: speakPulse 2.8s ease-in-out infinite;
+}
+
+.landing-shell .tile-float svg {
+ width: 11px !important;
+ height: 11px !important;
+ display: block;
+ flex-shrink: 0;
+}
+
+.landing-shell .expand-icn {
+ position: absolute;
+ right: 10px;
+ bottom: 8px;
+ width: 14px;
+ height: 14px;
+ color: rgba(255, 255, 255, 0.46);
display: grid;
place-items: center;
- color: #fff;
}
-.landing-shell .mic-off {
- background: rgba(255, 90, 122, 0.6);
+.landing-shell .expand-icn:hover {
+ color: rgba(255, 255, 255, 0.9);
}
-.landing-shell .floating-ui {
+.landing-shell .tile-footer {
position: absolute;
- inset: auto;
- z-index: 2;
- padding: 12px 18px;
- border-radius: 14px;
+ left: 12px;
+ right: 12px;
+ bottom: 12px;
display: flex;
align-items: center;
+ justify-content: flex-start;
+ gap: 6px;
+}
+
+.landing-shell .mute-icn {
+ display: grid;
+ place-items: center;
+ color: #fff;
+}
+
+.landing-shell .mute-icn svg {
+ width: 12px !important;
+ height: 12px !important;
+}
+
+.landing-shell .user-lbl {
+ padding: 3px 7px;
+ border-radius: 6px;
+ background: rgba(4, 9, 20, 0.82);
+ color: rgba(237, 244, 255, 0.96);
+ font-size: 9px;
+ font-weight: 600;
+}
+
+.landing-shell .tab-bar {
+ display: flex;
+ gap: 6px;
+ padding: 6px;
+ border-radius: 12px;
+ border: 1px solid rgba(255, 255, 255, 0.05);
+ background: rgba(11, 15, 28, 0.82);
+}
+
+.landing-shell .tab-btn {
+ flex: 1;
+ min-height: 42px;
+ padding: 8px 10px;
+ border: none;
+ border-radius: 10px;
+ background: transparent;
+ color: var(--text-muted);
+ font-size: 11px;
+ font-weight: 700;
+ text-align: center;
+ cursor: pointer;
+ transition: all 0.25s ease;
+}
+
+.landing-shell .tab-btn:hover {
+ color: var(--text-main);
+}
+
+.landing-shell .tab-btn.active {
+ color: #fff;
+ background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
+ box-shadow: 0 8px 18px rgba(59, 130, 246, 0.34);
+}
+
+.landing-shell .table-grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ grid-template-rows: repeat(2, 1fr);
gap: 10px;
- font-size: 13px;
- font-weight: 500;
+ flex: 1;
+ min-height: 0;
+}
+
+.landing-shell .grid-tile {
+ min-height: 144px;
+}
+
+.landing-shell .grid-tile:nth-child(1) {
+ min-height: 148px;
+}
+
+.landing-shell .grid-tile .grid-avatar {
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+.landing-shell .grid-tile .tile-footer {
+ left: 10px;
+ right: 10px;
+ bottom: 10px;
+}
+
+.landing-shell .add-tile {
+ border: 2px dashed rgba(255, 255, 255, 0.1);
+ background: transparent;
+}
+
+.landing-shell .add-tile:hover {
+ border-color: rgba(255, 255, 255, 0.3);
+}
+
+.landing-shell .add-tile svg {
+ width: 22px;
+ height: 22px;
+ color: rgba(255, 255, 255, 0.35);
+}
+
+.landing-shell .classroom-right {
+ background: rgba(11, 15, 28, 0.5);
+ border: 1px solid rgba(255, 255, 255, 0.06);
+ border-radius: 18px;
+ padding: 12px 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+}
+
+.landing-shell .raise-hand-main {
+ width: 54px;
+ height: 54px;
+ border-radius: 999px;
+ border: 1px solid rgba(245, 158, 11, 0.45);
+ background: linear-gradient(135deg, rgba(245, 158, 11, 0.18), rgba(245, 158, 11, 0.05));
+ display: grid;
+ place-items: center;
+ color: var(--accent-yellow);
+ cursor: pointer;
+ transition: transform 0.25s ease, box-shadow 0.25s ease, background 0.25s ease;
+ box-shadow: 0 8px 15px rgba(0, 0, 0, 0.18);
+}
+
+.landing-shell .raise-hand-main:hover {
+ transform: translateY(-2px) scale(1.04);
+ background: linear-gradient(135deg, rgba(245, 158, 11, 0.28), rgba(245, 158, 11, 0.08));
+ box-shadow: 0 10px 22px rgba(245, 158, 11, 0.25);
+}
+
+.landing-shell .raise-hand-main svg {
+ width: 24px;
+ height: 24px;
+}
+
+.landing-shell .quick-actions-grid {
+ width: 100%;
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 8px;
+}
+
+.landing-shell .act-btn {
+ height: 34px;
+ border-radius: 8px;
+ border: 1px solid rgba(255, 255, 255, 0.06);
+ background: rgba(255, 255, 255, 0.03);
+ color: #cbd5e1;
+ display: grid;
+ place-items: center;
+ cursor: pointer;
+ transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
+}
+
+.landing-shell .act-btn:hover {
+ background: rgba(255, 255, 255, 0.08);
+ border-color: rgba(255, 255, 255, 0.14);
color: #fff;
- background: rgba(15, 26, 74, 0.9);
- box-shadow: 0 10px 30px rgba(59, 130, 246, 0.3);
}
-.landing-shell .fu-1 {
- top: -25px;
- right: 20px;
- border: 1px solid #60a5fa;
- animation: floatUi 5s ease-in-out infinite;
+.landing-shell .act-btn svg {
+ width: 15px;
+ height: 15px;
}
-.landing-shell .fu-2 {
- bottom: -20px;
- left: 20px;
- border: 1px solid #22d3ee;
- box-shadow: 0 10px 30px rgba(34, 211, 238, 0.3);
- animation: floatUi 5s ease-in-out infinite reverse;
+.landing-shell .room-mode-box {
+ width: calc(100% + 20px);
+ margin: 0 -10px;
+ padding: 10px 0;
+ text-align: center;
+ background: rgba(0, 0, 0, 0.2);
+ border-top: 1px solid rgba(255, 255, 255, 0.05);
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
+}
+
+.landing-shell .mode-title {
+ color: var(--text-main);
+ font-size: 10px;
+ font-weight: 700;
+}
+
+.landing-shell .mode-sub {
+ margin-top: 2px;
+ color: var(--text-muted);
+ font-size: 9px;
}
-.landing-shell .wave-bars {
+.landing-shell .bottom-media-bar {
+ width: 100%;
display: flex;
- gap: 2px;
align-items: center;
- height: 16px;
+ justify-content: center;
+ gap: 8px;
}
-.landing-shell .wave-bars span {
- width: 3px;
- background: #22d3ee;
- border-radius: 2px;
- animation: wave 1s ease-in-out infinite;
+.landing-shell .media-circle {
+ width: 32px;
+ height: 32px;
+ border-radius: 999px;
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ background: rgba(255, 255, 255, 0.05);
+ display: grid;
+ place-items: center;
+ color: #fff;
+ cursor: pointer;
+ transition: transform 0.2s ease, background 0.2s ease;
}
-.landing-shell .wave-bars span:nth-child(1) {
- height: 40%;
- animation-delay: 0s;
+.landing-shell .media-circle:hover {
+ transform: translateY(-1px);
+ background: rgba(255, 255, 255, 0.1);
}
-.landing-shell .wave-bars span:nth-child(2) {
- height: 80%;
- animation-delay: 0.1s;
+.landing-shell .media-circle.off {
+ border-color: rgba(239, 68, 68, 0.3);
+ background: rgba(239, 68, 68, 0.05);
}
-.landing-shell .wave-bars span:nth-child(3) {
- height: 60%;
- animation-delay: 0.2s;
+.landing-shell .media-circle.off svg {
+ color: var(--accent-red);
}
-.landing-shell .wave-bars span:nth-child(4) {
- height: 100%;
- animation-delay: 0.3s;
+.landing-shell .media-circle.main-speaker {
+ width: 38px;
+ height: 38px;
+ background: rgba(255, 255, 255, 0.12);
}
-.landing-shell .wave-bars span:nth-child(5) {
- height: 50%;
- animation-delay: 0.4s;
+.landing-shell .media-circle.main-speaker svg {
+ width: 16px;
+ height: 16px;
+}
+
+.landing-shell .encryption-pill {
+ position: absolute;
+ left: 22px;
+ bottom: -16px;
+ z-index: 2;
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+ min-height: 42px;
+ padding: 0 16px;
+ border-radius: 14px;
+ border: 1px solid rgba(46, 209, 255, 0.45);
+ background: rgba(9, 20, 44, 0.95);
+ color: #e8f7ff;
+ box-shadow:
+ 0 16px 26px rgba(3, 8, 20, 0.28),
+ 0 0 18px rgba(22, 188, 255, 0.16);
+}
+
+.landing-shell .encryption-pill svg {
+ width: 14px;
+ height: 14px;
+ color: #38d8ff;
}
.features {
@@ -1512,6 +1882,40 @@ fieldset {
}
}
+@keyframes cardFloat {
+ 0%,
+ 100% {
+ transform: translateY(0);
+ }
+ 50% {
+ transform: translateY(-10px);
+ }
+}
+
+@keyframes audioWave {
+ 0%,
+ 100% {
+ transform: scaleY(0.55);
+ opacity: 0.75;
+ }
+ 50% {
+ transform: scaleY(1.12);
+ opacity: 1;
+ }
+}
+
+@keyframes speakPulse {
+ 0%,
+ 100% {
+ transform: scale(1);
+ opacity: 0.92;
+ }
+ 50% {
+ transform: scale(1.08);
+ opacity: 1;
+ }
+}
+
@keyframes avatarFloat {
0%,
100% {
@@ -1603,9 +2007,9 @@ fieldset {
}
.landing-shell .hero-visual {
- width: min(100%, 500px);
- height: 440px;
- min-height: 440px;
+ width: min(100%, 760px);
+ height: 500px;
+ min-height: 500px;
margin-top: 20px;
transform: none;
animation: heroCardIn 1s ease both 0.12s;
@@ -1630,13 +2034,29 @@ fieldset {
}
.landing-shell .hero-visual {
- width: min(100%, 500px);
- height: 400px;
- min-height: 400px;
+ width: min(100%, 760px);
+ height: auto;
+ min-height: 0;
}
- .landing-shell .mockup-grid {
+ .landing-shell .classroom-body {
grid-template-columns: 1fr;
+ height: auto;
+ }
+
+ .landing-shell .classroom-left {
+ flex-direction: row;
+ overflow-x: auto;
+ padding-bottom: 2px;
+ }
+
+ .landing-shell .classroom-left > div {
+ min-width: 170px;
+ }
+
+ .landing-shell .table-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ grid-template-rows: repeat(3, minmax(0, 118px));
}
.features {
diff --git a/bbbeasy-frontend/src/components/LandingPage.tsx b/bbbeasy-frontend/src/components/LandingPage.tsx
index 66cb22f3..50d6b3da 100644
--- a/bbbeasy-frontend/src/components/LandingPage.tsx
+++ b/bbbeasy-frontend/src/components/LandingPage.tsx
@@ -26,17 +26,110 @@ import {
BgColorsOutlined,
PlayCircleOutlined,
ControlOutlined,
- AudioOutlined,
- AudioMutedOutlined,
- SecurityScanOutlined,
} from '@ant-design/icons';
import DynamicIcon from './DynamicIcon';
import settingsService from 'services/settings.service';
const { Title, Paragraph } = Typography;
+const RoomIcon = () => (
+
+);
+
+const MicOffIcon = () => (
+
+);
+
+const ExpandIcon = () => (
+
+);
+
+const HandIcon = () => (
+
+);
+
+const ShieldIcon = () => (
+
+);
+
+const CameraOffIcon = () => (
+
+);
+
+const SpeakerIcon = () => (
+
+);
+
+const ActionEmojiIcon = () => (
+
+);
+
+const ActionFullscreenIcon = () => (
+
+);
+
+const ActionQuestionIcon = () => (
+
+);
+
+const ActionChatIcon = () => (
+
+);
+
+const ActionCalendarIcon = () => (
+
+);
+
+const ActionMoreIcon = () => (
+
+);
+
const LandingPage = () => {
const [platformName, setPlatformName] = React.useState('');
+ const [activeTab, setActiveTab] = React.useState('My Table');
const navigate = useNavigate();
useEffect(() => {
settingsService.collect_settings().then((result) => {
@@ -44,33 +137,6 @@ const LandingPage = () => {
});
}, []);
- const participants = [
- {
- initials: 'JD',
- name: 'John Doe',
- className: 'mock-blue',
- micIcon: ,
- },
- {
- initials: 'SM',
- name: 'Sarah M.',
- className: 'mock-orange',
- micIcon: ,
- },
- {
- initials: 'AK',
- name: 'Alex K.',
- className: 'mock-purple',
- micIcon: ,
- },
- {
- initials: 'ML',
- name: 'Maria L.',
- className: 'mock-green',
- micIcon: ,
- },
- ];
-
return (
@@ -100,38 +166,197 @@ const LandingPage = () => {
-
-
-
Room: Math-Class-01
-
-
- REC
+
+
+
+
+
+ Room:
+ Math-Class-01
+
+
+
+
+
+
+
+
+ HD Audio
+
-
-
- {participants.map((participant) => (
-
-
{participant.initials}
-
{participant.name}
-
{participant.micIcon}
+
+
+
+
+
Instructors
+
+
👩🏫
+
+ Instructor (She-Her)
+
+
+
+
+
+
+
+
+
+
+
+
+ {['My Table', 'Class share', "Instructor's video"].map((tab) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
B
+
+
+
+
+
Brandon (guest)
+
+
+
+
+
+
+
+
+
+
+
- ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Room mode
+
Audio only
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+ End-to-end Encryption
-
HD Audio
-
-
-
- End-to-end Encryption
From 733cc9c7cde297f5ac8e53e420115519794625fd Mon Sep 17 00:00:00 2001
From: talel
Date: Tue, 11 Aug 2026 16:31:36 +0100
Subject: [PATCH 09/17] front_imp
---
bbbeasy-frontend/src/App-webapp.css | 242 +++++++++++++++++-
.../src/components/auth/Login.tsx | 43 +++-
.../src/components/auth/Register.tsx | 239 ++++++++++-------
bbbeasy-frontend/src/locale/ar-TN.json | 13 +
bbbeasy-frontend/src/locale/en-US.json | 13 +
bbbeasy-frontend/src/locale/fr-FR.json | 13 +
6 files changed, 463 insertions(+), 100 deletions(-)
diff --git a/bbbeasy-frontend/src/App-webapp.css b/bbbeasy-frontend/src/App-webapp.css
index 67124938..16eac51a 100644
--- a/bbbeasy-frontend/src/App-webapp.css
+++ b/bbbeasy-frontend/src/App-webapp.css
@@ -2082,11 +2082,171 @@ fieldset {
}
}
/********************LOGIN/REGISTER********************/
+.login-page {
+ position: relative;
+ min-height: calc(100vh - 80px);
+ padding: clamp(44px, 7vh, 80px) clamp(24px, 4vw, 68px) 72px;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: clamp(32px, 4vw, 72px);
+ overflow: hidden;
+ background: var(--bbbeasy-landing-bg);
+ background-size: 100% 100%;
+ background-repeat: no-repeat;
+}
+
+.login-page::before {
+ content: none;
+}
+
+.login-page::after {
+ content: none;
+}
+
+.login-page.ant-row {
+ position: relative;
+ z-index: 1;
+ width: 100%;
+ min-height: calc(100vh - 200px);
+ justify-content: space-between;
+ align-items: flex-start;
+}
+
+.login-page .login-hero-column {
+ display: flex;
+ align-items: center;
+ min-height: calc(100vh - 200px);
+ padding: 0 !important;
+ flex: 1 1 0 !important;
+ min-width: 0;
+}
+
+.login-page .login-hero {
+ max-width: 640px;
+ padding-left: clamp(24px, 4vw, 76px);
+ padding-right: clamp(8px, 2vw, 24px);
+ padding-top: clamp(20px, 5vh, 72px);
+ animation: loginHeroFloat 8s ease-in-out infinite alternate;
+}
+
+.login-page .login-hero-tag {
+ display: inline-flex;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 28px;
+ color: #8ab9ff;
+ font-size: 13px;
+ font-weight: 700;
+ letter-spacing: 0.35em;
+ text-transform: uppercase;
+}
+
+.login-page .login-hero-tag-line {
+ width: 34px;
+ height: 3px;
+ border-radius: 999px;
+ background: #f6b51b;
+ box-shadow: 0 0 18px rgba(246, 181, 27, 0.35);
+}
+
+.login-page .login-hero-title {
+ margin: 0 !important;
+ line-height: 0.96 !important;
+ font-weight: 800 !important;
+ color: #f8fbff !important;
+ letter-spacing: -0.03em;
+}
+
+.login-page .login-hero-title .login-hero-title-main,
+.login-page .login-hero-title .login-hero-title-accent {
+ display: block;
+}
+
+.login-page .login-hero-title .login-hero-title-main {
+ color: #f8fbff;
+}
+
+.login-page .login-hero-title .login-hero-title-accent {
+ color: #f6b51b;
+ margin-top: 6px;
+}
+
+.login-page .login-hero-description {
+ margin-top: 18px !important;
+ margin-bottom: 34px !important;
+ font-size: 18px;
+ line-height: 1.7;
+ color: rgba(191, 210, 248, 0.9) !important;
+ max-width: 580px;
+}
+
+.login-page .login-hero-points {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 28px;
+ margin-top: 14px;
+}
+
+.login-page .login-hero-point {
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+ color: #dbeafe;
+ font-size: 14px;
+ font-weight: 600;
+}
+
+.login-page .login-hero-point-icon {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ border: 1px solid rgba(245, 181, 27, 0.45);
+ color: #f6b51b;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 14px;
+ line-height: 1;
+ box-shadow: 0 0 12px rgba(246, 181, 27, 0.14);
+ flex-shrink: 0;
+}
+
+.login-page .section-top {
+ padding: 0 !important;
+ margin-left: auto !important;
+ margin-right: clamp(12px, 4vw, 72px) !important;
+ margin-top: clamp(-8px, 1vh, 8px) !important;
+ flex: 0 0 500px !important;
+ max-width: 500px !important;
+ width: 500px !important;
+}
+
+.login-page .login-form-column {
+ display: flex;
+ justify-content: flex-end;
+ align-items: flex-start;
+ min-height: calc(100vh - 200px);
+}
+
+.login-page .login-form-column .form-content {
+ margin-top: clamp(-12px, -1vh, 0px);
+ transform: translateY(-18px);
+}
+
.section-top {
padding: 50px 0 !important;
}
.form-content {
- padding: 0 30px !important;
+ padding: 34px 34px 30px !important;
+ border: 1px solid rgba(148, 163, 184, 0.18) !important;
+ border-radius: 28px !important;
+ box-shadow:
+ 0 32px 70px rgba(2, 6, 23, 0.38),
+ 0 0 0 1px rgba(255, 255, 255, 0.04) inset !important;
+ background: rgba(255, 255, 255, 0.97) !important;
+ backdrop-filter: blur(12px);
+ -webkit-backdrop-filter: blur(12px);
}
.form-header {
margin-bottom: 40px !important;
@@ -2106,7 +2266,85 @@ fieldset {
margin-bottom: 20px !important;
}
.form-footer .ant-typography {
- color: gray !important;
+ color: #5b667a !important;
+}
+
+@media (max-width: 992px) {
+ .login-page {
+ justify-content: center;
+ padding-inline: 20px;
+ gap: 28px;
+ }
+
+ .login-page .login-hero-column,
+ .login-page .section-top {
+ flex: 1 1 100% !important;
+ max-width: 100% !important;
+ width: 100% !important;
+ margin-right: 0 !important;
+ }
+
+ .login-page .login-hero-column {
+ min-height: auto;
+ justify-content: center;
+ }
+
+ .login-page .login-hero {
+ max-width: 720px;
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .login-page .login-form-column {
+ justify-content: center;
+ min-height: auto;
+ }
+
+ .login-page .login-form-column .form-content {
+ transform: none;
+ margin-top: 0;
+ }
+}
+
+@media (max-width: 576px) {
+ .login-page {
+ padding-top: 36px;
+ padding-bottom: 56px;
+ }
+
+ .login-page .login-hero {
+ padding-top: 0;
+ }
+
+ .login-page .login-hero-title {
+ font-size: 44px !important;
+ }
+
+ .login-page .login-hero-description {
+ font-size: 16px;
+ }
+
+ .login-page .login-hero-points {
+ gap: 16px;
+ }
+
+ .login-page .section-top {
+ max-width: 100% !important;
+ }
+
+ .form-content {
+ padding: 28px 20px 24px !important;
+ border-radius: 22px !important;
+ }
+}
+
+@keyframes loginHeroFloat {
+ 0% {
+ transform: translateY(0);
+ }
+ 100% {
+ transform: translateY(-10px);
+ }
}
/*******************ROOMS*********************/
.home-guide {
diff --git a/bbbeasy-frontend/src/components/auth/Login.tsx b/bbbeasy-frontend/src/components/auth/Login.tsx
index 7bf70fef..eed370ba 100644
--- a/bbbeasy-frontend/src/components/auth/Login.tsx
+++ b/bbbeasy-frontend/src/components/auth/Login.tsx
@@ -119,8 +119,47 @@ const Login: React.FC = () => {
};
return (
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ✓
+
+
+
+
+
+ ✓
+
+
+
+
+
+
+
+
+
{
confirmPassword: '',
agreement: false,
};
- settingsService
- .collect_settings()
- .then((response) => {
- console.log(response.data);
- const settings: SettingsType = response.data;
- setLogo(settings.logo);
- })
- .catch((error) => {
- console.log(error);
- });
+ React.useEffect(() => {
+ settingsService
+ .collect_settings()
+ .then((response) => {
+ const settings: SettingsType = response.data;
+ setLogo(settings.logo);
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ }, []);
+
const navigate = useNavigate();
const handleRegistration = (formValue: formType) => {
@@ -75,93 +77,138 @@ const Register = () => {
};
return (
-
- {successful ? (
-
- }
- subTitle={}
- extra={
-
- }
- />
-
- ) : (
-
-
-
-
-
-
-
-
-
- {message && (
- EN_US[elem] == message)} />
- }
- showIcon
- />
- )}
-
-
- value
- ? Promise.resolve()
- : Promise.reject(new Error(t('accept-agreement'))),
- },
- ]}
- >
-
-
-
- {' '}
-
- {' '}
-
-
- {' '}
-
-
-
-
-
-
-
-
-
-
- )}
+ }
+ />
+ ) : (
+ <>
+
+
+
+
+
+
+
+ {message && (
+ EN_US[elem] == message)} />
+ }
+ showIcon
+ />
+ )}
+
+
+ value
+ ? Promise.resolve()
+ : Promise.reject(new Error(t('accept-agreement'))),
+ },
+ ]}
+ >
+
+
+
+ {' '}
+
+ {' '}
+
+
+ {' '}
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+
);
};
diff --git a/bbbeasy-frontend/src/locale/ar-TN.json b/bbbeasy-frontend/src/locale/ar-TN.json
index 83e00058..a7bdfe6e 100644
--- a/bbbeasy-frontend/src/locale/ar-TN.json
+++ b/bbbeasy-frontend/src/locale/ar-TN.json
@@ -66,6 +66,19 @@
"username-already-exist": "اسم المستخدم موجود مسبقا",
"email-already-exist": "البريد الإلكتروني موجود مسبقا",
"welcome-app": "مرحبا بعودتك",
+ "login-hero-tag": "مساحة عمل احترافية",
+ "login-hero-title-main": "كل ما تحتاجه.",
+ "login-hero-title-accent": "بكل بساطة.",
+ "login-hero-description": "مرحبًا بك في BBBEasy. سجّل الدخول للمتابعة إلى مساحة عملك وإدارة نشاطك في تجربة آمنة وواضحة وفعّالة.",
+ "login-hero-point-1": "وصول آمن",
+ "login-hero-point-2": "سير عمل بسيط",
+ "sign-up-hero-tag": "ابدأ الآن",
+ "sign-up-hero-title-main": "أنشئ",
+ "sign-up-hero-title-accent": "حساب BBBEasy",
+ "sign-up-hero-description": "أنشئ حسابك وابدأ باستخدام مساحة عمل آمنة وعصرية مصممة للتعاون بسرعة وسهولة.",
+ "sign-up-hero-point-1": "تسجيل سريع وبسيط",
+ "sign-up-hero-point-2": "وصول آمن إلى الحساب",
+ "sign-up-hero-point-3": "جاهز للاستعمال في ثوانٍ",
"welcome": "رسالة ترحيب",
"accept-agreement": "يجب قبول الاتفاق",
"agree": "أوافق على",
diff --git a/bbbeasy-frontend/src/locale/en-US.json b/bbbeasy-frontend/src/locale/en-US.json
index b5b2c410..fd49515b 100644
--- a/bbbeasy-frontend/src/locale/en-US.json
+++ b/bbbeasy-frontend/src/locale/en-US.json
@@ -66,6 +66,19 @@
"username-already-exist": "Username already exists",
"email-already-exist": "Email already exists",
"welcome-app": "Welcome back",
+ "login-hero-tag": "Professional workspace",
+ "login-hero-title-main": "Everything you need.",
+ "login-hero-title-accent": "Simply.",
+ "login-hero-description": "Welcome to BBBEasy. Sign in to continue to your workspace and manage your activity through a secure, clear and efficient experience.",
+ "login-hero-point-1": "Secure access",
+ "login-hero-point-2": "Simple workflow",
+ "sign-up-hero-tag": "Get started",
+ "sign-up-hero-title-main": "Create your",
+ "sign-up-hero-title-accent": "BBBEasy account.",
+ "sign-up-hero-description": "Set up your account and access a secure, modern workspace built for fast collaboration and simple onboarding.",
+ "sign-up-hero-point-1": "Quick and simple registration",
+ "sign-up-hero-point-2": "Secure account access",
+ "sign-up-hero-point-3": "Ready to use in seconds",
"welcome": "Welcome",
"accept-agreement": "Should accept agreement",
"agree": "I agree to the",
diff --git a/bbbeasy-frontend/src/locale/fr-FR.json b/bbbeasy-frontend/src/locale/fr-FR.json
index 7fffb4b2..ae365c72 100644
--- a/bbbeasy-frontend/src/locale/fr-FR.json
+++ b/bbbeasy-frontend/src/locale/fr-FR.json
@@ -67,6 +67,19 @@
"username-already-exist": "Ce nom d’utilisateur existe déjà",
"email-already-exist": "Cette adresse e-mail existe déjà",
"welcome-app": "Bon retour",
+ "login-hero-tag": "Espace professionnel",
+ "login-hero-title-main": "Tout ce qu'il vous faut.",
+ "login-hero-title-accent": "Simplement.",
+ "login-hero-description": "Bienvenue sur BBBEasy. Connectez-vous pour continuer vers votre espace de travail et gérer votre activité dans un environnement sécurisé, clair et efficace.",
+ "login-hero-point-1": "Accès sécurisé",
+ "login-hero-point-2": "Flux de travail simple",
+ "sign-up-hero-tag": "Commencer",
+ "sign-up-hero-title-main": "Créez votre",
+ "sign-up-hero-title-accent": "compte BBBEasy.",
+ "sign-up-hero-description": "Créez votre compte et accédez à un espace de travail sécurisé et moderne, pensé pour collaborer rapidement et commencer facilement.",
+ "sign-up-hero-point-1": "Inscription rapide et simple",
+ "sign-up-hero-point-2": "Accès sécurisé au compte",
+ "sign-up-hero-point-3": "Prêt à utiliser en quelques secondes",
"welcome": "Message de Bienvenue",
"accept-agreement": "Devrait accepter l'accord",
"agree": "J'accepte les",
From 526365a96fed8bd000404642a8d19302c747b45a Mon Sep 17 00:00:00 2001
From: talel
Date: Tue, 11 Aug 2026 18:06:11 +0100
Subject: [PATCH 10/17] brf
---
bbbeasy-frontend/src/App-webapp.css | 21 +++++++++++++++++++
.../src/components/auth/Register.tsx | 2 +-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/bbbeasy-frontend/src/App-webapp.css b/bbbeasy-frontend/src/App-webapp.css
index 16eac51a..2f96daec 100644
--- a/bbbeasy-frontend/src/App-webapp.css
+++ b/bbbeasy-frontend/src/App-webapp.css
@@ -2232,6 +2232,27 @@ fieldset {
.login-page .login-form-column .form-content {
margin-top: clamp(-12px, -1vh, 0px);
transform: translateY(-18px);
+ width: min(100%, 520px);
+}
+
+.login-page .password-install {
+ padding-left: 0 !important;
+ padding-right: 0 !important;
+}
+
+.register-page .login-form-column {
+ min-height: calc(100vh - 240px);
+}
+
+.register-page .login-form-column .form-content {
+ margin-top: clamp(-28px, -3vh, -12px);
+ transform: translateY(-28px);
+ width: min(100%, 460px);
+}
+
+.register-page .password-install {
+ padding-left: 0 !important;
+ padding-right: 0 !important;
}
.section-top {
diff --git a/bbbeasy-frontend/src/components/auth/Register.tsx b/bbbeasy-frontend/src/components/auth/Register.tsx
index dba1da01..45ec396b 100644
--- a/bbbeasy-frontend/src/components/auth/Register.tsx
+++ b/bbbeasy-frontend/src/components/auth/Register.tsx
@@ -77,7 +77,7 @@ const Register = () => {
};
return (
-
+