Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
609184a
feat: refreshing UX/UI
gnugomez Jul 1, 2026
9b33fa9
chore: cleaning up redesign implementation
gnugomez Jul 1, 2026
053f2be
feat: adding some more shortcuts
gnugomez Jul 2, 2026
466a2ac
fix: removing some unnecessary hooks/contexts
gnugomez Jul 2, 2026
1b58875
refactor: improving search implementation following react good practices
gnugomez Jul 2, 2026
10800fe
fix: wrong negative margin
gnugomez Jul 2, 2026
a4885ae
feat: some UI consistency improvements
gnugomez Jul 2, 2026
13a68ee
fix: cancel pending debounced search on unmount and route change
gnugomez Jul 2, 2026
1661c30
fix: redirect legacy search URLs to the new search route
gnugomez Jul 2, 2026
6c761c7
fix: restore ExtensionCategory and getCategories in the public API
gnugomez Jul 2, 2026
c40011c
fix: fetch home page rows with TanStack Query
gnugomez Jul 2, 2026
7694b7d
fix: use router location in useSearch and push history when entering …
gnugomez Jul 2, 2026
0fa5b60
fix: ignore global shortcuts while a popup or dialog has focus
gnugomez Jul 2, 2026
420fd28
fix: remove redundant debounce from extension list fetches
gnugomez Jul 2, 2026
d8e6773
refactor: consolidate floating surface styling in the theme
gnugomez Jul 2, 2026
cffddb0
fix: keep footer below the fold on short pages
gnugomez Jul 2, 2026
389bf28
refactor: convert px values to rem
gnugomez Jul 2, 2026
9d2ec88
fix: enforce viewport min-height on main content
gnugomez Jul 2, 2026
825b3bc
refactor: merge category data into a single module
gnugomez Jul 2, 2026
83ba1d6
refactor: move query sync into SearchProvider and slim useSearch
gnugomez Jul 2, 2026
29aa0ca
refactor: move hooks and context files to their conventional directories
gnugomez Jul 2, 2026
d5760a7
chore: remove dead props and simplify card stagger
gnugomez Jul 2, 2026
47085d1
feat: improve accessibility of search and category controls
gnugomez Jul 2, 2026
791208f
refactor: share focus ring and hover primitives, dedup menu item styles
gnugomez Jul 2, 2026
8fde429
fix: align namespace detail and search page with new card and icon types
gnugomez Jul 2, 2026
a7143d7
feat: scroll selected category pill into view
gnugomez Jul 2, 2026
7847693
feat: add keyboard focus outline to pills, cards and footer controls
gnugomez Jul 2, 2026
83b50c2
fix: stop sidebar scroll container clipping focus outlines
gnugomez Jul 2, 2026
63c1efd
fix: match compact navbar mark size to the full logo
gnugomez Jul 2, 2026
130f595
fix: center toolbar logo vertically on all pages
gnugomez Jul 2, 2026
404d5f9
fix: balance spacing around mobile navbar mark
gnugomez Jul 2, 2026
626ba7b
feat: open first result on Enter from the search input
gnugomez Jul 2, 2026
9d2b4ca
feat: share a results cursor between the search input and the grid
gnugomez Jul 2, 2026
9deca40
refactor: consume signals as objects with typed payloads
gnugomez Jul 2, 2026
381d357
refactor: renaming seach focus signals
gnugomez Jul 2, 2026
231690d
refactor: rebuild the results grid navigation as a declarative cursor
gnugomez Jul 3, 2026
3d7e809
feat: make the home page and footer fully replaceable
gnugomez Jul 3, 2026
d3c6628
fix: only push the footer under the fold on mobile
gnugomez Jul 3, 2026
7d40bdf
fix: ease the navbar tint fade to remove its visible edge
gnugomez Jul 3, 2026
fa0e128
feat: make the search field background translucent
gnugomez Jul 3, 2026
ea4927a
fix: adding scroll-to-top component
gnugomez Jul 3, 2026
ca89a61
chore: updating changelog
gnugomez Jul 3, 2026
9947d33
chore: deleting unnecesary package-lock
gnugomez Jul 3, 2026
76693ad
chore: use full license headers
gnugomez Jul 3, 2026
bf947f5
feat: using curated sections sortby as on see all filter
gnugomez Jul 3, 2026
4e79592
feat: expose keyboard shortcuts and co-locate them with their controls
gnugomez Jul 3, 2026
2ac832e
chore: updating yarn.lock
gnugomez Jul 3, 2026
282a985
feat: using Section primitive in search
gnugomez Jul 3, 2026
81f0832
fix: theme has wrong xs value
gnugomez Jul 3, 2026
18c3368
fix: improving layered navbar blur
gnugomez Jul 5, 2026
3b8241b
feat: improving search-bar focust behaviour
gnugomez Jul 5, 2026
622ad0e
refactor: split search coordination into focus and page-bar contexts
gnugomez Jul 5, 2026
81795c8
fix: harden search field behavior across entry points
gnugomez Jul 5, 2026
c3f44de
fix: removing unnecessary footer links + adjusting bottom padding
gnugomez Jul 6, 2026
8176db4
Merge origin/main into gnugomez/main/redesing
gnugomez Jul 6, 2026
36cb623
fix: inconsistencies with the theme
gnugomez Jul 6, 2026
30774aa
fix: refining the view transition animation
gnugomez Jul 7, 2026
472c29c
fix: simplify nav gradient blur implementation
gnugomez Jul 7, 2026
e57e271
feat: adapting extension-details to new design
gnugomez Jul 7, 2026
173ce67
Merge remote-tracking branch 'origin/main' into gnugomez/main/redesing
gnugomez Jul 7, 2026
175ce20
chore: updating default page-settigs
gnugomez Jul 7, 2026
2e1d8c9
fix: removing duplicated v tag from footer version
gnugomez Jul 7, 2026
5960a8c
Merge remote-tracking branch 'origin/main' into gnugomez/main/redesing
gnugomez Jul 8, 2026
409f577
feat: re-styling banner
gnugomez Jul 9, 2026
b2f6c32
feat: misc style changes
gnugomez Jul 9, 2026
9e0d094
feat: exporting logo component
gnugomez Jul 9, 2026
7e71b2f
feat: updating mobile menu collapsible to popover
gnugomez Jul 9, 2026
8b483a0
feat: allowing get-involved section to open internal links
gnugomez Jul 9, 2026
e642ddd
feat: adapt footer links to support internal routing
gnugomez Jul 9, 2026
7f8452b
fix: replace usage of :first-child
gnugomez Jul 9, 2026
6d8aaa1
fix: grid layout breaks on mobile
gnugomez Jul 9, 2026
7730c34
feat: adding grid layout to namespace details page
gnugomez Jul 9, 2026
27b66eb
fix: prevent nav search field from zooming on mobile
gnugomez Jul 9, 2026
768227c
feat: adding skeletons for extension cards
gnugomez Jul 10, 2026
fd03184
feat: using skeletons in search
gnugomez Jul 10, 2026
461e4db
chore: incrementing serach page size
gnugomez Jul 10, 2026
aecd71d
fix: extension-list fade-in animation is shared with skeletons
gnugomez Jul 10, 2026
6fce8fb
feat: using tanstack query for search
gnugomez Jul 13, 2026
11e96e4
feat: making browse categories more compact
gnugomez Jul 14, 2026
7b8cafc
feat: improving back navigation to search
gnugomez Jul 14, 2026
7d46e09
fix: browse categories hide some names
gnugomez Jul 15, 2026
ee3674c
Merge branch 'main' into gnugomez/main/redesing
netomi Jul 15, 2026
c4dfed9
Merge branch 'main' into gnugomez/main/redesing
gnugomez Jul 16, 2026
342f826
feat: updating selected tab fill color
gnugomez Jul 16, 2026
64d8273
feat: improve scroll behaviour on tab-switching
gnugomez Jul 16, 2026
2de9a5d
compact user avatar
netomi Jul 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions webui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@ This change log covers only the frontend library (webui) of Open VSX.

### Added

- Add a home page with hero search, popular searches, a category browser, curated extension rows and get-involved cards
- Add a dedicated search page under `/search` with query, category, sort field and sort order synced to the URL
- Add global keyboard shortcuts
- Add keyboard navigation of search results: `↑`/`↓`
- Add a structured footer
- Add scroll-to-top on forward navigation
- Support searching users and managing their roles in the admin dashboard ([#1847](https://github.com/eclipse-openvsx/openvsx/pull/1847))
- Added an extension details page to admin dashboard and user settings ([#1939](https://github.com/eclipse-openvsx/openvsx/pull/1939))

### Changed

- Redesign the web UI: new navbar with integrated search field, new theme, extension cards, category pills and page layout
- Improve accessibility: visible focus outlines on interactive controls
- Morph the hero search into the navbar search field using the View Transitions API
- Token display in generate-token dialog now uses a masked input with show/hide toggle and copy button ([#1966](https://github.com/eclipse-openvsx/openvsx/pull/1966)
- Migrate admin dashboard to use `@tanstack/react-query` ([#1917](https://github.com/eclipse-openvsx/openvsx/pull/1917)
- Replace formatting from `stylistic` with `prettier` ([#1916](https://github.com/eclipse-openvsx/openvsx/pull/1916))
Expand Down
3 changes: 0 additions & 3 deletions webui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
</head>

<body>
Expand Down
3 changes: 3 additions & 0 deletions webui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@fontsource-variable/geist": "^5.2.9",
"@fontsource-variable/geist-mono": "^5.2.8",
"@fontsource/roboto": "^5.2.10",
"@mdit/plugin-alert": "^0.22.3",
"@mui/base": "^5.0.0-beta.9",
"@mui/icons-material": "^5.15.14",
Expand Down
101 changes: 61 additions & 40 deletions webui/src/components/banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,53 +9,75 @@
********************************************************************************/

import { FunctionComponent, PropsWithChildren } from 'react';
import { Paper, Grid, Button, Collapse } from '@mui/material';
import { Box, Button, Collapse, IconButton } from '@mui/material';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import WarningAmberRoundedIcon from '@mui/icons-material/WarningAmberRounded';
import CloseIcon from '@mui/icons-material/Close';

const VARIANTS = {
info: { Icon: InfoOutlinedIcon, bg: 'accentSoft', accent: 'secondary.light' },
warning: { Icon: WarningAmberRoundedIcon, bg: 'warningSoft', accent: 'warningAccent' }
} as const;

export const Banner: FunctionComponent<PropsWithChildren<BannerProps>> = props => {
const cardColor = props.theme === 'dark' ? '#fff' : '#000';
const cardBackground = `${props.color}.${props.theme}`;
const { color = 'info', open, showDismissButton, dismissButtonLabel, dismissButtonOnClick, children } = props;
const { Icon, bg, accent } = VARIANTS[color];
return (
<Collapse in={props.open}>
<Paper
elevation={0}
<Collapse in={open} timeout={{ enter: 800, exit: 300 }}>
<Box
sx={{
display: 'block',
width: '100%',
mx: 'auto',
pb: 2,
pr: 2,
pl: 2,
pt: 2,
color: cardColor,
bgcolor: cardBackground,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
gap: '1rem',
minHeight: '2.25rem',
py: '0.375rem',
// Left/right edges line up with the navbar content.
px: { xs: '0.625rem', sm: '1.75rem' },
bgcolor: bg,
color: 'text.primary',
// The link in the consumer content follows the tone's accent.
'& a': {
color: cardColor,
fontWeight: 'bold'
color: accent,
fontWeight: 700,
textDecoration: 'none',
'&:hover': { textDecoration: 'underline' }
}
}}>
<Grid container spacing={2}>
<Grid item xs={12} sm sx={{ alignSelf: 'center' }}>
{props.children}
</Grid>
{props.showDismissButton && (
<Grid
item
xs={12}
sm='auto'
sx={{
<Box sx={{ display: 'flex', alignItems: 'center', gap: '0.5rem', minWidth: 0 }}>
<Icon sx={{ color: accent, fontSize: '1.125rem', flexShrink: 0 }} />
<Box component='span' sx={{ fontSize: '0.875rem', lineHeight: 1.4 }}>
{children}
</Box>
</Box>
{showDismissButton &&
(dismissButtonLabel ? (
<Button
variant='text'
onClick={dismissButtonOnClick}
sx={theme => ({
flexShrink: 0,
color: accent,
px: 2,
py: 0.5,
fontWeight: 600,
fontSize: '0.8125rem',
whiteSpace: 'nowrap',
alignSelf: 'center',
display: 'flex',
justifyContent: 'center',
flexBasis: '100%'
}}>
<Button variant='outlined' onClick={props.dismissButtonOnClick}>
{props.dismissButtonLabel ?? 'Close'}
</Button>
</Grid>
)}
</Grid>
</Paper>
borderRadius: `${theme.shape.borderRadius}px`,
'&:hover': { backgroundColor: 'color-mix(in srgb, currentColor 8%, transparent)' }
})}>
{dismissButtonLabel}
</Button>
) : (
<IconButton
size='small'
aria-label='Dismiss'
onClick={dismissButtonOnClick}
sx={{ flexShrink: 0, color: 'inherit', mr: '-0.375rem' }}>
<CloseIcon sx={{ fontSize: '1.125rem' }} />
</IconButton>
))}
</Box>
</Collapse>
);
};
Expand All @@ -66,5 +88,4 @@ interface BannerProps {
dismissButtonLabel?: string;
dismissButtonOnClick?: () => void;
color?: 'info' | 'warning';
theme?: 'light' | 'dark';
}
65 changes: 65 additions & 0 deletions webui/src/components/categories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/********************************************************************************
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/

import { FunctionComponent } from 'react';
import { SvgIconProps } from '@mui/material';
import DataObjectIcon from '@mui/icons-material/DataObject';
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
import SpellcheckIcon from '@mui/icons-material/Spellcheck';
import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft';
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import PaletteIcon from '@mui/icons-material/Palette';
import BugReportIcon from '@mui/icons-material/BugReport';
import AccountTreeIcon from '@mui/icons-material/AccountTree';
import KeyboardIcon from '@mui/icons-material/Keyboard';
import ExtensionIcon from '@mui/icons-material/Extension';
import BarChartIcon from '@mui/icons-material/BarChart';
import TranslateIcon from '@mui/icons-material/Translate';
import InsightsIcon from '@mui/icons-material/Insights';
import ModelTrainingIcon from '@mui/icons-material/ModelTraining';
import MenuBookIcon from '@mui/icons-material/MenuBook';
import GridViewIcon from '@mui/icons-material/GridView';
import { CATEGORIES, ExtensionCategory } from '../extension-registry-types';

export const DefaultCategoryIcon: FunctionComponent<SvgIconProps> = GridViewIcon;

// The category list itself lives in extension-registry-types; this record is
// compile-checked to stay exhaustive when categories are added or removed.
export const CATEGORY_ICONS: Record<ExtensionCategory, FunctionComponent<SvgIconProps>> = {
AI: AutoAwesomeIcon,
'Programming Languages': DataObjectIcon,
Snippets: ContentCopyIcon,
Linters: SpellcheckIcon,
Themes: PaletteIcon,
Debuggers: BugReportIcon,
Formatters: FormatAlignLeftIcon,
Keymaps: KeyboardIcon,
'SCM Providers': AccountTreeIcon,
Other: GridViewIcon,
'Extension Packs': ExtensionIcon,
'Language Packs': TranslateIcon,
'Data Science': InsightsIcon,
'Machine Learning': ModelTrainingIcon,
Visualization: BarChartIcon,
Notebooks: MenuBookIcon
};

const SORTED_CATEGORIES: ExtensionCategory[] = [...CATEGORIES].sort((a, b) => {
if (a === 'Other') return 1;
if (b === 'Other') return -1;
return a.localeCompare(b);
});

export function useCategories(): ExtensionCategory[] {
return SORTED_CATEGORIES;
}
63 changes: 63 additions & 0 deletions webui/src/components/category-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/********************************************************************************
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/

import { FunctionComponent } from 'react';
import { Box, ButtonBase, SvgIconProps, Typography } from '@mui/material';
import { styled } from '@mui/material/styles';
import { cardHoverLift, cardSurface, focusOutline } from './page-primitives';

const Root = styled(ButtonBase)(({ theme }) => ({
...cardSurface(theme),
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
textAlign: 'left',
overflow: 'hidden',
flexGrow: 1,
maxWidth: '16rem',
gap: '0.625rem',
padding: '0.625rem 0.875rem 0.625rem 0.75rem',
color: theme.palette.text.primary,
transition: 'border-color 0.15s, box-shadow 0.15s, transform 0.15s',
...cardHoverLift(theme),
...focusOutline(theme),
'& .MuiTouchRipple-root': { color: theme.palette.secondary.main }
}));

export interface CategoryCardProps {
label: string;
icon: FunctionComponent<SvgIconProps>;
onClick: () => void;
}

export const CategoryCard: FunctionComponent<CategoryCardProps> = ({ label, icon: Icon, onClick }) => (
<Root onClick={onClick}>
<Box
sx={{
width: '1.875rem',
height: '1.875rem',
borderRadius: '8px',
bgcolor: 'accentSoft',
color: 'secondary.main',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0
}}>
<Icon sx={{ fontSize: '1.0625rem' }} />
</Box>
<Typography noWrap sx={{ fontSize: '0.875rem', fontWeight: 600, minWidth: 0 }}>
{label}
</Typography>
</Root>
);
64 changes: 64 additions & 0 deletions webui/src/components/category-list-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/********************************************************************************
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/

import { FunctionComponent } from 'react';
import { ButtonBase, SvgIconProps } from '@mui/material';
import { styled } from '@mui/material/styles';
import { focusOutline } from './page-primitives';

const Root = styled(ButtonBase, {
shouldForwardProp: prop => prop !== 'isSelected'
})<{ isSelected: boolean }>(({ theme, isSelected }) => ({
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
gap: '0.5rem',
width: '100%',
textAlign: 'left',
padding: '0.4375rem 0.625rem',
borderRadius: theme.shape.borderRadius,
overflow: 'hidden',
fontSize: '0.8125rem',
fontWeight: isSelected ? 600 : 400,
color: isSelected ? theme.palette.secondary.light : theme.palette.text.secondary,
backgroundColor: isSelected ? theme.palette.accentSoft : 'transparent',
marginBottom: '1px',
fontFamily: 'inherit',
transition: 'background 0.14s, color 0.14s',
'&:hover': isSelected
? {}
: {
backgroundColor: theme.palette.surface3,
color: theme.palette.text.primary
},
...focusOutline(theme)
}));

export interface CategoryListItemProps {
label: string;
icon: FunctionComponent<SvgIconProps>;
isSelected: boolean;
onClick: () => void;
}

export const CategoryListItem: FunctionComponent<CategoryListItemProps> = ({
label,
icon: Icon,
isSelected,
onClick
}) => (
<Root isSelected={isSelected} aria-current={isSelected ? 'true' : undefined} onClick={onClick}>
<Icon sx={{ fontSize: '0.9375rem', opacity: 0.75, flexShrink: 0 }} />
{label}
</Root>
);
Loading