SpringBoard-like v1
This commit is contained in:
parent
70088d37e0
commit
29fade983d
14 changed files with 257 additions and 32 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -90,7 +90,6 @@ out
|
|||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
|
|
15
README.md
15
README.md
|
@ -1,2 +1,13 @@
|
|||
This is the Vue 3 + Vite template branch.
|
||||
If you want to download this for use, this is not a working Bridge Launcher Project, but a template. In that case select a different branch.
|
||||
# SpringBoard-like
|
||||
|
||||
A Brige Launcher Project inspired by SpringBoard, iOS default launcher,
|
||||
|
||||
# Screenshots
|
||||
|
||||
*none because still in development*
|
||||
|
||||
# Customizing dock apps
|
||||
1. Open [Dock.vue](src/components/Dock.vue)
|
||||
2. On your phone (or dev env), select the *invisible* text below the icon's label name. Copy it fully.
|
||||
> Note: Thats the **Package name** of the app you want to pin on the dock
|
||||
3. Put the wanted app's package name instead of the default one
|
1
dist/assets/index-Byzfhg1j.css
vendored
Normal file
1
dist/assets/index-Byzfhg1j.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
body{margin:0;padding:0;box-sizing:border-box;background-color:gray}#applist{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;scroll-snap-stop:always}#applist-wrapper{width:100%}.applist-page{scroll-snap-align:start;display:flex;flex-direction:row;flex-wrap:wrap;min-width:100vw;justify-content:flex-start;align-content:flex-start;padding-bottom:10%;padding-top:5%}.applist-page>*{min-width:25%;margin-bottom:5%}#dock{padding:5%;margin:5%;gap:15px;border-radius:24px;background-color:#00000040;border:1px solid white;display:flex;justify-content:center;position:fixed;bottom:0;left:0;right:0}.section{padding:5%;margin:0 5% 5%;border-radius:15px;background-color:#00000040;border:1px solid white;width:100%}.ui-button{border:none;border:1px solid white;border-radius:6px;padding:2%;background-color:#00000080;color:#fff;margin:1%}.app-icon[data-v-fa001907]{display:flex;align-items:center;flex-direction:column;width:max-content;height:max-content}.app-icon .app-icon[data-v-fa001907]>*:nth-child(n+2){padding-bottom:10px}.app-image[data-v-fa001907]{width:60px;height:60px;border-radius:12px}.app-label[data-v-fa001907]{font-size:12px;color:var(--label-color)}.app-package[data-v-fa001907]{font-size:3px;color:#0000}
|
17
dist/assets/index-C4iP7xdQ.js
vendored
Normal file
17
dist/assets/index-C4iP7xdQ.js
vendored
Normal file
File diff suppressed because one or more lines are too long
14
dist/index.html
vendored
Normal file
14
dist/index.html
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>SpringBoard</title>
|
||||
<script type="module" crossorigin src="/assets/index-C4iP7xdQ.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Byzfhg1j.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
1
dist/vite.svg
vendored
Normal file
1
dist/vite.svg
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
1
dist/vue.svg
vendored
Normal file
1
dist/vue.svg
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
After Width: | Height: | Size: 496 B |
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue</title>
|
||||
<title>SpringBoard</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
42
src/App.vue
42
src/App.vue
|
@ -1,29 +1,41 @@
|
|||
<template>
|
||||
This is a <strong>TEMPLATE</strong>
|
||||
<Suspense>
|
||||
<template #default>
|
||||
<div>
|
||||
<AppIcon v-for="app in apps" :key="app.packageName" :packageName="app.packageName" :label="app.label" />
|
||||
</div>
|
||||
</template>
|
||||
</Suspense>
|
||||
<div id="applist-wrapper">
|
||||
<Suspense>
|
||||
<template #default>
|
||||
<div id="applist">
|
||||
<div class="applist-page" v-for="(page, index) in paginatedApps" :key="index">
|
||||
<AppIcon v-for="app in page" :key="app.packageName" :packageName="app.packageName" :label="app.label" />
|
||||
</div>
|
||||
<div class="applist-page" v-if="paginatedApps.length > 0">
|
||||
<Settings></Settings>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Suspense>
|
||||
</div>
|
||||
<Dock></Dock>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import AppIcon from './components/AppIcon.vue'
|
||||
import { ref, computed } from 'vue';
|
||||
import AppIcon from './components/AppIcon.vue';
|
||||
import Dock from './components/Dock.vue';
|
||||
import Settings from './components/Settings.vue';
|
||||
|
||||
const apps = ref([])
|
||||
|
||||
async function loadApps() {
|
||||
const resp = await fetch(Bridge.getAppsURL())
|
||||
const data = await resp.json()
|
||||
apps.value = data.apps
|
||||
apps.value = data.apps.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: 'base' }))
|
||||
}
|
||||
|
||||
loadApps()
|
||||
|
||||
const itemsPerPage = 4 * 6;
|
||||
const paginatedApps = computed(() => {
|
||||
return Array(Math.ceil(apps.value.length / itemsPerPage)).fill().map((_, index) => {
|
||||
return apps.value.slice(index * itemsPerPage, (index + 1) * itemsPerPage);
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
|
@ -5,23 +5,49 @@ import { defineProps, ref, onMounted } from 'vue'
|
|||
const props = defineProps({
|
||||
packageName: {
|
||||
type: String,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
required: false,
|
||||
default: "UNSETLABEL"
|
||||
},
|
||||
hideLabel: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
}
|
||||
})
|
||||
|
||||
let darkLabel
|
||||
if (Bridge.getSystemNightMode() == 'yes') {
|
||||
darkLabel = true;
|
||||
} else {
|
||||
darkLabel = false;
|
||||
}
|
||||
// Create a ref to hold the icon URL
|
||||
const icon = ref('');
|
||||
icon.value = await Bridge.getDefaultAppIconURL(props.packageName);
|
||||
const label = ref('')
|
||||
if (props.label.length >= 10) {
|
||||
label.value = `${props.label.slice(0, 10 - 3).trim()}...`;
|
||||
} else {
|
||||
label.value = props.label;
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
Bridge.requestLaunchApp(props.packageName);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-icon">
|
||||
<img :src="icon" :alt="props.label" />
|
||||
<span>{{ props.label }}</span>
|
||||
<div
|
||||
class="app-icon"
|
||||
@click="handleClick()"
|
||||
:style="{ '--label-color': darkLabel ? '#000000' : '#ffffff' }"
|
||||
>
|
||||
<img :src="icon" :alt="label" class="app-image">
|
||||
<span v-if="!props.hideLabel" class="app-label">{{ label }}</span>
|
||||
<span v-if="!props.hideLabel" class="app-package">{{ props.packageName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -29,15 +55,28 @@ icon.value = await Bridge.getDefaultAppIconURL(props.packageName);
|
|||
.app-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
width: max-content;
|
||||
height: max-content;
|
||||
|
||||
.app-icon > *:nth-child(n+2) {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.app-icon img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
.app-image {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.app-icon span {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
.app-label {
|
||||
font-size: 12px;
|
||||
color: var(--label-color);
|
||||
}
|
||||
|
||||
.app-package {
|
||||
font-size: 3px;
|
||||
color: #00000000;
|
||||
}
|
||||
</style>
|
||||
|
|
14
src/components/Dock.vue
Normal file
14
src/components/Dock.vue
Normal file
|
@ -0,0 +1,14 @@
|
|||
<script setup>
|
||||
import AppIcon from './AppIcon.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Suspense>
|
||||
<div id="dock">
|
||||
<AppIcon packageName="app.revenge" :hideLabel="true"/>
|
||||
<AppIcon packageName="com.radolyn.ayugram" :hideLabel="true"/>
|
||||
<AppIcon packageName="org.mozilla.fennec_fdroid" :hideLabel="true"/>
|
||||
<AppIcon packageName="org.akanework.gramophone" :hideLabel="true"/>
|
||||
</div>
|
||||
</Suspense>
|
||||
</template>
|
53
src/components/Settings.vue
Normal file
53
src/components/Settings.vue
Normal file
|
@ -0,0 +1,53 @@
|
|||
<script setup>
|
||||
function toggleBridgeButton() {
|
||||
console.log('Changed Bridge Button visibility to...')
|
||||
if (Bridge.getBridgeButtonVisibility() == 'shown') {
|
||||
Bridge.requestSetBridgeButtonVisibility('hidden');
|
||||
console.log('hidden');
|
||||
} else {
|
||||
Bridge.requestSetBridgeButtonVisibility('shown');
|
||||
console.log('shown');
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSystemWallpapers() {
|
||||
console.log('Changed system wallpapers to...')
|
||||
if (Bridge.getDrawSystemWallpaperBehindWebViewEnabled()) {
|
||||
Bridge.requestSetDrawSystemWallpaperBehindWebViewEnabled(false);
|
||||
console.log('false');
|
||||
} else {
|
||||
Bridge.requestSetDrawSystemWallpaperBehindWebViewEnabled(true);
|
||||
console.log('true');
|
||||
}
|
||||
}
|
||||
|
||||
function toggleOverscrolling() {
|
||||
console.log('Changed overscrolling effect to...')
|
||||
if (Bridge.getOverscrollEffects == 'default') {
|
||||
Bridge.requestSetOverscrollEffects('none');
|
||||
console.log('none');
|
||||
} else {
|
||||
Bridge.requestSetOverscrollEffects('default');
|
||||
console.log('default');
|
||||
}
|
||||
}
|
||||
|
||||
function openBridgeAppDrawer() {
|
||||
Bridge.requestOpenBridgeAppDrawer();
|
||||
}
|
||||
function reloadWindow() {
|
||||
window.location.reload();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="section">
|
||||
<button class="ui-button" @click="toggleBridgeButton()">Toggle Bridge button</button>
|
||||
<button class="ui-button" @click="openBridgeAppDrawer()">Open Bridge App Drawer</button>
|
||||
<button class="ui-button" @click="toggleSystemWallpapers()">Toggle system wallpaper visibility</button>
|
||||
<button class="ui-button" @click="toggleOverscrolling()">Toggle overscrolling</button>
|
||||
<button class="ui-button" @click="reloadWindow()">Reload</button>
|
||||
<br>
|
||||
<small style="font-size:xx-small;color:white">Everything else can be configured through Bridge's Settings</small>
|
||||
</div>
|
||||
</template>
|
|
@ -10,4 +10,6 @@ if (!window.Bridge) {
|
|||
});
|
||||
}
|
||||
|
||||
Bridge.requestSetBridgeTheme('system');
|
||||
|
||||
createApp(App).mount('#app')
|
||||
|
|
|
@ -1,7 +1,68 @@
|
|||
// SCSS goes here
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
background-color: #808080;
|
||||
}
|
||||
|
||||
#applist {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
scroll-snap-stop: always;
|
||||
}
|
||||
|
||||
#applist-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.applist-page {
|
||||
scroll-snap-align: start;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
min-width: 100vw;
|
||||
justify-content: flex-start;
|
||||
align-content: flex-start;
|
||||
padding-bottom: 10%;
|
||||
padding-top: 5%;
|
||||
& > * {
|
||||
min-width: 25%; // 4 columns
|
||||
margin-bottom: 5%;
|
||||
}
|
||||
}
|
||||
|
||||
#dock {
|
||||
padding: 5%;
|
||||
margin: 5%;
|
||||
gap: 15px;
|
||||
border-radius: 24px;
|
||||
background-color: rgba(0,0,0,0.25);
|
||||
border: 1px solid white;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 5%;
|
||||
margin: 5%;
|
||||
margin-top: 0;
|
||||
border-radius: 15px;
|
||||
background-color: rgba(0,0,0,0.25);
|
||||
border: 1px solid white;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.ui-button {
|
||||
border: none;
|
||||
border: 1px solid white;
|
||||
border-radius: 6px;
|
||||
padding: 2%;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
color: white;
|
||||
margin: 1%;
|
||||
}
|
Loading…
Add table
Reference in a new issue