mirror of
https://github.com/uqbar-dao/nectar.git
synced 2025-01-02 13:36:47 +03:00
Merge pull request #375 from kinode-dao/tm/appstore-paging-fix
Appstore paging fix
This commit is contained in:
commit
fc5e60f67e
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
94
kinode/packages/app_store/pkg/ui/assets/index-Mr04YvPM.js
Normal file
94
kinode/packages/app_store/pkg/ui/assets/index-Mr04YvPM.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -14,8 +14,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="/main:app_store:sys/assets/index-GPWa2djr.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/main:app_store:sys/assets/index-EAwGkdAI.css">
|
||||
<script type="module" crossorigin src="/main:app_store:sys/assets/index-Mr04YvPM.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/main:app_store:sys/assets/index-fGthT1qI.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -11,9 +11,10 @@ interface ActionButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
app: AppInfo;
|
||||
isIcon?: boolean;
|
||||
permitMultiButton?: boolean;
|
||||
launchPath?: string
|
||||
}
|
||||
|
||||
export default function ActionButton({ app, isIcon = false, permitMultiButton = false, ...props }: ActionButtonProps) {
|
||||
export default function ActionButton({ app, launchPath = '', isIcon = false, permitMultiButton = false, ...props }: ActionButtonProps) {
|
||||
const { installed, downloaded, updatable } = useMemo(() => {
|
||||
const versions = Object.entries(app?.metadata?.properties?.code_hashes || {});
|
||||
const latestHash = (versions.find(([v]) => v === app.metadata?.properties?.current_version) || [])[1];
|
||||
@ -32,21 +33,6 @@ export default function ActionButton({ app, isIcon = false, permitMultiButton =
|
||||
};
|
||||
}, [app]);
|
||||
|
||||
|
||||
const [launchPath, setLaunchPath] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/apps').then(data => data.json())
|
||||
.then((data: Array<{ package_name: string, path: string }>) => {
|
||||
if (Array.isArray(data)) {
|
||||
const homepageAppData = data.find(otherApp => app.package === otherApp.package_name)
|
||||
if (homepageAppData) {
|
||||
setLaunchPath(homepageAppData.path)
|
||||
}
|
||||
}
|
||||
})
|
||||
}, [app])
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* if it's got a UI and it's updatable, show both buttons if we have space (launch will otherwise push out update) */}
|
||||
|
@ -15,9 +15,10 @@ interface AppEntryProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
size?: "small" | "medium" | "large";
|
||||
overrideImageSize?: "small" | "medium" | "large";
|
||||
showMoreActions?: boolean;
|
||||
launchPath?: string;
|
||||
}
|
||||
|
||||
export default function AppEntry({ app, size = "medium", overrideImageSize, showMoreActions, ...props }: AppEntryProps) {
|
||||
export default function AppEntry({ app, size = "medium", overrideImageSize, showMoreActions, launchPath, ...props }: AppEntryProps) {
|
||||
const isMobile = isMobileCheck()
|
||||
const navigate = useNavigate()
|
||||
|
||||
@ -45,6 +46,7 @@ export default function AppEntry({ app, size = "medium", overrideImageSize, show
|
||||
})}>
|
||||
<ActionButton
|
||||
app={app}
|
||||
launchPath={launchPath}
|
||||
isIcon={!showMoreActions && size !== 'large'}
|
||||
className={classNames({
|
||||
'bg-orange text-lg': size === 'large',
|
||||
|
@ -22,6 +22,7 @@ export default function AppPage() {
|
||||
const navigate = useNavigate();
|
||||
const params = useParams();
|
||||
const [app, setApp] = useState<AppInfo | undefined>(undefined);
|
||||
const [launchPath, setLaunchPath] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
const myApp = myApps.local.find((a) => appId(a) === params.id);
|
||||
@ -91,6 +92,18 @@ export default function AppPage() {
|
||||
}
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/apps').then(data => data.json())
|
||||
.then((data: Array<{ package_name: string, path: string }>) => {
|
||||
if (Array.isArray(data)) {
|
||||
const homepageAppData = data.find(otherApp => app?.package === otherApp.package_name)
|
||||
if (homepageAppData) {
|
||||
setLaunchPath(homepageAppData.path)
|
||||
}
|
||||
}
|
||||
})
|
||||
}, [app])
|
||||
|
||||
return (
|
||||
<div className={classNames("flex flex-col w-full p-2",
|
||||
{
|
||||
@ -143,7 +156,12 @@ export default function AppPage() {
|
||||
<div className={classNames("flex-center gap-2", {
|
||||
'flex-col': isMobile,
|
||||
})}>
|
||||
<ActionButton app={app} className={classNames("self-center bg-orange text-lg px-12")} permitMultiButton />
|
||||
<ActionButton
|
||||
app={app}
|
||||
launchPath={launchPath}
|
||||
className={classNames("self-center bg-orange text-lg px-12")}
|
||||
permitMultiButton
|
||||
/>
|
||||
</div>
|
||||
{app.installed && app.state?.mirroring && (
|
||||
<button type="button" onClick={goToPublish}>
|
||||
|
@ -19,21 +19,25 @@ export default function StorePage() {
|
||||
const { listedApps, getListedApps, rebuildIndex } = useAppsStore();
|
||||
|
||||
const [resultsSort, setResultsSort] = useState<string>("Recently published");
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||
const [displayedApps, setDisplayedApps] = useState<AppInfo[]>(listedApps);
|
||||
const [page, setPage] = useState(1);
|
||||
const [tags, setTags] = useState<string[]>([])
|
||||
const [launchPaths, setLaunchPaths] = useState<{ [package_name: string]: string }>({})
|
||||
|
||||
const pages = useMemo(
|
||||
() =>
|
||||
Array.from(
|
||||
{ length: Math.ceil(displayedApps.length / 10) },
|
||||
{
|
||||
length: Math.ceil(listedApps.length / 10)
|
||||
},
|
||||
(_, index) => index + 1
|
||||
),
|
||||
[displayedApps]
|
||||
[listedApps]
|
||||
);
|
||||
|
||||
const featuredPackageNames = ['dartfrog', 'kcal', 'memedeck', 'filter'];
|
||||
|
||||
useEffect(() => {
|
||||
const start = (page - 1) * 10;
|
||||
const end = start + 10;
|
||||
@ -104,6 +108,23 @@ export default function StorePage() {
|
||||
|
||||
const isMobile = isMobileCheck()
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/apps').then(data => data.json())
|
||||
.then((data: Array<{ package_name: string, path: string }>) => {
|
||||
if (Array.isArray(data)) {
|
||||
listedApps.forEach(app => {
|
||||
const homepageAppData = data.find(otherApp => app.package === otherApp.package_name)
|
||||
if (homepageAppData) {
|
||||
setLaunchPaths({
|
||||
...launchPaths,
|
||||
[app.package]: homepageAppData.path
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}, [listedApps])
|
||||
|
||||
return (
|
||||
<div className={classNames("flex flex-col w-full max-h-screen p-2", {
|
||||
'gap-4 max-w-screen': isMobile,
|
||||
@ -159,13 +180,14 @@ export default function StorePage() {
|
||||
<div className={classNames("flex gap-2", {
|
||||
'flex-col': isMobile
|
||||
})}>
|
||||
{displayedApps.filter(app => {
|
||||
return ['kcal', 'command_center', 'memedeck', 'filter'].indexOf(app.package) !== -1
|
||||
{listedApps.filter(app => {
|
||||
return featuredPackageNames.indexOf(app.package) !== -1
|
||||
}).map((app) => (
|
||||
<AppEntry
|
||||
key={appId(app) + (app.state?.our_version || "")}
|
||||
size={'medium'}
|
||||
app={app}
|
||||
launchPath={launchPaths[app.package]}
|
||||
className={classNames("grow", {
|
||||
'w-1/4': !isMobile,
|
||||
'w-full': isMobile
|
||||
@ -179,34 +201,38 @@ export default function StorePage() {
|
||||
'gap-2': isMobile,
|
||||
'gap-4': !isMobile,
|
||||
})}>
|
||||
{displayedApps.map(app => <AppEntry
|
||||
key={appId(app) + (app.state?.our_version || "")}
|
||||
size='large'
|
||||
app={app}
|
||||
className="self-stretch"
|
||||
overrideImageSize="medium"
|
||||
/>)}
|
||||
{displayedApps
|
||||
.filter(app => searchQuery ? true : featuredPackageNames.indexOf(app.package) === -1)
|
||||
.map(app => <AppEntry
|
||||
key={appId(app) + (app.state?.our_version || "")}
|
||||
size='large'
|
||||
app={app}
|
||||
className="self-stretch"
|
||||
overrideImageSize="medium"
|
||||
/>)}
|
||||
</div>
|
||||
{pages.length > 1 && <div className="flex self-center">
|
||||
{page !== pages[0] && (
|
||||
<button className="icon" onClick={() => setPage(page - 1)}>
|
||||
<FaChevronLeft />
|
||||
</button>
|
||||
)}
|
||||
{pages.length > 1 && <div className="flex flex-wrap self-center gap-2">
|
||||
<button
|
||||
className="icon"
|
||||
onClick={() => page !== pages[0] && setPage(page - 1)}
|
||||
>
|
||||
<FaChevronLeft />
|
||||
</button>
|
||||
{pages.map((p) => (
|
||||
<button
|
||||
key={`page-${p}`}
|
||||
className={classNames('my-1 mx-2 clear', { "font-bold": p === page })}
|
||||
className={classNames('icon', { "!bg-white/10": p === page })}
|
||||
onClick={() => setPage(p)}
|
||||
>
|
||||
{p}
|
||||
</button>
|
||||
))}
|
||||
{page !== pages[pages.length - 1] && (
|
||||
<button className="icon" onClick={() => setPage(page + 1)}>
|
||||
<FaChevronRight />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className="icon"
|
||||
onClick={() => page !== pages[pages.length - 1] && setPage(page + 1)}
|
||||
>
|
||||
<FaChevronRight />
|
||||
</button>
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
|
File diff suppressed because one or more lines are too long
@ -9,7 +9,7 @@
|
||||
<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-Gt0JAj27.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-DqBTDSfz.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BS5LP50I.css">
|
||||
</head>
|
||||
|
||||
|
2
kinode/packages/homepage/ui/dist/index.html
vendored
2
kinode/packages/homepage/ui/dist/index.html
vendored
@ -9,7 +9,7 @@
|
||||
<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-Gt0JAj27.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-DqBTDSfz.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BS5LP50I.css">
|
||||
</head>
|
||||
|
||||
|
@ -34,6 +34,9 @@ const usePersistentStore = create<PersistentStore>()(
|
||||
setFavoriteApps: (favoriteApps: PersistentStore['favoriteApps']) => set({ favoriteApps }),
|
||||
toggleWidgetVisibility: (package_name: string) => {
|
||||
const { widgetSettings } = get()
|
||||
if (!window.confirm(`Really hide this widget?`)) {
|
||||
return
|
||||
}
|
||||
set({
|
||||
widgetSettings: {
|
||||
...widgetSettings,
|
||||
|
@ -93,7 +93,7 @@ impl process::ProcessState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a message from the main event loop into a result for the process to receive.
|
||||
/// Forward the message from the main event loop to the process in the form of a result.
|
||||
/// If the message is a response or error, get context if we have one.
|
||||
fn kernel_message_to_process_receive(
|
||||
&mut self,
|
||||
|
Loading…
Reference in New Issue
Block a user