Skip to content
Open
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
13,662 changes: 1,777 additions & 11,885 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@
},
"dependencies": {
"@firebolt-js/sdk": "^1.4.1",
"@lightningjs/blits": "^2.0.0"
"@lightningjs/blits": "github:lightning-js/blits#feature/named-router-views"
}
}
23 changes: 22 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ import SpecialCharacters from './pages/SpecialCharacters.js'
import Layout from './pages/Layout.js'
import { FireBoltRoutes } from './pages/Firebolt.js'
import Announcer from './pages/Announcer.js'
import NamedRoutes from './pages/NamedRoutes.js'
import SidePanel from './pages/appInApp/SidePanel.js'

const queryString = new URLSearchParams(window.location.search)
const showSource = !!queryString.get('source')
Expand All @@ -68,10 +70,12 @@ export default Blits.Application({
components: {
SourceInfo,
FPScounter,
SidePanel,
},
template: `
<Element w="1920" h="1080" :color="$backgroundColor">
<RouterView w="100%" h="100%" />
<RouterView w="100%" h="100%" ref="routerView" :active="$routerActive" />
<SidePanel :x.transition="{value: $panelX, duration: 300}" ref="sidePanel" />
<FPScounter x="1610" :show="$showFPS" />
<SourceInfo ref="info" :show="$showInfo" />
</Element>
Expand All @@ -81,6 +85,8 @@ export default Blits.Application({
backgroundColor: '#1e293b',
showFPS: showFPS,
showInfo: false,
panelX: 1920,
routerActive: true,
}
},
routes: [
Expand Down Expand Up @@ -144,6 +150,8 @@ export default Blits.Application({
component: Announcer,
announce: 'Welcome to the announcement example page',
},
// Named Routes (App-in-App)
{ path: '/demos/named-routes', component: NamedRoutes },
// Benchmarks and stress tests
{ path: '/benchmarks/exponential', component: Exponential },
...FireBoltRoutes,
Expand All @@ -161,6 +169,18 @@ export default Blits.Application({
this.$listen('clearBackground', () => {
this.backgroundColor = 'transparent'
})

// Named routes panel events
this.$listen('openPanel', () => {
this.panelX = 1520
this.$select('sidePanel').$focus()
this.routerActive = false
})
this.$listen('closePanel', () => {
this.$select('routerView').$focus()
this.routerActive = true
this.panelX = 1920
})
},
},
input: {
Expand Down Expand Up @@ -213,6 +233,7 @@ const getSourcePath = (routerPath) => {
'/demos/focushandling': 'src/pages/FocusHandling',
'/demos/memory-game': 'src/pages/MemoryGame',
'/demos/player': 'src/pages/Player',
'/demos/named-routes': 'src/pages/NamedRoutes',
'/examples/positioning': 'src/pages/Positioning',
'/examples/colors': 'src/pages/Colors',
'/examples/gradients': 'src/pages/Gradients',
Expand Down
122 changes: 122 additions & 0 deletions src/pages/NamedRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import Blits from '@lightningjs/blits'

export default Blits.Component('NamedRoutes', {
template: `
<Element w="1920" h="1080" color="#0f172a">
<!-- Header -->
<Element x="80" y="60">
<Text content="Named Routes: App-in-App" size="44" color="#ffffff" />
<Text
y="60"
content="This page demonstrates a child app (Side Panel) living inside the main App."
size="20"
color="#94a3b8"
/>
<Text
y="90"
content="The Side Panel has its own named RouterView and independent navigation."
size="20"
color="#94a3b8"
/>
</Element>

<!-- How it works -->
<Element x="80" y="200" w="760" h="250" color="#1e293b">
<Element x="30" y="25">
<Text content="How it works:" size="26" color="#e2e8f0" />
<Text
y="45"
content="- SidePanel uses a named RouterView (name: sidePanel)"
size="18"
color="#cbd5e1"
/>
<Text
y="72"
content="- Navigate with: $router.get('sidePanel').to(path)"
size="18"
color="#cbd5e1"
/>
<Text
y="99"
content="- Go back with: $router.get('sidePanel').back()"
size="18"
color="#cbd5e1"
/>
<Text
y="126"
content="- Panel routes can use hooks.before (see Recommendations)"
size="18"
color="#cbd5e1"
/>
<Text y="153" content="- Main and panel routers coexist independently" size="18" color="#cbd5e1" />
</Element>
</Element>

<!-- Open Panel Button -->
<Element x="80" y="500" w="300" h="70" :color="$buttonFocused ? '#3b82f6' : '#334155'" ref="openBtn">
<Text
content="Open Side Panel"
size="24"
mount="{x: 0.5, y: 0.5}"
x="150"
y="35"
:color="$buttonFocused ? '#ffffff' : '#94a3b8'"
/>
</Element>

<!-- Status -->
<Element x="80" y="610">
<Text
:content="'Panel: ' + ($panelOpen ? 'OPEN' : 'CLOSED')"
size="20"
:color="$panelOpen ? '#4ade80' : '#64748b'"
/>
<Text y="34" :content="'Main route: ' + $mainRoute" size="18" color="#94a3b8" />
<Text y="62" :content="'Panel route: ' + $panelRoute" size="18" color="#94a3b8" />
</Element>
<!-- Instructions -->
<Element x="80" y="720">
<Text content="Press [Enter] on the button to open the Side Panel" size="18" color="#64748b" />
<Text y="28" content="In the panel: [Up/Down] pages, [Back] panel history, [Left] close" size="18" color="#64748b" />
</Element>
</Element>
`,
state() {
return {
panelOpen: false,
buttonFocused: true,
}
},
computed: {
mainRoute() {
const route = this.$router.currentRoute
return (route && route.path) || '/'
},
panelRoute() {
const route = this.$router.get('sidePanel').currentRoute
return (route && route.path) || '/'
},
},
hooks: {
focus() {
this.buttonFocused = true
this.panelOpen = false
},
},
input: {
enter() {
if (!this.panelOpen) {
this.$emit('openPanel')
this.panelOpen = true
this.buttonFocused = false
}
},
left() {
if (this.panelOpen) {
this.$emit('closePanel')
this.panelOpen = false
this.buttonFocused = true
}
},
},
})
5 changes: 5 additions & 0 deletions src/pages/Portal.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ export default Blits.Component('Portal', {
id: 'demos/player',
description: 'Example of Video Playback with basic controls',
},
{
title: 'Named Routes',
id: 'demos/named-routes',
description: 'App-in-App: child app with its own named RouterView inside the main App',
},
],
example: [
{
Expand Down
88 changes: 88 additions & 0 deletions src/pages/appInApp/SidePanel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import Blits from '@lightningjs/blits'

import NowPlaying from './panel/NowPlaying.js'
import Recommendations from './panel/Recommendations.js'
import Trending from './panel/Trending.js'

export default Blits.Component('SidePanel', {
template: `
<Element w="900" h="1080" color="#1e293b">
<Element w="2" h="1080" color="#334155" />
<Element x="10">
<RouterView w="980" h="1080" :active="$active" ref="routerView" name="sidePanel" />
</Element>
<!-- Navigation instructions at bottom -->
<Element x="20" y="820">
<Element w="980" h="2" color="#334155" />
<Text y="15" content="Panel Navigation:" size="18" color="#e2e8f0" />
<Text y="42" content="[Up/Down] Switch pages" size="15" color="#4ade80" />
<Text y="64" content="[Back] Panel history back" size="15" color="#4ade80" />
<Text y="86" content="[Left] Return to main page" size="15" color="#4ade80" />
<Text y="120" :content="'Page ' + ($pageIndex + 1) + ' of 3'" size="14" color="#64748b" />
<Text y="144" :content="'Panel route: ' + $panelRoute" size="14" color="#64748b" />
</Element>
</Element>
`,
router: {
routes: [
{ path: '/', component: NowPlaying },
{
path: '/recommendations',
component: Recommendations,
hooks: {
before(to) {
// Example of a secondary RouterView route hook
to.data.subtitle = 'Loaded via sidePanel before hook'
return to
},
},
},
{ path: '/trending', component: Trending },
],
},
state() {
return {
active: false,
pageIndex: 0,
pages: ['/', '/recommendations', '/trending'],
}
},
computed: {
panelRoute() {
const route = this.$router.get('sidePanel').currentRoute
return (route && route.path) || '/'
},
},
hooks: {
focus() {
this.active = true
this.pageIndex = 0
this.$select('routerView').$focus()
},
unfocus() {
this.active = false
this.$emit('closePanel')
},
},
input: {
up() {
this.pageIndex = (this.pageIndex - 1 + this.pages.length) % this.pages.length
this.$router.get('sidePanel').to(this.pages[this.pageIndex])
},
down() {
this.pageIndex = (this.pageIndex + 1) % this.pages.length
this.$router.get('sidePanel').to(this.pages[this.pageIndex])
},
back() {
// Prefer named RouterView history; close the panel when there is nowhere to go back
if (this.$router.get('sidePanel').back()) {
this.pageIndex = Math.max(0, this.pageIndex - 1)
return
}
this.$emit('closePanel')
},
left() {
this.$emit('closePanel')
},
},
})
24 changes: 24 additions & 0 deletions src/pages/appInApp/panel/NowPlaying.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Blits from '@lightningjs/blits'

export default Blits.Component('NowPlaying', {
template: `
<Element w="380" h="800">
<Text content="Now Playing" size="30" x="20" y="30" color="#3b82f6" />
<Text content="Page 1 of 3" size="14" x="20" y="68" color="#64748b" />
<Element y="100" x="20" w="340" h="2" color="#ffffff40" />
<Element y="120" x="20">
<Text content="The Dark Knight" size="24" color="#e2e8f0" />
<Text y="35" content="Runtime: 2h 32m" size="17" color="#94a3b8" />
<Text y="60" content="Rating: 9.0/10" size="17" color="#fbbf24" />
<Text y="100" content="Director: Christopher Nolan" size="17" color="#94a3b8" />
<Text y="125" content="Genre: Action, Drama" size="17" color="#94a3b8" />
</Element>
<Element y="290" x="20">
<Text content="Up Next" size="20" color="#64748b" />
<Text y="30" content="Inception" size="17" color="#94a3b8" />
<Text y="55" content="Interstellar" size="17" color="#94a3b8" />
<Text y="80" content="Tenet" size="17" color="#94a3b8" />
</Element>
</Element>
`,
})
41 changes: 41 additions & 0 deletions src/pages/appInApp/panel/Recommendations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Blits from '@lightningjs/blits'

export default Blits.Component('Recommendations', {
props: {
subtitle: {
type: String,
default: '',
},
},
template: `
<Element w="380" h="800">
<Text content="Recommendations" size="30" x="20" y="30" color="#a855f7" />
<Text content="Page 2 of 3" size="14" x="20" y="68" color="#64748b" />
<Text :content="$subtitle || 'Based on your history'" size="14" x="20" y="92" color="#86efac" />
<Element y="120" x="20" w="340" h="2" color="#ffffff40" />
<Element y="140" x="20">
<Text content="Based on your history" size="16" color="#64748b" />
<Element y="30">
<Text content="1. Breaking Bad" size="20" color="#e2e8f0" />
<Text y="25" content="Drama - 5 Seasons" size="15" color="#94a3b8" />
</Element>
<Element y="80">
<Text content="2. Better Call Saul" size="20" color="#e2e8f0" />
<Text y="25" content="Drama - 6 Seasons" size="15" color="#94a3b8" />
</Element>
<Element y="130">
<Text content="3. The Wire" size="20" color="#e2e8f0" />
<Text y="25" content="Crime - 5 Seasons" size="15" color="#94a3b8" />
</Element>
<Element y="180">
<Text content="4. Stranger Things" size="20" color="#e2e8f0" />
<Text y="25" content="Sci-Fi - 4 Seasons" size="15" color="#94a3b8" />
</Element>
<Element y="230">
<Text content="5. True Detective" size="20" color="#e2e8f0" />
<Text y="25" content="Thriller - 4 Seasons" size="15" color="#94a3b8" />
</Element>
</Element>
</Element>
`,
})
Loading