feat: Move world nav buttons into search bars

- Remove top world nav bar
- Add Islands/Planets buttons to Map search bar
- Add Map/Planets buttons to Islands search bar
- Add Map/Islands buttons to Planets search bar
- Move search bars to fixed position just below topbar
- Compact button styling matching map design
- v0.0.107

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-01-24 20:12:43 +00:00
parent 9706d673c3
commit ef075ccb9b
9 changed files with 113 additions and 50 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "sociowire-frontend", "name": "sociowire-frontend",
"version": "0.0.104", "version": "0.0.107",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "sociowire-frontend", "name": "sociowire-frontend",
"version": "0.0.104", "version": "0.0.107",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^7.1.0", "@fortawesome/fontawesome-free": "^7.1.0",
"axios": "^1.13.2", "axios": "^1.13.2",

View File

@ -1,7 +1,7 @@
{ {
"name": "sociowire-frontend", "name": "sociowire-frontend",
"private": true, "private": true,
"version": "0.0.104", "version": "0.0.107",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host 0.0.0.0", "dev": "vite --host 0.0.0.0",

View File

@ -214,31 +214,6 @@ export default function App() {
currentView={currentView} currentView={currentView}
/> />
{/* World Switcher Navigation */}
<div className="world-nav">
<button
className={`world-nav-btn ${currentView === 'map' ? 'is-active' : ''}`}
onClick={handleOpenMap}
>
<i className="fa-solid fa-earth-americas" />
<span>{t('worlds.map')}</span>
</button>
<button
className={`world-nav-btn ${currentView === 'islands' ? 'is-active' : ''}`}
onClick={handleOpenIslands}
>
<i className="fa-solid fa-umbrella-beach" />
<span>{t('worlds.islands')}</span>
</button>
<button
className={`world-nav-btn ${currentView === 'planets' ? 'is-active' : ''}`}
onClick={handleOpenPlanets}
>
<i className="fa-solid fa-globe" />
<span>{t('worlds.planets')}</span>
</button>
</div>
<div className="main-shell"> <div className="main-shell">
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
{/* MAP WORLD - Reality */} {/* MAP WORLD - Reality */}
@ -262,6 +237,7 @@ export default function App() {
selectedIsland={selectedIsland} selectedIsland={selectedIsland}
onSelectIsland={setSelectedIsland} onSelectIsland={setSelectedIsland}
onOpenIslands={handleOpenIslands} onOpenIslands={handleOpenIslands}
onOpenPlanets={handleOpenPlanets}
/> />
</Suspense> </Suspense>
</div> </div>
@ -308,6 +284,7 @@ export default function App() {
theme={theme} theme={theme}
onIslandClick={handleIslandClick} onIslandClick={handleIslandClick}
onOpenMap={handleOpenMap} onOpenMap={handleOpenMap}
onOpenPlanets={handleOpenPlanets}
/> />
</Suspense> </Suspense>
</motion.div> </motion.div>
@ -327,6 +304,7 @@ export default function App() {
<PlanetsWorld <PlanetsWorld
theme={theme} theme={theme}
onOpenMap={handleOpenMap} onOpenMap={handleOpenMap}
onOpenIslands={handleOpenIslands}
/> />
</Suspense> </Suspense>
</motion.div> </motion.div>

View File

@ -142,6 +142,7 @@ export default function MapView({
selectedIsland, selectedIsland,
onSelectIsland, onSelectIsland,
onOpenIslands, onOpenIslands,
onOpenPlanets,
}) { }) {
const { authenticated, username, token, needsEmailVerification } = useAuth(); const { authenticated, username, token, needsEmailVerification } = useAuth();
const CLUSTERS_ENABLED = false; const CLUSTERS_ENABLED = false;
@ -2238,11 +2239,19 @@ export default function MapView({
<button <button
type="button" type="button"
className="sw-search__iconBtn" className="sw-search__iconBtn"
title="Profile Island" title="Islands"
onClick={() => onOpenIslands && onOpenIslands()} onClick={() => onOpenIslands && onOpenIslands()}
> >
<i className="fa-solid fa-umbrella-beach"></i> <i className="fa-solid fa-umbrella-beach"></i>
</button> </button>
<button
type="button"
className="sw-search__iconBtn"
title="Planets"
onClick={() => onOpenPlanets && onOpenPlanets()}
>
<i className="fa-solid fa-globe"></i>
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -2,7 +2,9 @@
.islands-world { .islands-world {
position: relative; position: relative;
width: 100%; width: 100%;
min-height: 100vh; min-height: calc(100vh - 100px);
margin: 0;
padding: 0;
background: linear-gradient(180deg, #0a1628 0%, #0d2847 50%, #1e3a5f 100%); background: linear-gradient(180deg, #0a1628 0%, #0d2847 50%, #1e3a5f 100%);
overflow: hidden; overflow: hidden;
} }
@ -16,21 +18,21 @@
/* Search bar */ /* Search bar */
.islands-world-search { .islands-world-search {
position: absolute; position: fixed;
top: 16px; top: 56px;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
z-index: 100; z-index: 100;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
background: rgba(15, 23, 42, 0.9); background: rgba(15, 23, 42, 0.95);
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
border: 1px solid rgba(56, 189, 248, 0.3); border: 1px solid rgba(56, 189, 248, 0.3);
border-radius: 50px; border-radius: 50px;
padding: 10px 16px; padding: 8px 12px;
width: 90%; width: auto;
max-width: 360px; max-width: 500px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
} }
@ -53,6 +55,32 @@
border-radius: 20px; border-radius: 20px;
} }
.islands-world-search .world-nav-inline {
display: flex;
gap: 4px;
margin-left: 6px;
}
.islands-world-search .world-nav-btn-sm {
width: 30px;
height: 30px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.7);
font-size: 13px;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}
.islands-world-search .world-nav-btn-sm:hover {
background: rgba(56, 189, 248, 0.3);
color: white;
}
.islands-world-search input { .islands-world-search input {
flex: 1; flex: 1;
background: transparent; background: transparent;

View File

@ -10,7 +10,7 @@ import './IslandsWorld.css';
* IslandsWorld: Full-screen metaverse for personal islands * IslandsWorld: Full-screen metaverse for personal islands
* Each user has their own floating island in this virtual ocean * Each user has their own floating island in this virtual ocean
*/ */
export default function IslandsWorld({ theme, onIslandClick, onOpenMap }) { export default function IslandsWorld({ theme, onIslandClick, onOpenMap, onOpenPlanets }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { authenticated, username } = useAuth(); const { authenticated, username } = useAuth();
const containerRef = useRef(null); const containerRef = useRef(null);
@ -180,7 +180,7 @@ export default function IslandsWorld({ theme, onIslandClick, onOpenMap }) {
return ( return (
<div className="islands-world"> <div className="islands-world">
{/* Search bar with icon */} {/* Search bar with icon and world nav */}
<div className="islands-world-search"> <div className="islands-world-search">
<i className="fa-solid fa-umbrella-beach search-icon" /> <i className="fa-solid fa-umbrella-beach search-icon" />
<i className="fa-solid fa-search" /> <i className="fa-solid fa-search" />
@ -196,6 +196,14 @@ export default function IslandsWorld({ theme, onIslandClick, onOpenMap }) {
</button> </button>
)} )}
<span className="search-count">{islands.length}</span> <span className="search-count">{islands.length}</span>
<div className="world-nav-inline">
<button className="world-nav-btn-sm" onClick={onOpenMap} title={t('worlds.map')}>
<i className="fa-solid fa-earth-americas" />
</button>
<button className="world-nav-btn-sm" onClick={onOpenPlanets} title={t('worlds.planets')}>
<i className="fa-solid fa-globe" />
</button>
</div>
</div> </div>
{/* Main canvas */} {/* Main canvas */}

View File

@ -2,7 +2,9 @@
.planets-world { .planets-world {
position: relative; position: relative;
width: 100%; width: 100%;
min-height: 100vh; min-height: calc(100vh - 100px);
margin: 0;
padding: 0;
background: radial-gradient(ellipse at center, #0f0f1a 0%, #050510 70%, #000005 100%); background: radial-gradient(ellipse at center, #0f0f1a 0%, #050510 70%, #000005 100%);
overflow: hidden; overflow: hidden;
} }
@ -16,21 +18,21 @@
/* Search bar */ /* Search bar */
.planets-world-search { .planets-world-search {
position: absolute; position: fixed;
top: 16px; top: 56px;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
z-index: 100; z-index: 100;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
background: rgba(15, 15, 26, 0.9); background: rgba(15, 15, 26, 0.95);
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
border: 1px solid rgba(155, 89, 182, 0.3); border: 1px solid rgba(155, 89, 182, 0.3);
border-radius: 50px; border-radius: 50px;
padding: 10px 16px; padding: 8px 12px;
width: 90%; width: auto;
max-width: 360px; max-width: 500px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
} }
@ -53,6 +55,32 @@
border-radius: 20px; border-radius: 20px;
} }
.planets-world-search .world-nav-inline {
display: flex;
gap: 4px;
margin-left: 6px;
}
.planets-world-search .world-nav-btn-sm {
width: 30px;
height: 30px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.7);
font-size: 13px;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}
.planets-world-search .world-nav-btn-sm:hover {
background: rgba(155, 89, 182, 0.3);
color: white;
}
.planets-world-search input { .planets-world-search input {
flex: 1; flex: 1;
background: transparent; background: transparent;

View File

@ -10,7 +10,7 @@ import './PlanetsWorld.css';
* PlanetsWorld: Full-screen metaverse for group spaces (planets) * PlanetsWorld: Full-screen metaverse for group spaces (planets)
* Each planet represents a community/group floating in space * Each planet represents a community/group floating in space
*/ */
export default function PlanetsWorld({ theme, onOpenMap }) { export default function PlanetsWorld({ theme, onOpenMap, onOpenIslands }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { authenticated } = useAuth(); const { authenticated } = useAuth();
const containerRef = useRef(null); const containerRef = useRef(null);
@ -168,7 +168,7 @@ export default function PlanetsWorld({ theme, onOpenMap }) {
return ( return (
<div className="planets-world"> <div className="planets-world">
{/* Search bar with icon */} {/* Search bar with icon and world nav */}
<div className="planets-world-search"> <div className="planets-world-search">
<i className="fa-solid fa-globe search-icon" /> <i className="fa-solid fa-globe search-icon" />
<i className="fa-solid fa-search" /> <i className="fa-solid fa-search" />
@ -184,6 +184,14 @@ export default function PlanetsWorld({ theme, onOpenMap }) {
</button> </button>
)} )}
<span className="search-count">{planets.length}</span> <span className="search-count">{planets.length}</span>
<div className="world-nav-inline">
<button className="world-nav-btn-sm" onClick={onOpenMap} title={t('worlds.map')}>
<i className="fa-solid fa-earth-americas" />
</button>
<button className="world-nav-btn-sm" onClick={onOpenIslands} title={t('worlds.islands')}>
<i className="fa-solid fa-umbrella-beach" />
</button>
</div>
</div> </div>
{/* Main canvas */} {/* Main canvas */}

View File

@ -210,10 +210,14 @@
/* World containers */ /* World containers */
.world-container { .world-container {
width: 100%; width: 100%;
margin: 0;
padding: 0;
} }
.world-fullscreen { .world-fullscreen {
min-height: calc(100vh - 110px); min-height: calc(100vh - 100px);
margin: 0;
padding: 0;
} }
/* World placeholder */ /* World placeholder */