desktop: components/start-menu — Windows 11-style centered start menu with app grid, search, animated slide-up
This commit is contained in:
parent
490317b3ea
commit
8ad129ed17
@ -0,0 +1,24 @@
|
|||||||
|
<div class="start-menu-backdrop" (click)="close.emit()"></div>
|
||||||
|
<div class="start-menu">
|
||||||
|
<div class="start-header">
|
||||||
|
<span class="start-logo">🦋</span>
|
||||||
|
<span class="start-title">Butterfly</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="start-search">
|
||||||
|
<input type="text" placeholder="Type to search..." class="search-input" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="app-grid">
|
||||||
|
@for (app of apps; track app.id) {
|
||||||
|
<button class="app-tile" (click)="onLaunch(app.id)">
|
||||||
|
<span class="app-tile-icon">{{ app.icon }}</span>
|
||||||
|
<span class="app-tile-title">{{ app.title }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="start-footer">
|
||||||
|
<span class="version">Butterfly Desktop v0.1</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
134
desktop/src/app/components/start-menu/start-menu.component.scss
Normal file
134
desktop/src/app/components/start-menu/start-menu.component.scss
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
:host {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-menu-backdrop {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-menu {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 56px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 520px;
|
||||||
|
max-height: 580px;
|
||||||
|
background: #2d2d2d;
|
||||||
|
border: 1px solid #444;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 8px 48px rgba(0, 0, 0, 0.5), 0 2px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
z-index: 8500;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
animation: slideUp 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-50%) translateY(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(-50%) translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 20px 24px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-logo {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-search {
|
||||||
|
padding: 0 20px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border: 1px solid #555;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #383838;
|
||||||
|
color: #e0e0e0;
|
||||||
|
font-size: 13px;
|
||||||
|
outline: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: #0078d4;
|
||||||
|
box-shadow: 0 0 0 1px #0078d4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 4px;
|
||||||
|
padding: 4px 20px 16px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-tile {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 16px 8px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s;
|
||||||
|
color: #e0e0e0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: rgba(255, 255, 255, 0.03);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-tile-icon {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-tile-title {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-footer {
|
||||||
|
padding: 8px 24px 14px;
|
||||||
|
border-top: 1px solid #3a3a3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
import { Component, output } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-start-menu',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule],
|
||||||
|
templateUrl: './start-menu.component.html',
|
||||||
|
styleUrl: './start-menu.component.scss',
|
||||||
|
})
|
||||||
|
export class StartMenuComponent {
|
||||||
|
readonly launchApp = output<string>();
|
||||||
|
readonly close = output<void>();
|
||||||
|
|
||||||
|
apps = [
|
||||||
|
{ id: 'file-explorer', icon: '📁', title: 'File Explorer', description: 'Browse files and folders' },
|
||||||
|
{ id: 'terminal', icon: '⬛', title: 'Terminal', description: 'Command-line interface' },
|
||||||
|
{ id: 'text-editor', icon: '📝', title: 'Text Editor', description: 'Edit text and code files' },
|
||||||
|
{ id: 'browser', icon: '🌐', title: 'Web Browser', description: 'Browse the web' },
|
||||||
|
{ id: 'settings', icon: '⚙️', title: 'Settings', description: 'System configuration' },
|
||||||
|
{ id: 'remote-display', icon: '🖥️', title: 'Remote Desktop', description: 'Connect to a VM session' },
|
||||||
|
];
|
||||||
|
|
||||||
|
onLaunch(id: string): void {
|
||||||
|
this.launchApp.emit(id);
|
||||||
|
this.close.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user