mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-11-30 21:26:27 +03:00
Merge pull request #355 from kinode-dao/tm/widget-ui-fixes
Widget ui fixes
This commit is contained in:
commit
2978bf5935
@ -12,6 +12,9 @@ use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use crate::kinode::process::homepage::{AddRequest, Request as HomepageRequest};
|
||||
|
||||
/// Fetching OS version from main package.. LMK if there's a better way...
|
||||
const CARGO_TOML: &str = include_str!("../../../../Cargo.toml");
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct HomepageApp {
|
||||
package_name: String,
|
||||
@ -62,6 +65,7 @@ fn init(our: Address) {
|
||||
.expect("failed to bind to /our.js");
|
||||
|
||||
bind_http_path("/apps", true, false).expect("failed to bind /apps");
|
||||
bind_http_path("/version", true, false).expect("failed to bind /version");
|
||||
|
||||
loop {
|
||||
let Ok(ref message) = await_message() else {
|
||||
@ -134,6 +138,13 @@ fn init(our: Address) {
|
||||
.to_vec(),
|
||||
);
|
||||
}
|
||||
"/version" => {
|
||||
send_response(
|
||||
StatusCode::OK,
|
||||
Some(HashMap::new()),
|
||||
version_from_cargo_toml().as_bytes().to_vec(),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
send_response(
|
||||
StatusCode::OK,
|
||||
@ -149,3 +160,18 @@ fn init(our: Address) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn version_from_cargo_toml() -> String {
|
||||
let version = CARGO_TOML
|
||||
.lines()
|
||||
.find(|line| line.starts_with("version = "))
|
||||
.expect("Failed to find version in Cargo.toml");
|
||||
|
||||
version
|
||||
.split('=')
|
||||
.last()
|
||||
.expect("Failed to parse version from Cargo.toml")
|
||||
.trim()
|
||||
.trim_matches('"')
|
||||
.to_string()
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
kinode/packages/homepage/pkg/ui/assets/valet-icon-COgctyxf.png
Normal file
BIN
kinode/packages/homepage/pkg/ui/assets/valet-icon-COgctyxf.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@ -9,8 +9,8 @@
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
|
||||
<script type="module" crossorigin src="/assets/index-BrbxaEm2.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-iMQiSiXv.css">
|
||||
<script type="module" crossorigin src="/assets/index-C2uJ-HA5.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-C1M4NwvJ.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
BIN
kinode/packages/homepage/pkg/ui/valet-icon.png
Normal file
BIN
kinode/packages/homepage/pkg/ui/valet-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
4
kinode/packages/homepage/ui/dist/index.html
vendored
4
kinode/packages/homepage/ui/dist/index.html
vendored
@ -9,8 +9,8 @@
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
|
||||
<script type="module" crossorigin src="/assets/index-BrbxaEm2.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-iMQiSiXv.css">
|
||||
<script type="module" crossorigin src="/assets/index-C2uJ-HA5.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-C1M4NwvJ.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
3957
kinode/packages/homepage/ui/package-lock.json
generated
Normal file
3957
kinode/packages/homepage/ui/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
BIN
kinode/packages/homepage/ui/public/valet-icon.png
Normal file
BIN
kinode/packages/homepage/ui/public/valet-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@ -1,4 +1,3 @@
|
||||
import { FaCheck, FaX } from "react-icons/fa6"
|
||||
import useHomepageStore from "../store/homepageStore"
|
||||
import { Modal } from "./Modal"
|
||||
import classNames from "classnames"
|
||||
@ -14,35 +13,47 @@ const WidgetsSettingsModal = () => {
|
||||
>
|
||||
<div className="flex-col-center gap-4 mt-4">
|
||||
{apps.filter(app => app.widget).map(({ label, package_name }) => <div className="flex items-start bg-white/10 rounded p-2 self-stretch">
|
||||
<h4 className="mr-4">{label}</h4>
|
||||
<div className="flex-col-center gap-4 grow">
|
||||
<h4 className="mr-4 grow">{label}</h4>
|
||||
<div className="flex flex-col gap-4 grow">
|
||||
<div className="flex-center gap-2">
|
||||
<span>Show widget</span>
|
||||
<button
|
||||
className="icon"
|
||||
onClick={() => toggleWidgetVisibility(package_name)}
|
||||
>
|
||||
{!widgetSettings[package_name]?.hide ? <FaCheck /> : <FaX />}
|
||||
</button>
|
||||
<div className="flex relative grow">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={!widgetSettings[package_name]?.hide}
|
||||
onChange={() => toggleWidgetVisibility(package_name)}
|
||||
autoFocus
|
||||
/>
|
||||
{!widgetSettings[package_name]?.hide && (
|
||||
<span
|
||||
onClick={() => toggleWidgetVisibility(package_name)}
|
||||
className="checkmark"
|
||||
>
|
||||
✓
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-center gap-2">
|
||||
<span>Widget size</span>
|
||||
<button
|
||||
className={classNames({
|
||||
'clear': widgetSettings[package_name]?.size === 'large'
|
||||
})}
|
||||
onClick={() => setWidgetSize(package_name, 'small')}
|
||||
>
|
||||
Small
|
||||
</button>
|
||||
<button
|
||||
className={classNames({
|
||||
'clear': widgetSettings[package_name]?.size !== 'large'
|
||||
})}
|
||||
onClick={() => setWidgetSize(package_name, 'large')}
|
||||
>
|
||||
Large
|
||||
</button>
|
||||
<div className="flex-center grow">
|
||||
<button
|
||||
className={classNames({
|
||||
'clear': widgetSettings[package_name]?.size === 'large'
|
||||
})}
|
||||
onClick={() => setWidgetSize(package_name, 'small')}
|
||||
>
|
||||
Small
|
||||
</button>
|
||||
<button
|
||||
className={classNames({
|
||||
'clear': widgetSettings[package_name]?.size !== 'large'
|
||||
})}
|
||||
onClick={() => setWidgetSize(package_name, 'large')}
|
||||
>
|
||||
Large
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>)}
|
||||
|
@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'
|
||||
import KinodeText from '../components/KinodeText'
|
||||
import KinodeBird from '../components/KinodeBird'
|
||||
import useHomepageStore, { HomepageApp } from '../store/homepageStore'
|
||||
import { FaChevronDown, FaChevronUp, FaScrewdriverWrench, FaV } from 'react-icons/fa6'
|
||||
import { FaChevronDown, FaChevronUp, FaScrewdriverWrench } from 'react-icons/fa6'
|
||||
import AppsDock from '../components/AppsDock'
|
||||
import AllApps from '../components/AllApps'
|
||||
import Widgets from '../components/Widgets'
|
||||
@ -10,6 +10,8 @@ import { isMobileCheck } from '../utilities/dimensions'
|
||||
import classNames from 'classnames'
|
||||
import WidgetsSettingsModal from '../components/WidgetsSettingsModal'
|
||||
|
||||
import valetIcon from '../../public/valet-icon.png'
|
||||
|
||||
interface AppStoreApp {
|
||||
package: string,
|
||||
publisher: string,
|
||||
@ -19,6 +21,7 @@ interface AppStoreApp {
|
||||
}
|
||||
function Homepage() {
|
||||
const [our, setOur] = useState('')
|
||||
const [version, setVersion] = useState('')
|
||||
const [allAppsExpanded, setAllAppsExpanded] = useState(false)
|
||||
const { setApps, isHosted, fetchHostedStatus, showWidgetsSettings, setShowWidgetsSettings } = useHomepageStore()
|
||||
const isMobile = isMobileCheck()
|
||||
@ -26,9 +29,13 @@ function Homepage() {
|
||||
const getAppPathsAndIcons = () => {
|
||||
Promise.all([
|
||||
fetch('/apps').then(res => res.json() as any as HomepageApp[]),
|
||||
fetch('/main:app_store:sys/apps').then(res => res.json())
|
||||
]).then(([appsData, appStoreData]) => {
|
||||
console.log({ appsData, appStoreData })
|
||||
fetch('/main:app_store:sys/apps').then(res => res.json()),
|
||||
fetch('/version').then(res => res.text())
|
||||
]).then(([appsData, appStoreData, version]) => {
|
||||
console.log({ appsData, appStoreData, version })
|
||||
|
||||
setVersion(version)
|
||||
|
||||
const appz = appsData.map(app => ({
|
||||
...app,
|
||||
is_favorite: false, // Assuming initial state for all apps
|
||||
@ -87,13 +94,13 @@ function Homepage() {
|
||||
'top-8 left-8 right-8': !isMobile,
|
||||
'top-2 left-2 right-2': isMobile
|
||||
})}>
|
||||
{isHosted && <a
|
||||
href={`https://${our.replace('.os', '')}.hosting.kinode.net/`}
|
||||
className='button icon'
|
||||
>
|
||||
<FaV />
|
||||
</a>}
|
||||
{our}
|
||||
{!isHosted && <img
|
||||
src={valetIcon}
|
||||
className='!w-12 !h-12 !p-1 button icon object-cover'
|
||||
onClick={() => window.location.href = `https://${our.replace('.os', '')}.hosting.kinode.net/`}
|
||||
/>}
|
||||
<span>{our}</span>
|
||||
<span className='bg-white/10 rounded p-1'>v{version}</span>
|
||||
<button
|
||||
className="icon ml-auto"
|
||||
onClick={() => setShowWidgetsSettings(true)}
|
||||
|
@ -1372,7 +1372,7 @@ get-stream@^6.0.0:
|
||||
resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz"
|
||||
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
|
||||
|
||||
glob-parent@^5.1.2:
|
||||
glob-parent@^5.1.2, glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
|
||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||
@ -1386,13 +1386,6 @@ glob-parent@^6.0.2:
|
||||
dependencies:
|
||||
is-glob "^4.0.3"
|
||||
|
||||
glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
|
||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob@^7.1.3:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
|
||||
@ -1664,21 +1657,7 @@ mimic-fn@^2.1.0:
|
||||
resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
|
||||
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
||||
|
||||
minimatch@^3.0.5:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^3.1.1:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^3.1.2:
|
||||
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
|
@ -6,10 +6,6 @@ wit_bindgen::generate!({
|
||||
world: "process-v0",
|
||||
});
|
||||
|
||||
/// Fetching OS version from main package.. LMK if there's a better way...
|
||||
const CARGO_TOML: &str = include_str!("../../../../Cargo.toml");
|
||||
/// A static message to display on the homepage.
|
||||
const MOTD: &str = "Welcome to Kinode!";
|
||||
/// 20 minutes
|
||||
const REFRESH_INTERVAL: u64 = 20 * 60 * 1000;
|
||||
|
||||
@ -79,23 +75,20 @@ fn create_widget(posts: Vec<KinodeBlogPost>) -> String {
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-white overflow-hidden">
|
||||
<p>Kinode {}: {}</p>
|
||||
<p>Recent posts from kinode.org:</p>
|
||||
<body class="text-white overflow-hidden h-screen w-screen flex flex-col gap-2">
|
||||
<div
|
||||
id="latest-blog-posts"
|
||||
class="flex flex-col p-2 gap-2 backdrop-brightness-125 rounded-xl shadow-lg h-screen w-screen overflow-y-auto"
|
||||
class="flex flex-col p-2 gap-2 backdrop-brightness-125 rounded-xl shadow-lg h-screen w-screen overflow-y-auto self-stretch"
|
||||
style="
|
||||
scrollbar-color: transparent transparent;
|
||||
scrollbar-width: none;
|
||||
"
|
||||
>
|
||||
<p class="m-0 self-stretch text-center">Recent Posts</p>
|
||||
{}
|
||||
</div>
|
||||
</body>
|
||||
</html>"#,
|
||||
version_from_cargo_toml(),
|
||||
MOTD,
|
||||
posts
|
||||
.into_iter()
|
||||
.map(post_to_html_string)
|
||||
@ -103,21 +96,6 @@ fn create_widget(posts: Vec<KinodeBlogPost>) -> String {
|
||||
);
|
||||
}
|
||||
|
||||
fn version_from_cargo_toml() -> String {
|
||||
let version = CARGO_TOML
|
||||
.lines()
|
||||
.find(|line| line.starts_with("version = "))
|
||||
.expect("Failed to find version in Cargo.toml");
|
||||
|
||||
version
|
||||
.split('=')
|
||||
.last()
|
||||
.expect("Failed to parse version from Cargo.toml")
|
||||
.trim()
|
||||
.trim_matches('"')
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn fetch_three_most_recent_blog_posts() -> Vec<KinodeBlogPost> {
|
||||
let blog_posts = match http::send_request_await_response(
|
||||
http::Method::GET,
|
||||
|
Loading…
Reference in New Issue
Block a user