diff --git a/src/gui/src/UI/Dashboard/TabApps.js b/src/gui/src/UI/Dashboard/TabApps.js
index 6a3a0418b..5ba7e9981 100644
--- a/src/gui/src/UI/Dashboard/TabApps.js
+++ b/src/gui/src/UI/Dashboard/TabApps.js
@@ -58,14 +58,6 @@ const APP_CENTER_APP_NAME = 'app-center';
/** Puter's AI app builder, which generates an app from a description. */
const BUILDER_APP_NAME = 'builder';
-// -- App Center discovery under search --
-// When a search matches none of the user's own apps, the same query is put to
-// the App Center catalogue, so "I don't have it" continues into "here it is"
-// without leaving the tab. Shown only on the no-local-matches state — a query
-// that found the user's apps already answered them.
-const DISCOVER_PAGE_SIZE = 8;
-const DISCOVER_DEBOUNCE_MS = 250;
-
// -- Drag-to-reorder tuning --
const DRAG_START_DISTANCE = 5; // px a pointer must travel before a drag begins
const MODE_LONGPRESS_MS = 500; // hold on empty grid space before reorder mode engages
@@ -844,11 +836,6 @@ const TabApps = {
// their tiles (the mirror of _removedLocal).
_arriving: null,
_pendingInstalls: null,
- // Latest App Center answer for the search box ({ query, items }), plus
- // the debounce timer and a sequence guard against out-of-order responses.
- _discover: null,
- _discoverTimer: null,
- _discoverSeq: 0,
html () {
let h = '
';
@@ -942,26 +929,6 @@ const TabApps = {
$el_window.on('input', '.myapps-search', function () {
self.updateSearchIcons($el_window);
self.renderApps($el_window);
- self._queueDiscover($el_window);
- });
-
- // Launch an App Center discovery straight from the search results.
- // Distinct from '.myapps-tile': discovery tiles take no part in
- // drag-reorder, folders, or the running-dot machinery.
- const launchDiscovery = function () {
- const name = this.dataset.appName;
- if ( ! name || TabApps._launchingApps.has(name) ) return;
- TabApps._launchingApps.add(name);
- launch_app({ name, maximized: true })
- .catch(err => console.error(`Failed to launch ${name}:`, err))
- .finally(() => TabApps._launchingApps.delete(name));
- };
- $el_window.on('click', '.myapps-discover-tile', launchDiscovery);
- $el_window.on('keydown', '.myapps-discover-tile', function (e) {
- if ( e.key === 'Enter' || e.key === ' ' ) {
- e.preventDefault();
- launchDiscovery.call(this);
- }
});
// Clear search on cross click
@@ -1436,7 +1403,7 @@ const TabApps = {
this._pageCount = Math.ceil(items.length / layout.perPage);
this._page = Math.min(Math.floor(anchorIndex / layout.perPage), this._pageCount - 1);
- $container.html((no_matches ? buildNoMatchesHtml() + this._discoverHtml(query) : '')
+ $container.html((no_matches ? buildNoMatchesHtml() : '')
+ buildPagerHtml(items, layout, instant));
// A tile mid-arrival (a deep-link landing installing its app — see
// _spliceDeepLinkApp) stays parked invisible across re-renders; the
@@ -1478,89 +1445,6 @@ const TabApps = {
}, { passive: true });
},
- // -- App Center discovery under search --
-
- /**
- * The "From the App Center" strip for the no-local-matches state, from
- * the cached catalogue answer. Empty until the fetch for exactly this
- * query has landed — a stale strip would answer the wrong question.
- */
- _discoverHtml (query) {
- const discover = this._discover;
- if ( ! discover || discover.query !== query || discover.items.length === 0 ) {
- return '';
- }
- let h = '
';
- h += '
From the App Center
';
- h += '
';
- for ( const item of discover.items ) {
- h += `
`;
- h += item.icon
- ? `
})
`
- : '
';
- h += `
${html_encode(item.title)}`;
- h += '
';
- }
- h += '
';
- return h;
- },
-
- /** Debounced catalogue lookup for the current search box contents. */
- _queueDiscover ($el_window) {
- clearTimeout(this._discoverTimer);
- const query = String($el_window.find('.myapps-search').val() || '').trim();
- if ( ! query ) {
- this._discover = null;
- return;
- }
- // Already answered — nothing to fetch, nothing to re-render.
- if ( this._discover?.query === query ) return;
- const self = this;
- this._discoverTimer = setTimeout(async () => {
- const seq = ++self._discoverSeq;
- let items = [];
- try {
- const resp = await fetch(
- `${window.api_origin}/marketplace/search?q=${encodeURIComponent(query)}&page=1&pageSize=${DISCOVER_PAGE_SIZE}`,
- );
- if ( resp.ok ) {
- const body = await resp.json();
- items = Array.isArray(body?.items) ? body.items : [];
- }
- } catch {
- // Offline or the catalogue is down — the empty state simply
- // stays as it was.
- }
- // A newer keystroke owns the strip now.
- if ( seq !== self._discoverSeq ) return;
-
- // What the user already has isn't a discovery.
- const owned = new Set();
- for ( const app of self._apps || [] ) {
- if ( app.name ) owned.add(String(app.name).toLowerCase());
- if ( app.uid || app.uuid ) owned.add(String(app.uid || app.uuid).toLowerCase());
- }
- self._discover = {
- query,
- items: items
- .filter(item => item?.item_name
- && ! owned.has(String(item.item_name).toLowerCase())
- && ! owned.has(String(item.item_id || '').toLowerCase()))
- .map(item => ({
- name: String(item.item_name),
- title: String(item.item_title || item.item_name),
- icon: typeof item.icon_url === 'string' ? item.icon_url : null,
- })),
- };
- // Only the empty state renders the strip, so only re-render if
- // the query in the box is still the one this answer belongs to.
- const current = String($el_window.find('.myapps-search').val() || '').trim();
- if ( current === query ) {
- self.renderApps($el_window, { preservePage: true, instant: true });
- }
- }, DISCOVER_DEBOUNCE_MS);
- },
-
// Mark tiles whose app has a live window (visible OR minimized — both
// are running) with the macOS-dock-style dot. A folder wears the dot when
// anything inside it is running — the apps it hides are exactly the ones
diff --git a/src/gui/src/css/dashboard.css b/src/gui/src/css/dashboard.css
index 0bff7d247..74510112b 100644
--- a/src/gui/src/css/dashboard.css
+++ b/src/gui/src/css/dashboard.css
@@ -921,64 +921,6 @@ input.myapps-search:disabled {
padding: 20px 0 18px;
}
-/* "From the App Center" strip under a search with no local matches. */
-.myapps-discover {
- padding: 0 8px 16px;
-}
-
-.myapps-discover-title {
- font-size: 13px;
- font-weight: 500;
- color: var(--dashboard-text-tertiary);
- margin-bottom: 10px;
- text-align: center;
-}
-
-.myapps-discover-row {
- display: flex;
- flex-wrap: wrap;
- justify-content: center;
- gap: 14px;
-}
-
-.myapps-discover-tile {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 6px;
- width: 96px;
- padding: 10px 4px;
- border-radius: 10px;
- cursor: pointer;
- text-align: center;
-}
-
-.myapps-discover-tile:hover,
-.myapps-discover-tile:focus-visible {
- background: var(--dashboard-hover-bg, rgba(127, 127, 127, 0.12));
-}
-
-.myapps-discover-tile img,
-.myapps-discover-tile-blank {
- width: 48px;
- height: 48px;
- border-radius: 10px;
- object-fit: cover;
-}
-
-.myapps-discover-tile-blank {
- background: rgba(127, 127, 127, 0.15);
-}
-
-.myapps-discover-tile span {
- font-size: 12px;
- color: var(--dashboard-text-secondary);
- max-width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
/* iOS-style pager: pages snap horizontally, dots below, hover arrows */
.myapps-pager {