feat: glass pill action bars in CreateSpace, CreateChannel, JoinSpace, and RolesPanel

This commit is contained in:
Jannis Braun
2026-03-09 01:57:11 +01:00
parent 37f199e544
commit d75788febd
4 changed files with 128 additions and 102 deletions
@@ -128,21 +128,25 @@ export function CreateChannelModal() {
</div> </div>
)} )}
<div className="flex justify-end gap-2"> <div className="sticky bottom-0 z-10 pointer-events-none">
<button <div className="flex justify-center pt-3 pb-1">
type="button" <div className="glass-bubble rounded-full px-3 py-2 flex items-center gap-3 pointer-events-auto">
onClick={closeModal} <button
className="px-4 py-2 text-sm text-txt-secondary hover:text-txt-primary transition-colors" type="button"
> onClick={closeModal}
Cancel className="px-3 py-1 text-sm text-txt-tertiary hover:text-txt-secondary transition-colors"
</button> >
<button Cancel
type="submit" </button>
disabled={isLoading} <button
className="px-4 py-2 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded transition-colors disabled:opacity-50" type="submit"
> disabled={isLoading}
{isLoading ? 'Creating...' : 'Create Channel'} className="px-3 py-1.5 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded-full transition-colors disabled:opacity-50"
</button> >
{isLoading ? 'Creating...' : 'Create Channel'}
</button>
</div>
</div>
</div> </div>
</form> </form>
</Modal> </Modal>
@@ -238,21 +238,25 @@ export function CreateSpaceModal() {
</div> </div>
{/* Actions */} {/* Actions */}
<div className="flex justify-end gap-2"> <div className="sticky bottom-0 z-10 pointer-events-none">
<button <div className="flex justify-center pt-3 pb-1">
type="button" <div className="glass-bubble rounded-full px-3 py-2 flex items-center gap-3 pointer-events-auto">
onClick={handleClose} <button
className="px-4 py-2 text-sm text-txt-secondary hover:text-txt-primary transition-colors" type="button"
> onClick={handleClose}
Cancel className="px-3 py-1 text-sm text-txt-tertiary hover:text-txt-secondary transition-colors"
</button> >
<button Cancel
type="submit" </button>
disabled={isLoading || uploadingIcon} <button
className="px-4 py-2 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded transition-colors disabled:opacity-50" type="submit"
> disabled={isLoading || uploadingIcon}
{isLoading ? 'Creating...' : 'Create'} className="px-3 py-1.5 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded-full transition-colors disabled:opacity-50"
</button> >
{isLoading ? 'Creating...' : 'Create'}
</button>
</div>
</div>
</div> </div>
</form> </form>
</Modal> </Modal>
@@ -155,21 +155,25 @@ export function JoinSpaceModal() {
autoFocus autoFocus
/> />
</div> </div>
<div className="flex justify-end gap-2"> <div className="sticky bottom-0 z-10 pointer-events-none">
<button <div className="flex justify-center pt-3 pb-1">
type="button" <div className="glass-bubble rounded-full px-3 py-2 flex items-center gap-3 pointer-events-auto">
onClick={closeModal} <button
className="px-4 py-2 text-sm text-txt-secondary hover:text-txt-primary transition-colors" type="button"
> onClick={closeModal}
Cancel className="px-3 py-1 text-sm text-txt-tertiary hover:text-txt-secondary transition-colors"
</button> >
<button Cancel
type="submit" </button>
disabled={isLoading || !inviteCode.trim()} <button
className="px-4 py-2 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded transition-colors disabled:opacity-50" type="submit"
> disabled={isLoading || !inviteCode.trim()}
{isLoading ? 'Joining...' : 'Join Space'} className="px-3 py-1.5 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded-full transition-colors disabled:opacity-50"
</button> >
{isLoading ? 'Joining...' : 'Join Space'}
</button>
</div>
</div>
</div> </div>
</form> </form>
)} )}
@@ -199,29 +203,35 @@ export function JoinSpaceModal() {
</div> </div>
</div> </div>
</div> </div>
<div className="flex justify-between"> <div className="sticky bottom-0 z-10 pointer-events-none">
<button <div className="flex justify-center pt-3 pb-1">
type="button" <div className="glass-bubble rounded-full px-3 py-2 flex items-center gap-3 pointer-events-auto">
onClick={() => { setPhase('input'); setPassword(''); setError(''); }} <button
className="text-xs text-txt-tertiary hover:text-txt-secondary transition-colors" type="button"
> onClick={() => { setPhase('input'); setPassword(''); setError(''); }}
Back className="px-3 py-1 text-sm text-txt-tertiary hover:text-txt-secondary transition-colors flex items-center gap-1"
</button> >
<div className="flex gap-2"> <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<button <path strokeLinecap="round" strokeLinejoin="round" d="M15 19l-7-7 7-7" />
type="button" </svg>
onClick={closeModal} Back
className="px-4 py-2 text-sm text-txt-secondary hover:text-txt-primary transition-colors" </button>
> <div className="w-px h-5 bg-white/10" />
Cancel <button
</button> type="button"
<button onClick={closeModal}
type="submit" className="px-3 py-1 text-sm text-txt-tertiary hover:text-txt-secondary transition-colors"
disabled={isLoading || !password} >
className="px-4 py-2 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded transition-colors disabled:opacity-50" Cancel
> </button>
{isLoading ? 'Connecting...' : 'Connect & Join'} <button
</button> type="submit"
disabled={isLoading || !password}
className="px-3 py-1.5 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded-full transition-colors disabled:opacity-50"
>
{isLoading ? 'Connecting...' : 'Connect & Join'}
</button>
</div>
</div> </div>
</div> </div>
</form> </form>
@@ -258,29 +268,35 @@ export function JoinSpaceModal() {
/> />
</div> </div>
</div> </div>
<div className="flex justify-between"> <div className="sticky bottom-0 z-10 pointer-events-none">
<button <div className="flex justify-center pt-3 pb-1">
type="button" <div className="glass-bubble rounded-full px-3 py-2 flex items-center gap-3 pointer-events-auto">
onClick={() => { setPhase('connect'); setFallbackPassword(''); setError(''); }} <button
className="text-xs text-txt-tertiary hover:text-txt-secondary transition-colors" type="button"
> onClick={() => { setPhase('connect'); setFallbackPassword(''); setError(''); }}
Back className="px-3 py-1 text-sm text-txt-tertiary hover:text-txt-secondary transition-colors flex items-center gap-1"
</button> >
<div className="flex gap-2"> <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<button <path strokeLinecap="round" strokeLinejoin="round" d="M15 19l-7-7 7-7" />
type="button" </svg>
onClick={closeModal} Back
className="px-4 py-2 text-sm text-txt-secondary hover:text-txt-primary transition-colors" </button>
> <div className="w-px h-5 bg-white/10" />
Cancel <button
</button> type="button"
<button onClick={closeModal}
type="submit" className="px-3 py-1 text-sm text-txt-tertiary hover:text-txt-secondary transition-colors"
disabled={isLoading || !fallbackUsername || !fallbackPassword} >
className="px-4 py-2 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded transition-colors disabled:opacity-50" Cancel
> </button>
{isLoading ? 'Logging in...' : 'Login & Join'} <button
</button> type="submit"
disabled={isLoading || !fallbackUsername || !fallbackPassword}
className="px-3 py-1.5 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded-full transition-colors disabled:opacity-50"
>
{isLoading ? 'Logging in...' : 'Login & Join'}
</button>
</div>
</div> </div>
</div> </div>
</form> </form>
@@ -113,17 +113,19 @@ export function RolesPanel({ spaceId }: RolesPanelProps) {
<div className="p-2 bg-accent-rose/10 border border-accent-rose/30 rounded text-txt-danger text-sm">{error}</div> <div className="p-2 bg-accent-rose/10 border border-accent-rose/30 rounded text-txt-danger text-sm">{error}</div>
)} )}
<button <div className="sticky top-0 z-10 pointer-events-none pb-3">
onClick={handleCreateRole} <button
disabled={creating} onClick={handleCreateRole}
className="flex items-center gap-1.5 px-3 py-1.5 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded transition-colors disabled:opacity-50" disabled={creating}
> className="glass-bubble rounded-full px-3 py-1.5 flex items-center gap-1.5 text-sm text-txt-primary hover:text-txt-secondary transition-colors pointer-events-auto disabled:opacity-50"
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}> >
<line x1="12" y1="5" x2="12" y2="19" /> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
<line x1="5" y1="12" x2="19" y2="12" /> <line x1="12" y1="5" x2="12" y2="19" />
</svg> <line x1="5" y1="12" x2="19" y2="12" />
{creating ? 'Creating...' : 'Create Role'} </svg>
</button> {creating ? 'Creating...' : 'Create Role'}
</button>
</div>
<div className="space-y-1"> <div className="space-y-1">
{sortedRoles.map((role) => { {sortedRoles.map((role) => {