Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@ import MainContent from './components/MainContent'
import MiniRkxButton from './components/MiniRkxButton'
import MiniRkxMenu from './components/MiniRkxMenu'
import ApiSettingsModal from './components/ApiSettingsModal'
import './styles/minirkx.css'

export default function App() {
const [sidebarOpen, setSidebarOpen] = useState(false)
const [menuOpen, setMenuOpen] = useState(false)
const [showApiModal, setShowApiModal] = useState(false)
const [prompt, setPrompt] = useState('')
const [isRecording, setIsRecording] = useState(false)
const [currentPage, setCurrentPage] = useState('home')

const handleMenuCommand = (command: string) => {
console.log(`Menu command: ${command}`)
console.log(`[v0] Menu command: ${command}`)
// Handle menu commands here
}

const handleNavigate = (page: string) => {
console.log(`[v0] Navigating to: ${page}`)
setCurrentPage(page)
}

const handleSubmitPrompt = () => {
if (!prompt.trim()) return
console.log(`Submitting prompt: ${prompt}`)
Expand Down Expand Up @@ -68,6 +75,7 @@ export default function App() {
isOpen={menuOpen}
onClose={() => setMenuOpen(false)}
onMenuCommand={handleMenuCommand}
onNavigate={handleNavigate}
/>

{/* API Settings Modal */}
Expand Down
22 changes: 13 additions & 9 deletions src/components/MiniRkxMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ interface MiniRkxMenuProps {
isOpen: boolean
onClose: () => void
onMenuCommand: (command: string) => void
onNavigate?: (page: string) => void
}

const menuItems = [
{ icon: '🏠', label: 'Trang chủ', command: 'Trang chủ' },
{ icon: '📚', label: 'Thư viện', command: 'Thư viện' },
{ icon: '📂', label: 'Dự án', command: 'Dự án' },
{ icon: '⚙️', label: 'Ứng dụng', command: 'Ứng dụng' },
{ icon: '💻', label: 'Codex', command: 'Codex' },
{ icon: '🔧', label: 'Cài đặt', command: 'Cài đặt' },
{ icon: '🏠', label: 'Trang chủ', command: 'home', page: 'home' },
{ icon: '📚', label: 'Thư viện', command: 'library', page: 'library' },
{ icon: '📂', label: 'Dự án', command: 'projects', page: 'projects' },
{ icon: '⚙️', label: 'Ứng dụng', command: 'apps', page: 'apps' },
{ icon: '💻', label: 'Codex', command: 'codex', page: 'codex' },
{ icon: '🔧', label: 'Cài đặt', command: 'settings', page: 'settings' },
]

export default function MiniRkxMenu({ isOpen, onClose, onMenuCommand }: MiniRkxMenuProps) {
const handleItemClick = (command: string) => {
export default function MiniRkxMenu({ isOpen, onClose, onMenuCommand, onNavigate }: MiniRkxMenuProps) {
const handleItemClick = (command: string, page: string) => {
onMenuCommand(command)
if (onNavigate) {
onNavigate(page)
}
onClose()
}

Expand All @@ -28,7 +32,7 @@ export default function MiniRkxMenu({ isOpen, onClose, onMenuCommand }: MiniRkxM
<div
key={index}
className="minirkx-hex-item"
onClick={() => handleItemClick(item.command)}
onClick={() => handleItemClick(item.command, item.page)}
>
<div className="minirkx-hex-content">
<div className="minirkx-hex-icon">{item.icon}</div>
Expand Down
199 changes: 199 additions & 0 deletions src/styles/minirkx.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/* MiniRkx Floating Button Styles */
.minirkx-button {
position: fixed;
bottom: 32px;
right: 32px;
width: 72px;
height: 72px;
border-radius: 18px;
background: linear-gradient(135deg, #0052cc 0%, #00d2ff 100%);
border: 2px solid rgba(0, 210, 255, 0.4);
z-index: 35;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 24px rgba(0, 210, 255, 0.3), 0 8px 32px rgba(0, 82, 204, 0.2);
user-select: none;
-webkit-user-select: none;
padding: 0;
}

.minirkx-button:hover {
transform: scale(1.08);
box-shadow: 0 0 32px rgba(0, 210, 255, 0.5), 0 12px 48px rgba(0, 82, 204, 0.3);
border-color: rgba(0, 210, 255, 0.6);
}

.minirkx-button:active {
transform: scale(0.95);
}

.minirkx-button.open {
transform: rotate(45deg);
}

.minirkx-logo {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}

.minirkx-logo svg {
width: 100%;
height: 100%;
filter: drop-shadow(0 0 8px rgba(0, 210, 255, 0.4));
}

@keyframes minirkx-pulse-glow {
0%, 100% {
box-shadow: 0 0 24px rgba(0, 210, 255, 0.3), 0 8px 32px rgba(0, 82, 204, 0.2);
}
50% {
box-shadow: 0 0 36px rgba(0, 210, 255, 0.5), 0 12px 48px rgba(0, 82, 204, 0.35);
}
}

.minirkx-button.pulse {
animation: minirkx-pulse-glow 2s ease-in-out infinite;
}

/* Honeycomb Menu */
.minirkx-menu {
position: fixed;
inset: 0;
z-index: 30;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s ease;
}

.minirkx-menu.open {
pointer-events: auto;
opacity: 1;
}

.minirkx-menu-backdrop {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0);
transition: background 0.3s ease;
cursor: pointer;
}

.minirkx-menu.open .minirkx-menu-backdrop {
background: rgba(0, 0, 0, 0.4);
}

.minirkx-honeycomb {
position: absolute;
bottom: 32px;
right: 32px;
width: 360px;
height: 360px;
display: flex;
align-items: center;
justify-content: center;
}

.minirkx-hex-item {
position: absolute;
width: 80px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
opacity: 0;
transform: scale(0) translate(0, 0);
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.minirkx-menu.open .minirkx-hex-item {
opacity: 1;
transform: scale(1) translate(var(--tx), var(--ty));
}

.minirkx-hex-item:nth-child(1) { --tx: 0px; --ty: -90px; transition-delay: 0.05s; }
.minirkx-hex-item:nth-child(2) { --tx: 78px; --ty: -45px; transition-delay: 0.1s; }
.minirkx-hex-item:nth-child(3) { --tx: 78px; --ty: 45px; transition-delay: 0.15s; }
.minirkx-hex-item:nth-child(4) { --tx: 0px; --ty: 90px; transition-delay: 0.2s; }
.minirkx-hex-item:nth-child(5) { --tx: -78px; --ty: 45px; transition-delay: 0.25s; }
.minirkx-hex-item:nth-child(6) { --tx: -78px; --ty: -45px; transition-delay: 0.3s; }

.minirkx-hex-content {
width: 100%;
height: 100%;
border-radius: 12px;
background: linear-gradient(135deg, rgba(0, 82, 204, 0.8) 0%, rgba(0, 210, 255, 0.8) 100%);
border: 2px solid rgba(0, 210, 255, 0.4);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
transition: all 0.3s ease;
box-shadow: 0 4px 16px rgba(0, 82, 204, 0.2);
user-select: none;
-webkit-user-select: none;
}

.minirkx-hex-item:hover .minirkx-hex-content {
transform: scale(1.12);
border-color: rgba(0, 210, 255, 0.8);
box-shadow: 0 8px 32px rgba(0, 210, 255, 0.4);
background: linear-gradient(135deg, rgba(0, 82, 204, 1) 0%, rgba(0, 210, 255, 1) 100%);
}

.minirkx-hex-icon {
font-size: 24px;
line-height: 1;
}

.minirkx-hex-label {
font-size: 10px;
font-weight: 700;
color: white;
text-align: center;
letter-spacing: 0.5px;
text-transform: uppercase;
}

@media (max-width: 768px) {
.minirkx-button {
width: 64px;
height: 64px;
bottom: 24px;
right: 24px;
}

.minirkx-honeycomb {
width: 280px;
height: 280px;
bottom: 24px;
right: 24px;
}

.minirkx-hex-item:nth-child(1) { --tx: 0px; --ty: -70px; }
.minirkx-hex-item:nth-child(2) { --tx: 60px; --ty: -35px; }
.minirkx-hex-item:nth-child(3) { --tx: 60px; --ty: 35px; }
.minirkx-hex-item:nth-child(4) { --tx: 0px; --ty: 70px; }
.minirkx-hex-item:nth-child(5) { --tx: -60px; --ty: 35px; }
.minirkx-hex-item:nth-child(6) { --tx: -60px; --ty: -35px; }

.minirkx-hex-content {
width: 72px;
height: 72px;
}

.minirkx-hex-icon {
font-size: 20px;
}

.minirkx-hex-label {
font-size: 9px;
}
}
Loading