mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-09-05 23:57:19 +08:00
feat: enhance PluginsPage layout with flexible tab content and improved overflow handling
This commit is contained in:
@@ -66,3 +66,28 @@ body { font-family: system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto
|
|||||||
.processors-tabs .ant-tabs-tabpane-active {
|
.processors-tabs .ant-tabs-tabpane-active {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.plugins-tabs {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
.plugins-tabs .ant-tabs-content-holder,
|
||||||
|
.plugins-tabs .ant-tabs-content {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.plugins-tabs .ant-tabs-tabpane {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.plugins-tabs .ant-tabs-tabpane-active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ const PluginsPage = memo(function PluginsPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div style={{ height: 'calc(100vh - 88px)', display: 'flex', flexDirection: 'column', minHeight: 0, overflow: 'hidden' }}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12, flexWrap: 'wrap' }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12, flexWrap: 'wrap' }}>
|
||||||
<Button type="primary" onClick={() => setAdding(true)}>{t('Install App')}</Button>
|
<Button type="primary" onClick={() => setAdding(true)}>{t('Install App')}</Button>
|
||||||
{tab === 'installed' && <Button onClick={reload} loading={loading}>{t('Refresh')}</Button>}
|
{tab === 'installed' && <Button onClick={reload} loading={loading}>{t('Refresh')}</Button>}
|
||||||
@@ -350,12 +350,13 @@ const PluginsPage = memo(function PluginsPage() {
|
|||||||
<Tabs
|
<Tabs
|
||||||
activeKey={tab}
|
activeKey={tab}
|
||||||
onChange={(k) => setTab(k as any)}
|
onChange={(k) => setTab(k as any)}
|
||||||
|
className="plugins-tabs"
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
key: 'installed',
|
key: 'installed',
|
||||||
label: t('Installed'),
|
label: t('Installed'),
|
||||||
children: (
|
children: (
|
||||||
<>
|
<div style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
|
||||||
<Input
|
<Input
|
||||||
placeholder={t('Search name/author/url/extension')}
|
placeholder={t('Search name/author/url/extension')}
|
||||||
@@ -366,30 +367,32 @@ const PluginsPage = memo(function PluginsPage() {
|
|||||||
onPressEnter={() => reload()}
|
onPressEnter={() => reload()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{loading ? (
|
<div style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: 4 }}>
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 12 }}>
|
{loading ? (
|
||||||
{Array.from({ length: 6 }).map((_, i) => (
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 12 }}>
|
||||||
<Card key={i} style={{ borderRadius: 10 }}>
|
{Array.from({ length: 6 }).map((_, i) => (
|
||||||
<Skeleton active avatar paragraph={{ rows: 3 }} />
|
<Card key={i} style={{ borderRadius: 10 }}>
|
||||||
</Card>
|
<Skeleton active avatar paragraph={{ rows: 3 }} />
|
||||||
))}
|
</Card>
|
||||||
</div>
|
))}
|
||||||
) : (filteredSystemApps.length + filtered.length) === 0 ? (
|
</div>
|
||||||
<Empty description={t('No plugins')} />
|
) : (filteredSystemApps.length + filtered.length) === 0 ? (
|
||||||
) : (
|
<Empty description={t('No plugins')} />
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))', gap: 12 }}>
|
) : (
|
||||||
{filteredSystemApps.map(renderSystemCard)}
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))', gap: 12 }}>
|
||||||
{filtered.map(renderCard)}
|
{filteredSystemApps.map(renderSystemCard)}
|
||||||
</div>
|
{filtered.map(renderCard)}
|
||||||
)}
|
</div>
|
||||||
</>
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'discover',
|
key: 'discover',
|
||||||
label: t('Discover'),
|
label: t('Discover'),
|
||||||
children: (
|
children: (
|
||||||
<>
|
<div style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12, flexWrap: 'wrap' }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12, flexWrap: 'wrap' }}>
|
||||||
<Input
|
<Input
|
||||||
placeholder={t('Search apps')}
|
placeholder={t('Search apps')}
|
||||||
@@ -417,34 +420,36 @@ const PluginsPage = memo(function PluginsPage() {
|
|||||||
Foxel Center
|
Foxel Center
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{repoLoading ? (
|
<div style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: 4 }}>
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 12 }}>
|
{repoLoading ? (
|
||||||
{Array.from({ length: 6 }).map((_, i) => (
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 12 }}>
|
||||||
<Card key={i} style={{ borderRadius: 10 }}>
|
{Array.from({ length: 6 }).map((_, i) => (
|
||||||
<Skeleton active avatar paragraph={{ rows: 3 }} />
|
<Card key={i} style={{ borderRadius: 10 }}>
|
||||||
</Card>
|
<Skeleton active avatar paragraph={{ rows: 3 }} />
|
||||||
))}
|
</Card>
|
||||||
</div>
|
))}
|
||||||
) : repoItems.length === 0 ? (
|
|
||||||
<Empty description={t('No results')} />
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))', gap: 12 }}>
|
|
||||||
{repoItems.map(renderRepoCard)}
|
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', justifyContent: 'center', marginTop: 12 }}>
|
) : repoItems.length === 0 ? (
|
||||||
<Pagination
|
<Empty description={t('No results')} />
|
||||||
current={repoPage}
|
) : (
|
||||||
pageSize={repoPageSize}
|
<>
|
||||||
total={repoTotal}
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))', gap: 12 }}>
|
||||||
showSizeChanger
|
{repoItems.map(renderRepoCard)}
|
||||||
pageSizeOptions={[12, 24, 48].map(String)}
|
</div>
|
||||||
onChange={(p, ps) => { setRepoPage(p); setRepoPageSize(ps); }}
|
<div style={{ display: 'flex', justifyContent: 'center', marginTop: 12 }}>
|
||||||
/>
|
<Pagination
|
||||||
</div>
|
current={repoPage}
|
||||||
</>
|
pageSize={repoPageSize}
|
||||||
)}
|
total={repoTotal}
|
||||||
</>
|
showSizeChanger
|
||||||
|
pageSizeOptions={[12, 24, 48].map(String)}
|
||||||
|
onChange={(p, ps) => { setRepoPage(p); setRepoPageSize(ps); }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
@@ -463,7 +468,7 @@ const PluginsPage = memo(function PluginsPage() {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user