From f3eab207a5de3204c0e4a7d2c27d871c6c0297e9 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Tue, 20 Jan 2026 12:46:29 +0100 Subject: [PATCH] add shared assets at root for base-apps testing icons/, scripts/, ui/ folders are needed at root for base-apps manifest paths like ../../icons/ to resolve correctly during testing --- .gitignore | 6 +- icons/account.tga | 3 + icons/add.tga | 3 + icons/back.tga | 3 + icons/backspace.tga | 3 + icons/battery.tga | 3 + icons/browser.tga | 3 + icons/calculator.tga | 3 + icons/calendar.tga | 3 + icons/call_small.tga | 3 + icons/camera.tga | 3 + icons/clock.tga | 3 + icons/close.tga | 3 + icons/contact_phone.tga | 3 + icons/contacts.tga | 3 + icons/dialpad.tga | 3 + icons/download.tga | 3 + icons/files.tga | 3 + icons/flash.tga | 3 + icons/forward.tga | 3 + icons/gallery.tga | 3 + icons/game.tga | 3 + icons/heart.tga | 3 + icons/history.tga | 3 + icons/home.tga | 3 + icons/library.tga | 3 + icons/maps.tga | 3 + icons/menu.tga | 3 + icons/message.tga | 3 + icons/more.tga | 3 + icons/music.tga | 3 + icons/notes.tga | 3 + icons/phone.tga | 3 + icons/play.tga | 3 + icons/refresh.tga | 3 + icons/search.tga | 3 + icons/send.tga | 3 + icons/settings.tga | 3 + icons/signal.tga | 3 + icons/store.tga | 3 + icons/switch-camera.tga | 3 + icons/timer.tga | 3 + icons/weather.tga | 3 + icons/wifi.tga | 3 + scripts/layout.lua | 103 +++ scripts/navigation.lua | 145 ++++ ui/components.rcss | 1485 +++++++++++++++++++++++++++++++++++++++ ui/html.rcss | 93 +++ ui/layout.rcss | 270 +++++++ ui/theme.rcss | 333 +++++++++ 50 files changed, 2560 insertions(+), 4 deletions(-) create mode 100644 icons/account.tga create mode 100644 icons/add.tga create mode 100644 icons/back.tga create mode 100644 icons/backspace.tga create mode 100644 icons/battery.tga create mode 100644 icons/browser.tga create mode 100644 icons/calculator.tga create mode 100644 icons/calendar.tga create mode 100644 icons/call_small.tga create mode 100644 icons/camera.tga create mode 100644 icons/clock.tga create mode 100644 icons/close.tga create mode 100644 icons/contact_phone.tga create mode 100644 icons/contacts.tga create mode 100644 icons/dialpad.tga create mode 100644 icons/download.tga create mode 100644 icons/files.tga create mode 100644 icons/flash.tga create mode 100644 icons/forward.tga create mode 100644 icons/gallery.tga create mode 100644 icons/game.tga create mode 100644 icons/heart.tga create mode 100644 icons/history.tga create mode 100644 icons/home.tga create mode 100644 icons/library.tga create mode 100644 icons/maps.tga create mode 100644 icons/menu.tga create mode 100644 icons/message.tga create mode 100644 icons/more.tga create mode 100644 icons/music.tga create mode 100644 icons/notes.tga create mode 100644 icons/phone.tga create mode 100644 icons/play.tga create mode 100644 icons/refresh.tga create mode 100644 icons/search.tga create mode 100644 icons/send.tga create mode 100644 icons/settings.tga create mode 100644 icons/signal.tga create mode 100644 icons/store.tga create mode 100644 icons/switch-camera.tga create mode 100644 icons/timer.tga create mode 100644 icons/weather.tga create mode 100644 icons/wifi.tga create mode 100644 scripts/layout.lua create mode 100644 scripts/navigation.lua create mode 100644 ui/components.rcss create mode 100644 ui/html.rcss create mode 100644 ui/layout.rcss create mode 100644 ui/theme.rcss diff --git a/.gitignore b/.gitignore index 319bcf5..7f5b060 100644 --- a/.gitignore +++ b/.gitignore @@ -17,10 +17,8 @@ test_*.log *_hierarchy.json recorded_actions.json -# Duplicate asset folders (use src/main/assets/ instead) -/icons/ -/scripts/ -/ui/ +# Note: /icons/, /scripts/, /ui/ at root are needed for base-apps testing +# They should be copies of src/main/assets/{icons,scripts,ui} # Sandbox data created during testing /src/main/assets/sandbox_data/ diff --git a/icons/account.tga b/icons/account.tga new file mode 100644 index 0000000..71e7f88 --- /dev/null +++ b/icons/account.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d06b26a0c072f57aef0ffaa4fc918766e6c6526213ca799d1e6d260be2a275e +size 9234 diff --git a/icons/add.tga b/icons/add.tga new file mode 100644 index 0000000..23a46f2 --- /dev/null +++ b/icons/add.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:161ad9d1947acdad2be332a7f1c760318554c3587aa51074aacde69e5e248e53 +size 9234 diff --git a/icons/back.tga b/icons/back.tga new file mode 100644 index 0000000..2f95b91 --- /dev/null +++ b/icons/back.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0dddba952a0ab45e5e10b9a12ed9010ee9ea42ca4880499a31ed9bb1491ade89 +size 9234 diff --git a/icons/backspace.tga b/icons/backspace.tga new file mode 100644 index 0000000..f7d4a34 --- /dev/null +++ b/icons/backspace.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d185f970b478e764760d2b02733bdad4563eb14e0feecd5fea5594bde8cc530 +size 9234 diff --git a/icons/battery.tga b/icons/battery.tga new file mode 100644 index 0000000..9dda0c2 --- /dev/null +++ b/icons/battery.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4d4ae61df2a0a020276a7bbd1e07d3951e1a336a4d0827a6b7723d61c1621cd +size 9234 diff --git a/icons/browser.tga b/icons/browser.tga new file mode 100644 index 0000000..8e24c73 --- /dev/null +++ b/icons/browser.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c197f9ea2b46366ce93921277914e61c88d464eec5114645d029f8922ad13ed9 +size 36882 diff --git a/icons/calculator.tga b/icons/calculator.tga new file mode 100644 index 0000000..8f3cd5a --- /dev/null +++ b/icons/calculator.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b26dd55dd906721eeb6aa1013f351245f14419d588b81c0f56aad77c8baeccd6 +size 36882 diff --git a/icons/calendar.tga b/icons/calendar.tga new file mode 100644 index 0000000..2e1b16f --- /dev/null +++ b/icons/calendar.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:496cd2a82e219fe451c0e709ec84c7fa80eb1f9c3f5c6c8718e9bffe6c93753b +size 36882 diff --git a/icons/call_small.tga b/icons/call_small.tga new file mode 100644 index 0000000..0e87324 --- /dev/null +++ b/icons/call_small.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97e1cd5ab2e73c8bd21cd9e0e9f01611a9ab17f369a54ef6b3ad45e9243c5b63 +size 9234 diff --git a/icons/camera.tga b/icons/camera.tga new file mode 100644 index 0000000..94eff75 --- /dev/null +++ b/icons/camera.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3bb3513d1cbb13bf808f4bb155f7d2f823307c0d12e100d367b23cfea0da1e5b +size 36882 diff --git a/icons/clock.tga b/icons/clock.tga new file mode 100644 index 0000000..69fa686 --- /dev/null +++ b/icons/clock.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f227c1b4c7fe680576cd2fb89060f758812948bdafa0cc3ca13b768d4ebed6ed +size 36882 diff --git a/icons/close.tga b/icons/close.tga new file mode 100644 index 0000000..ccb2ac2 --- /dev/null +++ b/icons/close.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62f858a08e9d05a621484d556045ab5ce829f7c487f082d136d788bd97861aec +size 9234 diff --git a/icons/contact_phone.tga b/icons/contact_phone.tga new file mode 100644 index 0000000..d6fa4d5 --- /dev/null +++ b/icons/contact_phone.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3a8b0cd6f02dd2a1d2231acfaeba6e46ab556b4f07123c0cfcee965c46c7b888 +size 9234 diff --git a/icons/contacts.tga b/icons/contacts.tga new file mode 100644 index 0000000..d6dd4f0 --- /dev/null +++ b/icons/contacts.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ac88f3429e34ebdcc44feeeb9474ca98dc01a0e6dd37d986a8daaf773efaa434 +size 36882 diff --git a/icons/dialpad.tga b/icons/dialpad.tga new file mode 100644 index 0000000..9694906 --- /dev/null +++ b/icons/dialpad.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce0e370125001136be86837642b237ba27394c78b01b9c9ce6d1e4f85320ef1b +size 9234 diff --git a/icons/download.tga b/icons/download.tga new file mode 100644 index 0000000..646d3f6 --- /dev/null +++ b/icons/download.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6ba618cfd901d45f2cc4ca1ca7951d489f75640db68bcbd49b7b44e27b9f5e2 +size 9234 diff --git a/icons/files.tga b/icons/files.tga new file mode 100644 index 0000000..18d4517 --- /dev/null +++ b/icons/files.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e66c03ebea19367a92190b6703e8745b7060fe7ee97f4accbaafde84d2879e0 +size 36882 diff --git a/icons/flash.tga b/icons/flash.tga new file mode 100644 index 0000000..691b0e0 --- /dev/null +++ b/icons/flash.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7b4f073aff4a6c7a3b553a19b8a9481344b97c356cf6d198d949d8e548942739 +size 9234 diff --git a/icons/forward.tga b/icons/forward.tga new file mode 100644 index 0000000..b8e6f89 --- /dev/null +++ b/icons/forward.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a1a8b3c8a754a0b43fa5738b534dec0245d73c8c381341cda9381a7b25f62fb +size 9234 diff --git a/icons/gallery.tga b/icons/gallery.tga new file mode 100644 index 0000000..8637963 --- /dev/null +++ b/icons/gallery.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c27fab4bc2ed6f757a22d1be78ddce0fcd8ffa6f4e854e0d5dfddb78a55718d6 +size 36882 diff --git a/icons/game.tga b/icons/game.tga new file mode 100644 index 0000000..93f5ecd --- /dev/null +++ b/icons/game.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea10844fa645a317801194d59d071d74563f1d561949f7f3ad7b4ab2fb935549 +size 9234 diff --git a/icons/heart.tga b/icons/heart.tga new file mode 100644 index 0000000..da61902 --- /dev/null +++ b/icons/heart.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eef94f67fd12188585fb3776220d72e976146f4186b0da38f53e09632bde61c3 +size 9234 diff --git a/icons/history.tga b/icons/history.tga new file mode 100644 index 0000000..202b8d5 --- /dev/null +++ b/icons/history.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:67e44ad050f6da50a833dab72a3aff58c3b8372e8e00a7315676b33c4c9e054f +size 9234 diff --git a/icons/home.tga b/icons/home.tga new file mode 100644 index 0000000..3ff78f0 --- /dev/null +++ b/icons/home.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:54c6a2b46e41b8e195c606ed96f02313574ff14c45e87fa076359494d1a6cd85 +size 9234 diff --git a/icons/library.tga b/icons/library.tga new file mode 100644 index 0000000..93bfb86 --- /dev/null +++ b/icons/library.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9f901748c8b65a67692fb4c18f6f04974191c25fb22685e0b7fe4b0b9101d9e +size 9234 diff --git a/icons/maps.tga b/icons/maps.tga new file mode 100644 index 0000000..4450877 --- /dev/null +++ b/icons/maps.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:010619d697b90a634a43fd9c011a4f6d7e47fb8bd3f753d320d16373d59664c0 +size 36882 diff --git a/icons/menu.tga b/icons/menu.tga new file mode 100644 index 0000000..f97f6ca --- /dev/null +++ b/icons/menu.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:affe25fb084638acff5e30b512144f42dadcca90080952a62b275f0b508d8f18 +size 9234 diff --git a/icons/message.tga b/icons/message.tga new file mode 100644 index 0000000..65a816c --- /dev/null +++ b/icons/message.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dbae2f2835d8788c7669256afb7c959fbfcdab75c4010efd19cb00e6ef88b983 +size 36882 diff --git a/icons/more.tga b/icons/more.tga new file mode 100644 index 0000000..ad2db04 --- /dev/null +++ b/icons/more.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85e174b65a12dadbae3db34c58e6c4b88b946a074ead948008fdbdf91960be8e +size 9234 diff --git a/icons/music.tga b/icons/music.tga new file mode 100644 index 0000000..3f01189 --- /dev/null +++ b/icons/music.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:107e15abf240a074709daa6b1b029c91c79e4f1a37164c12e597e3fa5681d878 +size 36882 diff --git a/icons/notes.tga b/icons/notes.tga new file mode 100644 index 0000000..ab1dcdb --- /dev/null +++ b/icons/notes.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9418a3c71ac8d5725181df6cbbef15068ab6b2da31686949492ee7c0ec5b5e67 +size 36882 diff --git a/icons/phone.tga b/icons/phone.tga new file mode 100644 index 0000000..95800ba --- /dev/null +++ b/icons/phone.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:faf243f7dfc3ea8c18c8dc46069857f977b638fd8f0f1f9bd6c1a0a6a7b68c52 +size 36882 diff --git a/icons/play.tga b/icons/play.tga new file mode 100644 index 0000000..2e0cfd0 --- /dev/null +++ b/icons/play.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:007531183043cdb419b3d3c95c2032f4895c1958df008c670ed5b476dbb92737 +size 9234 diff --git a/icons/refresh.tga b/icons/refresh.tga new file mode 100644 index 0000000..26840c5 --- /dev/null +++ b/icons/refresh.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6971909669c9b4885d6d7a47bb0d39578e9dd623d8db3a76a5471fa17471da89 +size 9234 diff --git a/icons/search.tga b/icons/search.tga new file mode 100644 index 0000000..fb2cd76 --- /dev/null +++ b/icons/search.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7aa9168b66c351d986788748d9773d12d271b756e49854e109d609d8d333e946 +size 9234 diff --git a/icons/send.tga b/icons/send.tga new file mode 100644 index 0000000..b98ac0b --- /dev/null +++ b/icons/send.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b1e30362c46f5b6933959f9810b99264f82a20f9ed26b02a0d28433af5befe01 +size 9234 diff --git a/icons/settings.tga b/icons/settings.tga new file mode 100644 index 0000000..92d123e --- /dev/null +++ b/icons/settings.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3cc46b65a5192de576b3ae018887eebd2f529fc7c4719c120c73dd7c780f63e2 +size 36882 diff --git a/icons/signal.tga b/icons/signal.tga new file mode 100644 index 0000000..ed6c007 --- /dev/null +++ b/icons/signal.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:23b5eee9afda355a4ef3166cb1e9ca582e161e7b4041bd0833ed24a8e1375276 +size 9234 diff --git a/icons/store.tga b/icons/store.tga new file mode 100644 index 0000000..234b90d --- /dev/null +++ b/icons/store.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19bc9956deed8379041a48fa0847b3b57c3627dcc5784c74e2af6a6a00b2ce73 +size 36882 diff --git a/icons/switch-camera.tga b/icons/switch-camera.tga new file mode 100644 index 0000000..1b6e09a --- /dev/null +++ b/icons/switch-camera.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:414ac737296e8da98f0b7fd04758919e89239037641ef0382b80a3df75a30a15 +size 9234 diff --git a/icons/timer.tga b/icons/timer.tga new file mode 100644 index 0000000..3d3c501 --- /dev/null +++ b/icons/timer.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a60b7132b69e4747a8071404c5b668ba641ae56d7a02c721cb8a8ecc7d3b591 +size 9234 diff --git a/icons/weather.tga b/icons/weather.tga new file mode 100644 index 0000000..3c153b2 --- /dev/null +++ b/icons/weather.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4def86b6b9b913a65eb9573fe5f2929ff2aca76d2faf88a3542f90ed4136ab1a +size 36882 diff --git a/icons/wifi.tga b/icons/wifi.tga new file mode 100644 index 0000000..c7cbdb6 --- /dev/null +++ b/icons/wifi.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0953efd8935e443e52e77efe38b20c4a4baaf5087bcf470a220cd12ee90b825 +size 9234 diff --git a/scripts/layout.lua b/scripts/layout.lua new file mode 100644 index 0000000..bedfde6 --- /dev/null +++ b/scripts/layout.lua @@ -0,0 +1,103 @@ +-- Layout System for Virtual Smartphone +-- Provides reusable UI component helpers +-- Requires navigation.lua to be loaded first + +-- Icon paths (relative to assets/) +local ICON_PATH = "../../icons/" + +-- Default icons +local icons = { + back = ICON_PATH .. "back.tga", + home = ICON_PATH .. "home.tga", + menu = ICON_PATH .. "menu.tga", + search = ICON_PATH .. "search.tga", + more = ICON_PATH .. "more.tga", + close = ICON_PATH .. "close.tga", + wifi = ICON_PATH .. "wifi.tga", + signal = ICON_PATH .. "signal.tga", + battery = ICON_PATH .. "battery.tga" +} + +-- Get current time formatted as HH:MM +local function getCurrentTime() + -- In sandbox, we might not have os.date, use a default + if os and os.date then + return os.date("%H:%M") + end + return "12:30" +end + +-- Update status bar time +function updateStatusTime(doc) + local timeEl = doc:GetElementById("status-time") + if timeEl then + timeEl.inner_rml = getCurrentTime() + end +end + +-- Initialize status bar with current time +-- Call from document onload +function initStatusBar(doc) + updateStatusTime(doc) + + -- Set up timer to update time every minute if timers are available + if setTimeout then + local function updateLoop() + updateStatusTime(doc) + setTimeout(updateLoop, 60000) + end + setTimeout(updateLoop, 60000) + end +end + +-- Initialize app bar back button +-- Call from document onload +function initAppBar(doc) + local backBtn = doc:GetElementById("app-bar-back") + if backBtn then + -- Back button is handled via onclick in RML + -- This is for any additional setup + end +end + +-- Initialize system navigation bar +-- Call from document onload +function initSystemNav(doc) + -- Navigation buttons are handled via onclick in RML + -- This is for any additional setup +end + +-- Full layout initialization +-- Call from document onload: initLayout(document) +function initLayout(doc) + initStatusBar(doc) + initAppBar(doc) + initSystemNav(doc) + print("Layout initialized") +end + +-- Handle back button press (for app bar or system nav) +function onBackPressed() + if canGoBack and canGoBack() then + goBack() + else + -- If at root, go home + if goHome then + goHome() + end + end +end + +-- Handle home button press +function onHomePressed() + if goHome then + goHome() + end +end + +-- Handle recent apps button press (placeholder) +function onRecentPressed() + print("Recent apps pressed (not implemented)") +end + +print("Layout system loaded") diff --git a/scripts/navigation.lua b/scripts/navigation.lua new file mode 100644 index 0000000..f5eb9ef --- /dev/null +++ b/scripts/navigation.lua @@ -0,0 +1,145 @@ +-- Navigation System for Virtual Smartphone +-- Handles screen transitions and state management + +-- Screen registry - maps screen names to RML file paths +local screens = { + home = "apps/home/home.rml", + lock = "apps/home/lock.rml", + dialer = "apps/dialer/dialer.rml", + calling = "apps/dialer/calling.rml", + contacts = "apps/contacts/contacts.rml", + contact_detail = "apps/contacts/contact_detail.rml", + messages = "apps/messages/messages.rml", + chat = "apps/messages/chat.rml", + settings = "apps/settings/settings.rml", + browser = "apps/browser/browser.rml", + store = "apps/store/store.rml", + camera = "apps/camera/camera.rml", + music = "apps/music/music.rml" +} + +-- Use global state to persist across document loads +-- Initialize only if not already set +if not _G.nav_state then + _G.nav_state = { + history = {}, + current_screen = "home", + nav_direction = "none" -- "forward", "back", "home", "none" + } +end + +-- Local references for convenience +local history = _G.nav_state.history +local function get_current() return _G.nav_state.current_screen end +local function set_current(s) _G.nav_state.current_screen = s end +local function get_direction() return _G.nav_state.nav_direction end +local function set_direction(d) _G.nav_state.nav_direction = d end + +-- Apply animation class based on navigation direction +local function applyNavAnimation() + local dir = get_direction() + print("Applying animation, direction: " .. dir) + if dir ~= "none" and document then + -- In RmlUi Lua, get body element + local body = document.body + if body then + print("Found body element, setting class nav-" .. dir) + -- Set the appropriate animation class + if dir == "forward" then + body:SetClass("nav-forward", true) + elseif dir == "back" then + body:SetClass("nav-back", true) + elseif dir == "home" then + body:SetClass("nav-home", true) + else + body:SetClass("nav-default", true) + end + else + print("Body element not found!") + end + end +end + +-- Navigate to a screen by name +function navigateTo(screen_name) + print("navigateTo called with: " .. tostring(screen_name)) + local path = screens[screen_name] + if path then + -- Push current screen to history before navigating + table.insert(history, get_current()) + set_current(screen_name) + set_direction("forward") + + -- Load the new screen using C++ function + local success = loadScreen(path) + if success then + applyNavAnimation() + print("Navigated to: " .. screen_name .. " (history depth: " .. #history .. ")") + else + -- Restore previous state on failure + set_current(table.remove(history)) + print("Failed to navigate to: " .. screen_name) + end + return success + else + print("Unknown screen: " .. screen_name) + return false + end +end + +-- Go back to previous screen +function goBack() + print("goBack called (history depth: " .. #history .. ")") + if #history > 0 then + local previous = table.remove(history) + local path = screens[previous] + if path then + set_current(previous) + set_direction("back") + loadScreen(path) + applyNavAnimation() + print("Back to: " .. previous) + return true + end + else + print("No history to go back to") + end + return false +end + +-- Go to home screen (clear history) +function goHome() + -- Clear the history table + for i = #history, 1, -1 do + history[i] = nil + end + set_current("home") + set_direction("home") + loadScreen(screens.home) + applyNavAnimation() + print("Navigated to home") +end + +-- Get current screen name +function getCurrentScreen() + return get_current() +end + +-- Check if we can go back +function canGoBack() + return #history > 0 +end + +-- Clear navigation history +function clearHistory() + for i = #history, 1, -1 do + history[i] = nil + end +end + +-- Get history depth +function getHistoryDepth() + return #history +end + +print("Navigation system initialized (current: " .. get_current() .. ", history: " .. #history .. ")") diff --git a/ui/components.rcss b/ui/components.rcss new file mode 100644 index 0000000..87a9d45 --- /dev/null +++ b/ui/components.rcss @@ -0,0 +1,1485 @@ +/* ============================================== + Components: Material UI Components (VR Optimized) + All sizes increased for VR readability and raycast interaction + All interactive elements have hover/active states + ============================================== */ + +/* ============== Status Bar (VR-sized) ============== */ + +.status-bar { + height: 36px; + padding: 0 16px; + background-color: transparent; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 16px; + color: #FFFFFF; +} + +.status-bar-time { + font-weight: 500; +} + +.status-bar-icons { + display: flex; + gap: 8px; +} + +/* ============== App Bar (VR-sized) ============== */ + +.app-bar { + height: 72px; + padding: 0 16px; + background-color: #1E1E1E; + display: flex; + align-items: center; +} + +.app-bar-nav { + width: 56px; + height: 56px; + display: flex; + align-items: center; + justify-content: center; + margin-right: 12px; + cursor: pointer; + border-radius: 28px; +} + +.app-bar-nav:hover { + background-color: rgba(255, 255, 255, 0.1); +} + +.app-bar-nav:active { + background-color: rgba(255, 255, 255, 0.2); +} + +.app-bar-title { + font-size: 26px; + font-weight: 500; + flex: 1; + color: #FFFFFF; +} + +.app-bar-actions { + display: flex; + gap: 8px; +} + +/* ============== Buttons (VR-sized) ============== */ + +.btn { + padding: 16px 32px; + font-size: 18px; + font-weight: 500; + font-family: LatoLatin; + text-align: center; + border-radius: 8px; + cursor: pointer; + min-height: 56px; +} + +.btn:hover { + opacity: 0.9; +} + +.btn:active { + opacity: 0.8; +} + +.btn-primary { + background-color: #BB86FC; + color: #000000; +} + +.btn-primary:hover { + background-color: #D4A5FF; +} + +.btn-primary:active { + background-color: #9A67EA; +} + +.btn-secondary { + background-color: #03DAC6; + color: #000000; +} + +.btn-secondary:hover { + background-color: #4AEADB; +} + +.btn-secondary:active { + background-color: #00B3A1; +} + +.btn-outlined { + background-color: transparent; + color: #BB86FC; +} + +.btn-outlined:hover { + background-color: rgba(187, 134, 252, 0.15); +} + +.btn-outlined:active { + background-color: rgba(187, 134, 252, 0.25); +} + +.btn-text { + background-color: transparent; + color: #BB86FC; + padding: 12px 20px; +} + +.btn-text:hover { + background-color: rgba(187, 134, 252, 0.1); +} + +.btn-text:active { + background-color: rgba(187, 134, 252, 0.2); +} + +/* Icon Button (VR-sized - larger touch target) */ +.btn-icon { + width: 64px; + height: 64px; + padding: 0; + border-radius: 32px; + background-color: transparent; + display: flex; + align-items: center; + justify-content: center; + font-size: 28px; + cursor: pointer; +} + +.btn-icon:hover { + background-color: rgba(255, 255, 255, 0.12); +} + +.btn-icon:active { + background-color: rgba(255, 255, 255, 0.2); +} + +/* Floating Action Button (VR-sized) */ +.btn-fab { + width: 72px; + height: 72px; + border-radius: 36px; + background-color: #BB86FC; + color: #000000; + display: flex; + align-items: center; + justify-content: center; + font-size: 32px; + position: absolute; + bottom: 100px; + right: 20px; + cursor: pointer; +} + +.btn-fab:hover { + background-color: #D4A5FF; + transform: scale(1.05); +} + +.btn-fab:active { + background-color: #9A67EA; + transform: scale(0.95); +} + +/* ============== Input Fields (VR-sized) ============== */ + +.input-container { + margin-bottom: 20px; +} + +.input-label { + font-size: 16px; + color: #B3B3B3; + margin-bottom: 8px; +} + +.input-field { + width: 100%; + padding: 16px 0; + font-size: 20px; + font-family: LatoLatin; + color: #FFFFFF; + background-color: transparent; + border-bottom-width: 2px; + border-bottom-color: #333333; +} + +.input-field:focus { + border-bottom-color: #BB86FC; +} + +.input-field:hover { + border-bottom-color: #666666; +} + +/* Search Input (VR-sized) */ +.search-bar { + display: flex; + align-items: center; + padding: 14px 20px; + background-color: #2D2D2D; + border-radius: 32px; + margin: 12px 16px; + cursor: pointer; +} + +.search-bar:hover { + background-color: #3D3D3D; +} + +.search-icon { + font-size: 24px; + color: #B3B3B3; + margin-right: 16px; +} + +.search-input { + flex: 1; + background-color: transparent; + font-size: 20px; + color: #FFFFFF; +} + +/* ============== Cards (VR-sized) ============== */ + +.card { + background-color: #1E1E1E; + border-radius: 12px; + padding: 20px; + margin: 12px; + cursor: pointer; +} + +.card:hover { + background-color: #252525; +} + +.card:active { + background-color: #2A2A2A; +} + +.card-elevated { + background-color: #2D2D2D; +} + +.card-elevated:hover { + background-color: #353535; +} + +.card-header { + font-size: 24px; + font-weight: 500; + margin-bottom: 10px; + color: #FFFFFF; +} + +.card-subtitle { + font-size: 18px; + color: #B3B3B3; + margin-bottom: 16px; +} + +.card-content { + font-size: 18px; + color: #B3B3B3; +} + +.card-actions { + display: flex; + justify-content: flex-end; + margin-top: 20px; + gap: 12px; +} + +/* ============== Lists (VR-sized) ============== */ + +.list { + display: flex; + flex-direction: column; +} + +.list-item { + display: flex; + align-items: center; + padding: 16px 20px; + min-height: 72px; + cursor: pointer; +} + +.list-item:hover { + background-color: rgba(255, 255, 255, 0.08); +} + +.list-item:active { + background-color: rgba(255, 255, 255, 0.15); +} + +.list-item-avatar { + width: 56px; + height: 56px; + border-radius: 28px; + background-color: #BB86FC; + margin-right: 20px; + display: flex; + align-items: center; + justify-content: center; + font-size: 24px; + color: #000000; +} + +.list-item-icon { + width: 56px; + height: 56px; + margin-right: 20px; + display: flex; + align-items: center; + justify-content: center; + font-size: 28px; + color: #B3B3B3; +} + +.list-item-content { + flex: 1; + display: flex; + flex-direction: column; +} + +.list-item-title { + font-size: 20px; + color: #FFFFFF; +} + +.list-item-subtitle { + font-size: 16px; + color: #B3B3B3; + margin-top: 4px; +} + +.list-item-action { + font-size: 28px; + color: #666666; + cursor: pointer; +} + +.list-item-action:hover { + color: #FFFFFF; +} + +.list-divider { + height: 1px; + background-color: #333333; + margin-left: 96px; +} + +.list-header { + padding: 20px 20px 12px 20px; + font-size: 18px; + font-weight: 500; + color: #BB86FC; +} + +/* ============== Bottom Navigation (VR-sized) ============== */ + +.bottom-nav { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 72px; + background-color: #1E1E1E; + display: flex; +} + +.bottom-nav-item { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + color: #666666; +} + +.bottom-nav-item:hover { + color: #B3B3B3; + background-color: rgba(255, 255, 255, 0.05); +} + +.bottom-nav-item:active { + background-color: rgba(255, 255, 255, 0.1); +} + +.bottom-nav-item.active { + color: #BB86FC; +} + +.bottom-nav-item.active:hover { + color: #D4A5FF; +} + +.bottom-nav-icon { + font-size: 28px; + margin-bottom: 6px; +} + +.bottom-nav-label { + font-size: 14px; +} + +/* ============== Dialogs/Modals (VR-sized) ============== */ + +.modal-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.7); + display: flex; + align-items: center; + justify-content: center; +} + +.modal-dialog { + background-color: #2D2D2D; + border-radius: 16px; + padding: 32px; + width: 360px; + max-width: 90%; +} + +.modal-title { + font-size: 26px; + font-weight: 500; + color: #FFFFFF; + margin-bottom: 20px; +} + +.modal-content { + font-size: 18px; + color: #B3B3B3; + margin-bottom: 32px; +} + +.modal-actions { + display: flex; + justify-content: flex-end; + gap: 12px; +} + +/* ============== Toast/Snackbar (VR-sized) ============== */ + +.toast { + position: absolute; + bottom: 100px; + left: 20px; + right: 20px; + background-color: #323232; + color: #FFFFFF; + padding: 20px 24px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 18px; +} + +.toast-action { + color: #BB86FC; + font-weight: 500; + margin-left: 20px; + cursor: pointer; +} + +.toast-action:hover { + color: #D4A5FF; +} + +/* ============== Toggle/Switch (VR-sized) ============== */ + +.toggle { + width: 52px; + height: 32px; + border-radius: 16px; + background-color: #666666; + position: relative; + cursor: pointer; +} + +.toggle:hover { + background-color: #777777; +} + +.toggle.active { + background-color: rgba(187, 134, 252, 0.5); +} + +.toggle.active:hover { + background-color: rgba(187, 134, 252, 0.6); +} + +.toggle-thumb { + width: 24px; + height: 24px; + border-radius: 12px; + background-color: #B3B3B3; + position: absolute; + top: 4px; + left: 4px; +} + +.toggle.active .toggle-thumb { + background-color: #BB86FC; + left: 24px; +} + +/* ============== Chips/Tags (VR-sized) ============== */ + +.chip { + display: inline-flex; + align-items: center; + padding: 10px 18px; + background-color: #2D2D2D; + border-radius: 24px; + font-size: 18px; + color: #FFFFFF; + margin: 6px; + cursor: pointer; +} + +.chip:hover { + background-color: #3D3D3D; +} + +.chip:active { + background-color: #454545; +} + +.chip.active { + background-color: #BB86FC; + color: #000000; +} + +.chip.active:hover { + background-color: #D4A5FF; +} + +.chip-icon { + margin-right: 10px; +} + +.chip-delete { + margin-left: 10px; + font-size: 22px; + color: #B3B3B3; + cursor: pointer; +} + +.chip-delete:hover { + color: #FFFFFF; +} + +/* ============== Dividers ============== */ + +.divider { + height: 1px; + background-color: #333333; +} + +.divider-inset { + margin-left: 96px; +} + +/* ============== App Grid (Home Screen - VR-sized) ============== */ + +.app-grid { + display: flex; + flex-wrap: wrap; + padding: 20px; +} + +.app-icon { + width: 25%; + display: flex; + flex-direction: column; + align-items: center; + padding: 16px 0; + cursor: pointer; + border-radius: 12px; +} + +.app-icon:hover { + background-color: rgba(255, 255, 255, 0.08); +} + +.app-icon:active { + background-color: rgba(255, 255, 255, 0.15); +} + +.app-icon-image { + width: 72px; + height: 72px; + border-radius: 18px; + background-color: #BB86FC; + display: flex; + align-items: center; + justify-content: center; + font-size: 32px; + color: #000000; + margin-bottom: 12px; +} + +.app-icon-image:hover { + transform: scale(1.05); +} + +.app-icon-label { + font-size: 16px; + color: #FFFFFF; + text-align: center; +} + +/* ============== Dock (VR-sized) ============== */ + +.dock { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 100px; + background-color: rgba(30, 30, 30, 0.95); + display: flex; + justify-content: space-around; + align-items: center; + padding: 0 40px; +} + +.dock-item { + width: 72px; + height: 72px; + border-radius: 18px; + background-color: #BB86FC; + display: flex; + align-items: center; + justify-content: center; + font-size: 36px; + color: #000000; + cursor: pointer; +} + +.dock-item:hover { + transform: scale(1.1); + background-color: #D4A5FF; +} + +.dock-item:active { + transform: scale(0.95); + background-color: #9A67EA; +} + +/* ============== Dial Pad (VR-sized) ============== */ + +.dial-pad { + display: flex; + flex-wrap: wrap; + padding: 20px; +} + +.dial-key { + width: 33.33%; + height: 96px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 48px; +} + +.dial-key:hover { + background-color: rgba(255, 255, 255, 0.12); +} + +.dial-key:active { + background-color: rgba(255, 255, 255, 0.2); +} + +.dial-key-number { + font-size: 42px; + font-weight: 300; + color: #FFFFFF; +} + +.dial-key-letters { + font-size: 14px; + color: #B3B3B3; + letter-spacing: 3px; + margin-top: 4px; +} + +.dial-display { + font-size: 48px; + font-weight: 300; + color: #FFFFFF; + text-align: center; + padding: 32px 20px; + letter-spacing: 3px; +} + +.dial-actions { + display: flex; + justify-content: center; + padding: 20px; + gap: 64px; +} + +.dial-call-btn { + width: 80px; + height: 80px; + border-radius: 40px; + background-color: #4CAF50; + display: flex; + align-items: center; + justify-content: center; + font-size: 36px; + color: #FFFFFF; + cursor: pointer; +} + +.dial-call-btn:hover { + background-color: #66BB6A; + transform: scale(1.05); +} + +.dial-call-btn:active { + background-color: #43A047; + transform: scale(0.95); +} + +/* ============== Chat Bubbles (VR-sized) ============== */ + +.chat-container { + display: flex; + flex-direction: column; + padding: 20px; + gap: 12px; +} + +.chat-bubble { + max-width: 75%; + padding: 14px 20px; + border-radius: 24px; + font-size: 18px; +} + +.chat-bubble-sent { + align-self: flex-end; + background-color: #BB86FC; + color: #000000; + border-bottom-right-radius: 6px; +} + +.chat-bubble-received { + align-self: flex-start; + background-color: #2D2D2D; + color: #FFFFFF; + border-bottom-left-radius: 6px; +} + +.chat-timestamp { + font-size: 14px; + color: #666666; + text-align: center; + margin: 12px 0; +} + +.chat-input-container { + display: flex; + align-items: center; + padding: 12px 20px; + background-color: #1E1E1E; +} + +.chat-input { + flex: 1; + padding: 14px 20px; + background-color: #2D2D2D; + border-radius: 32px; + font-size: 18px; + color: #FFFFFF; + margin-right: 12px; +} + +.chat-input:hover { + background-color: #3D3D3D; +} + +.chat-input:focus { + background-color: #353535; +} + +.chat-send-btn { + width: 56px; + height: 56px; + border-radius: 28px; + background-color: #BB86FC; + display: flex; + align-items: center; + justify-content: center; + font-size: 28px; + color: #000000; + cursor: pointer; +} + +.chat-send-btn:hover { + background-color: #D4A5FF; + transform: scale(1.05); +} + +.chat-send-btn:active { + background-color: #9A67EA; + transform: scale(0.95); +} + +/* ============== Section Headers (VR-sized) ============== */ + +.section-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 24px 20px 16px 20px; +} + +.section-title { + font-size: 24px; + font-weight: 600; + color: #FFFFFF; +} + +.section-action { + font-size: 16px; + font-weight: 600; + color: #B3B3B3; + cursor: pointer; +} + +.section-action:hover { + color: #FFFFFF; +} + +/* ============== Navigation Item (VR-sized) ============== */ + +.nav-item { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + color: #B3B3B3; + padding: 12px; +} + +.nav-item:hover { + background-color: rgba(255, 255, 255, 0.05); +} + +.nav-item:active { + background-color: rgba(255, 255, 255, 0.1); +} + +.nav-item.active { + color: #FFFFFF; +} + +.nav-item img { + width: 32px; + height: 32px; + margin-bottom: 6px; +} + +.nav-item span { + font-size: 14px; +} + +/* ============== Quick Cards (VR-sized) ============== */ + +.quick-card { + display: flex; + align-items: center; + background-color: #282828; + border-radius: 8px; + padding: 0; + height: 72px; + overflow: hidden; + cursor: pointer; +} + +.quick-card:hover { + background-color: #353535; +} + +.quick-card:active { + background-color: #3D3D3D; +} + +.quick-card-art { + width: 72px; + height: 72px; + display: flex; + align-items: center; + justify-content: center; + font-size: 28px; + color: #FFFFFF; +} + +.quick-card-title { + font-size: 17px; + font-weight: 600; + color: #FFFFFF; + padding: 0 16px; +} + +/* ============== Recent/Playlist Items (VR-sized) ============== */ + +.recent-item { + min-width: 160px; + cursor: pointer; + padding: 8px; + border-radius: 8px; +} + +.recent-item:hover { + background-color: rgba(255, 255, 255, 0.05); +} + +.recent-art { + width: 160px; + height: 160px; + border-radius: 12px; + margin-bottom: 16px; + display: flex; + align-items: center; + justify-content: center; + font-size: 52px; + color: #FFFFFF; +} + +.recent-title { + font-size: 18px; + color: #FFFFFF; + font-weight: 500; + margin-bottom: 6px; +} + +.recent-subtitle { + font-size: 16px; + color: #B3B3B3; +} + +.playlist-item { + display: flex; + align-items: center; + padding: 16px 20px; + cursor: pointer; +} + +.playlist-item:hover { + background-color: rgba(255, 255, 255, 0.05); +} + +.playlist-item:active { + background-color: rgba(255, 255, 255, 0.1); +} + +.playlist-art { + width: 72px; + height: 72px; + border-radius: 8px; + margin-right: 16px; + display: flex; + align-items: center; + justify-content: center; + font-size: 28px; + color: #FFFFFF; +} + +.playlist-info { + flex: 1; +} + +.playlist-title { + font-size: 20px; + color: #FFFFFF; + font-weight: 500; +} + +.playlist-meta { + font-size: 16px; + color: #B3B3B3; + margin-top: 6px; +} + +/* ============== Mini Player (VR-sized) ============== */ + +.mini-player { + display: flex; + align-items: center; + padding: 12px 20px; + background-color: #282828; +} + +.mini-player-art { + width: 64px; + height: 64px; + border-radius: 8px; + background-color: #667eea; + margin-right: 16px; + display: flex; + align-items: center; + justify-content: center; + font-size: 28px; + color: #FFFFFF; +} + +.mini-player-info { + flex: 1; +} + +.mini-player-title { + font-size: 18px; + color: #FFFFFF; + font-weight: 500; +} + +.mini-player-artist { + font-size: 16px; + color: #B3B3B3; + margin-top: 4px; +} + +.mini-player-controls { + display: flex; + gap: 12px; +} + +.mini-control-btn { + width: 56px; + height: 56px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 28px; +} + +.mini-control-btn:hover { + background-color: rgba(255, 255, 255, 0.1); +} + +.mini-control-btn:active { + background-color: rgba(255, 255, 255, 0.2); +} + +.mini-control-btn img { + width: 32px; + height: 32px; +} + +/* ============== Camera Controls (VR-sized) ============== */ + +.camera-btn { + width: 56px; + height: 56px; + border-radius: 28px; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; +} + +.camera-btn:hover { + background-color: rgba(255, 255, 255, 0.25); +} + +.camera-btn:active { + background-color: rgba(255, 255, 255, 0.35); +} + +.camera-btn img { + width: 32px; + height: 32px; +} + +.camera-mode { + font-size: 18px; + color: #B3B3B3; + cursor: pointer; + padding: 12px; + border-radius: 8px; +} + +.camera-mode:hover { + background-color: rgba(255, 255, 255, 0.1); + color: #FFFFFF; +} + +.camera-mode.active { + color: #FFD700; + font-weight: 600; +} + +.capture-btn { + width: 88px; + height: 88px; + border-radius: 44px; + background-color: #FFFFFF; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; +} + +.capture-btn:hover { + transform: scale(1.05); +} + +.capture-btn:active { + transform: scale(0.95); + background-color: #E0E0E0; +} + +.switch-camera-btn { + width: 64px; + height: 64px; + border-radius: 32px; + background-color: rgba(255, 255, 255, 0.25); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; +} + +.switch-camera-btn:hover { + background-color: rgba(255, 255, 255, 0.35); +} + +.switch-camera-btn:active { + background-color: rgba(255, 255, 255, 0.45); +} + +.switch-camera-btn img { + width: 32px; + height: 32px; +} + +.gallery-preview { + width: 64px; + height: 64px; + border-radius: 12px; + background-color: #333333; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; +} + +.gallery-preview:hover { + background-color: #444444; +} + +.gallery-preview img { + width: 32px; + height: 32px; + opacity: 0.8; +} + +.zoom-btn { + width: 44px; + height: 44px; + border-radius: 22px; + background-color: rgba(0, 0, 0, 0.6); + display: flex; + align-items: center; + justify-content: center; + font-size: 24px; + color: #FFFFFF; + cursor: pointer; +} + +.zoom-btn:hover { + background-color: rgba(255, 255, 255, 0.2); +} + +/* ============== Store Components (VR-sized) ============== */ + +.app-card { + min-width: 180px; + background-color: #1E1E1E; + border-radius: 16px; + padding: 16px; + cursor: pointer; +} + +.app-card:hover { + background-color: #2A2A2A; +} + +.app-card:active { + background-color: #303030; +} + +.app-card-icon { + width: 80px; + height: 80px; + border-radius: 20px; + margin-bottom: 16px; + display: flex; + align-items: center; + justify-content: center; + font-size: 36px; + color: #000000; +} + +.app-card-name { + font-size: 18px; + font-weight: 500; + color: #FFFFFF; + margin-bottom: 6px; +} + +.app-card-category { + font-size: 16px; + color: #B3B3B3; + margin-bottom: 10px; +} + +.app-card-rating { + display: flex; + align-items: center; + font-size: 16px; + color: #B3B3B3; +} + +.app-list-item { + display: flex; + align-items: center; + padding: 16px 20px; + cursor: pointer; +} + +.app-list-item:hover { + background-color: rgba(255, 255, 255, 0.05); +} + +.app-list-item:active { + background-color: rgba(255, 255, 255, 0.1); +} + +.app-list-icon { + width: 72px; + height: 72px; + border-radius: 16px; + margin-right: 20px; + display: flex; + align-items: center; + justify-content: center; + font-size: 32px; + color: #000000; +} + +.app-list-info { + flex: 1; +} + +.app-list-name { + font-size: 20px; + font-weight: 500; + color: #FFFFFF; +} + +.app-list-meta { + font-size: 16px; + color: #B3B3B3; + margin-top: 4px; +} + +.app-list-rating { + display: flex; + align-items: center; + margin-top: 6px; +} + +.app-list-rating span { + font-size: 16px; + color: #B3B3B3; +} + +.install-btn { + background-color: #BB86FC; + color: #000000; + font-size: 16px; + font-weight: 600; + padding: 12px 28px; + border-radius: 24px; + cursor: pointer; +} + +.install-btn:hover { + background-color: #D4A5FF; +} + +.install-btn:active { + background-color: #9A67EA; +} + +.install-btn.installed { + background-color: transparent; + color: #BB86FC; +} + +.install-btn.installed:hover { + background-color: rgba(187, 134, 252, 0.15); +} + +.category-chip { + background-color: #2D2D2D; + color: #FFFFFF; + font-size: 18px; + padding: 12px 24px; + border-radius: 24px; + white-space: nowrap; + cursor: pointer; +} + +.category-chip:hover { + background-color: #3D3D3D; +} + +.category-chip.active { + background-color: #BB86FC; + color: #000000; +} + +.category-chip.active:hover { + background-color: #D4A5FF; +} + +/* ============== Featured Banner (VR-sized) ============== */ + +.featured-banner { + margin: 0 20px 20px 20px; + height: 200px; + background-color: #6200EE; + border-radius: 20px; + padding: 28px; + display: flex; + flex-direction: column; + justify-content: flex-end; + cursor: pointer; +} + +.featured-banner:hover { + opacity: 0.95; +} + +.featured-tag { + font-size: 14px; + color: rgba(255,255,255,0.7); + text-transform: uppercase; + margin-bottom: 10px; +} + +.featured-title { + font-size: 32px; + font-weight: 600; + color: #FFFFFF; + margin-bottom: 6px; +} + +.featured-subtitle { + font-size: 18px; + color: rgba(255,255,255,0.8); +} + +/* ============== Store Search (VR-sized) ============== */ + +.store-search { + margin: 20px; + background-color: #2D2D2D; + border-radius: 32px; + padding: 16px 24px; + display: flex; + align-items: center; + cursor: pointer; +} + +.store-search:hover { + background-color: #3D3D3D; +} + +.store-search img { + width: 28px; + height: 28px; + margin-right: 16px; + opacity: 0.6; +} + +.store-search-text { + font-size: 20px; + color: #B3B3B3; +} + +/* ============== Store Navigation (VR-sized) ============== */ + +.store-bottom-nav { + display: flex; + height: 72px; + background-color: #1E1E1E; +} + +.store-nav-item { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + color: #B3B3B3; +} + +.store-nav-item:hover { + background-color: rgba(255, 255, 255, 0.05); +} + +.store-nav-item.active { + color: #BB86FC; +} + +.store-nav-item img { + width: 32px; + height: 32px; + margin-bottom: 6px; +} + +.store-nav-item span { + font-size: 14px; +} + +/* ============== Music Navigation (VR-sized) ============== */ + +.music-bottom-nav { + display: flex; + height: 72px; + background-color: #1E1E1E; +} diff --git a/ui/html.rcss b/ui/html.rcss new file mode 100644 index 0000000..ac19961 --- /dev/null +++ b/ui/html.rcss @@ -0,0 +1,93 @@ +body, div, +h1, h2, h3, h4, +h5, h6, p, +hr, pre, +tabset tabs +{ + display: block; +} + +h1 +{ + font-size: 2em; + margin: .67em 0; +} + +h2 +{ + font-size: 1.5em; + margin: .75em 0; +} + +h3 +{ + font-size: 1.17em; + margin: .83em 0; +} + +h4, p +{ + margin: 1.12em 0; +} + +h5 +{ + font-size: .83em; + margin: 1.5em 0; +} + +h6 +{ + font-size: .75em; + margin: 1.67em 0; +} + +h1, h2, h3, h4, +h5, h6, strong +{ + font-weight: bold; +} + +em +{ + font-style: italic; +} + +pre +{ + white-space: pre; +} + +hr +{ + border-width: 1px; +} + +table +{ + box-sizing: border-box; + display: table; +} +tr +{ + box-sizing: border-box; + display: table-row; +} +td +{ + box-sizing: border-box; + display: table-cell; +} +col +{ + box-sizing: border-box; + display: table-column; +} +colgroup +{ + display: table-column-group; +} +thead, tbody, tfoot +{ + display: table-row-group; +} diff --git a/ui/layout.rcss b/ui/layout.rcss new file mode 100644 index 0000000..edf6ad9 --- /dev/null +++ b/ui/layout.rcss @@ -0,0 +1,270 @@ +/* ============================================== + Layout Components: Reusable App Layout Structure + System status bar, app bar, navigation bar + ============================================== */ + +/* ============== System Status Bar ============== */ +/* Top bar showing time, signal, wifi, battery */ + +.system-status-bar { + height: 36px; + padding: 0 16px; + background-color: transparent; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 16px; + color: #FFFFFF; + z-index: 1000; +} + +.system-status-bar.bg-surface { + background-color: #1E1E1E; +} + +.system-status-time { + font-weight: 500; + font-size: 16px; +} + +.system-status-icons { + display: flex; + gap: 8px; + align-items: center; +} + +.system-status-icons img { + width: 24px; + height: 24px; + pointer-events: none; +} + +/* ============== App Bar ============== */ +/* Title bar with back button and optional actions */ + +.app-bar { + height: 72px; + padding: 0 8px; + background-color: #1E1E1E; + display: flex; + align-items: center; + z-index: 900; +} + +.app-bar.transparent { + background-color: transparent; +} + +.app-bar.primary { + background-color: #121212; +} + +.app-bar-back { + width: 56px; + height: 56px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 28px; +} + +.app-bar-back:hover { + background-color: rgba(255, 255, 255, 0.1); +} + +.app-bar-back:active { + background-color: rgba(255, 255, 255, 0.2); +} + +.app-bar-back img { + width: 32px; + height: 32px; + pointer-events: none; +} + +.app-bar-title { + flex: 1; + font-size: 24px; + font-weight: 500; + color: #FFFFFF; + padding-left: 8px; +} + +.app-bar-actions { + display: flex; + gap: 4px; +} + +.app-bar-action { + width: 56px; + height: 56px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 28px; +} + +.app-bar-action:hover { + background-color: rgba(255, 255, 255, 0.1); +} + +.app-bar-action:active { + background-color: rgba(255, 255, 255, 0.2); +} + +.app-bar-action img { + width: 28px; + height: 28px; + pointer-events: none; +} + +/* ============== System Navigation Bar ============== */ +/* Bottom bar with back, home, and recent buttons */ + +.system-nav-bar { + height: 56px; + background-color: #0A0A0A; + display: flex; + align-items: center; + justify-content: space-around; + z-index: 1000; +} + +.system-nav-bar.transparent { + background-color: rgba(10, 10, 10, 0.9); +} + +.system-nav-btn { + width: 72px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 24px; +} + +.system-nav-btn:hover { + background-color: rgba(255, 255, 255, 0.1); +} + +.system-nav-btn:active { + background-color: rgba(255, 255, 255, 0.2); +} + +.system-nav-btn img { + width: 28px; + height: 28px; + pointer-events: none; + opacity: 0.8; +} + +/* Home button - pill shape */ +.system-nav-home { + width: 96px; + height: 8px; + background-color: #FFFFFF; + border-radius: 4px; + cursor: pointer; + opacity: 0.6; +} + +.system-nav-home:hover { + opacity: 0.8; +} + +.system-nav-home:active { + opacity: 1.0; +} + +/* ============== Screen Layout ============== */ +/* Standard app screen structure */ + +.app-screen { + width: 100%; + height: 100%; + background-color: #121212; + display: flex; + flex-direction: column; +} + +.app-content { + flex: 1; + overflow: auto; + display: flex; + flex-direction: column; +} + +/* Content padding for nav bar */ +.app-content.with-nav { + padding-bottom: 56px; +} + +/* Content padding for dock */ +.app-content.with-dock { + padding-bottom: 100px; +} + +/* ============== Combined Header ============== */ +/* Status bar + App bar combined */ + +.app-header { + display: flex; + flex-direction: column; + background-color: #1E1E1E; +} + +.app-header.transparent { + background-color: transparent; +} + +.app-header .system-status-bar { + background-color: transparent; +} + +/* ============== Notification Badge ============== */ + +.notification-badge { + position: absolute; + top: 8px; + right: 8px; + min-width: 20px; + height: 20px; + background-color: #CF6679; + border-radius: 10px; + font-size: 12px; + font-weight: 600; + color: #FFFFFF; + display: flex; + align-items: center; + justify-content: center; + padding: 0 6px; +} + +/* ============== Recording Indicator ============== */ +/* Shown when camera/mic is active */ + +.recording-indicator { + position: absolute; + top: 8px; + right: 8px; + width: 12px; + height: 12px; + background-color: #F44336; + border-radius: 6px; + animation: recording-pulse 1.5s ease-in-out infinite; +} + +@keyframes recording-pulse { + 0%, 100% { opacity: 1.0; } + 50% { opacity: 0.4; } +} + +/* ============== Divider ============== */ + +.header-divider { + height: 1px; + background-color: #333333; +} diff --git a/ui/theme.rcss b/ui/theme.rcss new file mode 100644 index 0000000..43aab1b --- /dev/null +++ b/ui/theme.rcss @@ -0,0 +1,333 @@ +/* ============================================== + Theme: Material Dark for Virtual Smartphone (VR Optimized) + All sizes increased for VR readability and raycast interaction + ============================================== */ + +/* Base body styling */ +body { + font-family: LatoLatin; + background-color: #121212; + color: #FFFFFF; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + animation: 0.2s cubic-out fade-in; +} + +/* ============== Typography (VR-sized) ============== */ + +.text-h1 { + font-size: 120px; + font-weight: 300; +} + +.text-h2 { + font-size: 80px; + font-weight: 300; +} + +.text-h3 { + font-size: 64px; + font-weight: 400; +} + +.text-h4 { + font-size: 48px; + font-weight: 400; +} + +.text-h5 { + font-size: 32px; + font-weight: 400; +} + +.text-h6 { + font-size: 28px; + font-weight: 500; +} + +.text-body1 { + font-size: 22px; + font-weight: 400; +} + +.text-body2 { + font-size: 18px; + font-weight: 400; +} + +.text-caption { + font-size: 16px; + font-weight: 400; +} + +.text-overline { + font-size: 14px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 2px; +} + +/* ============== Text Colors ============== */ + +.text-primary { + color: #FFFFFF; +} + +.text-secondary { + color: #B3B3B3; +} + +.text-disabled { + color: #666666; +} + +.text-accent { + color: #BB86FC; +} + +.text-accent-secondary { + color: #03DAC6; +} + +.text-error { + color: #CF6679; +} + +/* ============== Background Colors ============== */ + +.bg-primary { + background-color: #121212; +} + +.bg-surface { + background-color: #1E1E1E; +} + +.bg-surface-variant { + background-color: #2D2D2D; +} + +.bg-accent { + background-color: #BB86FC; +} + +.bg-accent-secondary { + background-color: #03DAC6; +} + +.bg-error { + background-color: #CF6679; +} + +/* Hover highlight color - used for interactive element feedback */ +.bg-hover { + background-color: rgba(255, 255, 255, 0.12); +} + +/* ============== Spacing Utilities (VR-scaled) ============== */ + +.p-0 { padding: 0; } +.p-1 { padding: 6px; } +.p-2 { padding: 12px; } +.p-3 { padding: 18px; } +.p-4 { padding: 24px; } +.p-5 { padding: 36px; } +.p-6 { padding: 48px; } +.p-8 { padding: 72px; } + +.m-0 { margin: 0; } +.m-1 { margin: 6px; } +.m-2 { margin: 12px; } +.m-3 { margin: 18px; } +.m-4 { margin: 24px; } +.m-5 { margin: 36px; } +.m-6 { margin: 48px; } +.m-8 { margin: 72px; } + +.mt-1 { margin-top: 6px; } +.mt-2 { margin-top: 12px; } +.mt-3 { margin-top: 18px; } +.mt-4 { margin-top: 24px; } + +.mb-1 { margin-bottom: 6px; } +.mb-2 { margin-bottom: 12px; } +.mb-3 { margin-bottom: 18px; } +.mb-4 { margin-bottom: 24px; } + +/* ============== Layout Utilities ============== */ + +.flex { + display: flex; +} + +.flex-row { + display: flex; + flex-direction: row; +} + +.flex-col { + display: flex; + flex-direction: column; +} + +.flex-center { + display: flex; + justify-content: center; + align-items: center; +} + +.flex-between { + display: flex; + justify-content: space-between; +} + +.flex-around { + display: flex; + justify-content: space-around; +} + +.flex-1 { + flex: 1; +} + +.w-full { + width: 100%; +} + +.h-full { + height: 100%; +} + +.text-center { + text-align: center; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +/* ============== Border Utilities ============== */ + +.rounded { + border-radius: 6px; +} + +.rounded-lg { + border-radius: 12px; +} + +.rounded-xl { + border-radius: 20px; +} + +.rounded-full { + border-radius: 9999px; +} + +/* ============== Screen Structure ============== */ + +.screen { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + background-color: #121212; +} + +.screen-content { + flex: 1; + overflow: auto; +} + +/* ============== Animations ============== */ + +@keyframes fade-in { + 0% { opacity: 0; } + 100% { opacity: 1; } +} + +@keyframes slide-in-right { + 0% { transform: translateX(100px); opacity: 0; } + 100% { transform: translateX(0px); opacity: 1; } +} + +@keyframes slide-in-left { + 0% { transform: translateX(-100px); opacity: 0; } + 100% { transform: translateX(0px); opacity: 1; } +} + +@keyframes slide-up { + 0% { transform: translateY(50px); opacity: 0; } + 100% { transform: translateY(0px); opacity: 1; } +} + +@keyframes scale-in { + 0% { transform: scale(0.9); opacity: 0; } + 100% { transform: scale(1.0); opacity: 1; } +} + +/* Hover highlight animation */ +@keyframes hover-pulse { + 0% { background-color: rgba(255, 255, 255, 0.0); } + 50% { background-color: rgba(255, 255, 255, 0.15); } + 100% { background-color: rgba(255, 255, 255, 0.1); } +} + +/* Screen transition classes */ +.nav-forward { + animation: 0.2s cubic-out slide-in-right; +} + +.nav-back { + animation: 0.2s cubic-out slide-in-left; +} + +.nav-home { + animation: 0.2s back-out scale-in; +} + +.nav-default { + animation: 0.15s cubic-out fade-in; +} + +/* Animation utility classes */ +.animate-fade-in { + animation: 0.2s cubic-out fade-in; +} + +.animate-slide-right { + animation: 0.25s cubic-out slide-in-right; +} + +.animate-slide-left { + animation: 0.25s cubic-out slide-in-left; +} + +.animate-slide-up { + animation: 0.2s cubic-out slide-up; +} + +.animate-scale-in { + animation: 0.2s back-out scale-in; +} + +/* ============== Interactive Base Class ============== */ +/* All interactive elements should use cursor: pointer and have hover feedback */ + +.interactive { + cursor: pointer; +} + +.interactive:hover { + background-color: rgba(255, 255, 255, 0.1); +} + +.interactive:active { + background-color: rgba(255, 255, 255, 0.2); +}