feat: Add mode selection interface for creator/joiner
**Motivations :** - Improve user experience with clear role selection - Add intuitive interface to choose between creator and joiner modes - Provide easy navigation between modes **Modifications :** - Added mode selection screen with two main buttons - Added back buttons to return to mode selection - Enhanced CSS styling for mode buttons and navigation - Added JavaScript logic for mode switching **Pages affectées :** - src/pages/home/home.html - Added mode selection interface - src/pages/home/home.ts - Added mode selection logic - src/4nk.css - Added styling for mode selection and back buttons
This commit is contained in:
parent
03bc0b5602
commit
82b3b27ab6
116
src/4nk.css
116
src/4nk.css
@ -1080,3 +1080,119 @@ select[data-multi-select-plugin] {
|
|||||||
.custom-select::-webkit-scrollbar-thumb:hover {
|
.custom-select::-webkit-scrollbar-thumb:hover {
|
||||||
background: #555;
|
background: #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mode Selection Styles */
|
||||||
|
.mode-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 250px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
text-align: left;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn.primary-btn {
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn.primary-btn:hover {
|
||||||
|
background: var(--primary-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn.secondary-btn {
|
||||||
|
border-color: var(--secondary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn.secondary-btn:hover {
|
||||||
|
background: var(--secondary-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-icon {
|
||||||
|
font-size: 32px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-content h3 {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-content p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn:hover .mode-content p {
|
||||||
|
color: inherit;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Back Button Styles */
|
||||||
|
.back-btn {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
color: #666;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-btn:hover {
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header .back-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Design for Mode Selection */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.mode-buttons {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn {
|
||||||
|
min-width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header .back-btn {
|
||||||
|
position: static;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,8 +1,35 @@
|
|||||||
<div class="pairing-container">
|
<div class="pairing-container">
|
||||||
|
<!-- Mode Selection -->
|
||||||
|
<div id="mode-selection" class="card pairing-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>🔐 4NK Pairing</h2>
|
||||||
|
<p class="card-description">Choose your role in the pairing process</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mode-buttons">
|
||||||
|
<button id="creator-mode-btn" class="mode-btn primary-btn">
|
||||||
|
<div class="mode-icon">🔐</div>
|
||||||
|
<div class="mode-content">
|
||||||
|
<h3>Create New Pairing</h3>
|
||||||
|
<p>Generate 4 words to share with another device</p>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button id="joiner-mode-btn" class="mode-btn secondary-btn">
|
||||||
|
<div class="mode-icon">🔗</div>
|
||||||
|
<div class="mode-content">
|
||||||
|
<h3>Join Existing Pairing</h3>
|
||||||
|
<p>Enter 4 words from another device</p>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Creator Flow -->
|
<!-- Creator Flow -->
|
||||||
<div id="creator-flow" class="card pairing-card" style="display: none">
|
<div id="creator-flow" class="card pairing-card" style="display: none">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h2>🔐 Create New Pairing</h2>
|
<h2>🔐 Create New Pairing</h2>
|
||||||
|
<button id="back-to-mode-creator" class="back-btn">← Back to Mode Selection</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pairing-request"></div>
|
<div class="pairing-request"></div>
|
||||||
@ -28,6 +55,7 @@
|
|||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h2>🔗 Join Existing Pairing</h2>
|
<h2>🔗 Join Existing Pairing</h2>
|
||||||
<p class="card-description">Enter the 4 words from the creator device</p>
|
<p class="card-description">Enter the 4 words from the creator device</p>
|
||||||
|
<button id="back-to-mode-joiner" class="back-btn">← Back to Mode Selection</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
|
|||||||
@ -118,6 +118,9 @@ export async function initHomePage(): Promise<void> {
|
|||||||
// Set up iframe pairing button listeners
|
// Set up iframe pairing button listeners
|
||||||
setupIframePairingButtons();
|
setupIframePairingButtons();
|
||||||
|
|
||||||
|
// Set up mode selection
|
||||||
|
setupModeSelection();
|
||||||
|
|
||||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||||
container.querySelectorAll('.tab').forEach(tab => {
|
container.querySelectorAll('.tab').forEach(tab => {
|
||||||
addSubscription(tab, 'click', () => {
|
addSubscription(tab, 'click', () => {
|
||||||
@ -513,3 +516,66 @@ export function setupIframePairingButtons() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mode Selection Functions
|
||||||
|
export function setupModeSelection(): void {
|
||||||
|
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||||
|
|
||||||
|
// Mode selection buttons
|
||||||
|
const creatorModeBtn = container.querySelector('#creator-mode-btn') as HTMLButtonElement;
|
||||||
|
const joinerModeBtn = container.querySelector('#joiner-mode-btn') as HTMLButtonElement;
|
||||||
|
|
||||||
|
// Back buttons
|
||||||
|
const backToModeCreator = container.querySelector('#back-to-mode-creator') as HTMLButtonElement;
|
||||||
|
const backToModeJoiner = container.querySelector('#back-to-mode-joiner') as HTMLButtonElement;
|
||||||
|
|
||||||
|
if (creatorModeBtn) {
|
||||||
|
creatorModeBtn.addEventListener('click', () => {
|
||||||
|
showMode('creator');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinerModeBtn) {
|
||||||
|
joinerModeBtn.addEventListener('click', () => {
|
||||||
|
showMode('joiner');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backToModeCreator) {
|
||||||
|
backToModeCreator.addEventListener('click', () => {
|
||||||
|
showMode('selection');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backToModeJoiner) {
|
||||||
|
backToModeJoiner.addEventListener('click', () => {
|
||||||
|
showMode('selection');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMode(mode: 'selection' | 'creator' | 'joiner'): void {
|
||||||
|
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||||
|
|
||||||
|
const modeSelection = container.querySelector('#mode-selection') as HTMLElement;
|
||||||
|
const creatorFlow = container.querySelector('#creator-flow') as HTMLElement;
|
||||||
|
const joinerFlow = container.querySelector('#joiner-flow') as HTMLElement;
|
||||||
|
|
||||||
|
// Hide all flows
|
||||||
|
if (modeSelection) modeSelection.style.display = 'none';
|
||||||
|
if (creatorFlow) creatorFlow.style.display = 'none';
|
||||||
|
if (joinerFlow) joinerFlow.style.display = 'none';
|
||||||
|
|
||||||
|
// Show selected flow
|
||||||
|
switch (mode) {
|
||||||
|
case 'selection':
|
||||||
|
if (modeSelection) modeSelection.style.display = 'block';
|
||||||
|
break;
|
||||||
|
case 'creator':
|
||||||
|
if (creatorFlow) creatorFlow.style.display = 'block';
|
||||||
|
break;
|
||||||
|
case 'joiner':
|
||||||
|
if (joinerFlow) joinerFlow.style.display = 'block';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -523,14 +523,14 @@ export default class Services {
|
|||||||
|
|
||||||
private getRelayReadyPromise(): Promise<void> {
|
private getRelayReadyPromise(): Promise<void> {
|
||||||
console.log('🔍 DEBUG: getRelayReadyPromise called, promise exists:', !!this.relayReadyPromise);
|
console.log('🔍 DEBUG: getRelayReadyPromise called, promise exists:', !!this.relayReadyPromise);
|
||||||
|
|
||||||
// If we already have a relay with spAddress, return resolved promise
|
// If we already have a relay with spAddress, return resolved promise
|
||||||
const hasRelayWithAddress = Object.values(this.relayAddresses).some(address => address && address.trim() !== '');
|
const hasRelayWithAddress = Object.values(this.relayAddresses).some(address => address && address.trim() !== '');
|
||||||
if (hasRelayWithAddress) {
|
if (hasRelayWithAddress) {
|
||||||
console.log('🔍 DEBUG: Relay already ready with spAddress, returning resolved promise');
|
console.log('🔍 DEBUG: Relay already ready with spAddress, returning resolved promise');
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.relayReadyPromise) {
|
if (!this.relayReadyPromise) {
|
||||||
console.log('🔍 DEBUG: Creating new relay ready promise');
|
console.log('🔍 DEBUG: Creating new relay ready promise');
|
||||||
this.relayReadyPromise = new Promise<void>(resolve => {
|
this.relayReadyPromise = new Promise<void>(resolve => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user