diff --git a/configuration/application.yml b/configuration/application.yml
index b45bffeb8..868f97176 100644
--- a/configuration/application.yml
+++ b/configuration/application.yml
@@ -129,7 +129,7 @@ ovsx:
storage:
primary-service: azure-blob
webui:
- frontendRoutes: "/extension/**,/namespace/**,/user-settings/**,/admin-dashboard/**,/about,/publisher-agreement-*,/terms-of-use,/members"
+ frontendRoutes: "/extension/**,/namespace/**,/user-settings/**,/admin-dashboard/**,/about,/publisher-agreement-*,/terms-of-use,/members,/adopters"
eclipse:
# TODO change back to https://api.eclipse.org/ for release.
base-url: https://api-staging.eclipse.org/
diff --git a/website/dev/mock-service.ts b/website/dev/mock-service.ts
index 663bd6a80..b2d838897 100644
--- a/website/dev/mock-service.ts
+++ b/website/dev/mock-service.ts
@@ -14,7 +14,7 @@ import {
NamespaceMembershipList, AdminService, PublisherInfo, NewReview, ExtensionFilter, UrlString, MembershipRole
} from "openvsx-webui";
-const avatarUrl = 'https://upload.wikimedia.org/wikipedia/commons/1/19/Spongebob_Squarepants_as_a_balloon.jpg';
+const avatarUrl = 'https://upload.wikimedia.org/wikipedia/commons/9/99/Avatar_cupcake.png';
export class MockRegistryService extends ExtensionRegistryService {
diff --git a/website/src/about.tsx b/website/src/about.tsx
index 7fda45982..1177f0f31 100644
--- a/website/src/about.tsx
+++ b/website/src/about.tsx
@@ -9,7 +9,7 @@
********************************************************************************/
import * as React from 'react';
-import { Link, Typography, Container } from '@mui/material';
+import { Link, Typography, Container, List, ListItem, ListItemText } from '@mui/material';
import { styled, Theme } from '@mui/material/styles';
const Heading = styled(Typography)(({ theme }: { theme: Theme }) => ({
@@ -58,11 +58,24 @@ const About = () => {
- Publishing Extensions
-
- The publishing process is described in
- the openvsx Wiki.
-
+ Resources
+
+
+
+ The publishing process is described in the openvsx Wiki.
+
+
+
+
+ The FAQ section explains what you can and cannot do as a user of our service.
+
+
+
+
+ Get involved in the community.
+
+
+
;
}
diff --git a/website/src/adopters.tsx b/website/src/adopters.tsx
new file mode 100644
index 000000000..d8c4f0aff
--- /dev/null
+++ b/website/src/adopters.tsx
@@ -0,0 +1,34 @@
+import React from "react";
+import { Container, Typography, Box, Button } from "@mui/material";
+import { styled, Theme } from '@mui/material/styles';
+import AdoptersList from "./components/adopters-list";
+
+const Heading = styled(Typography)(({ theme }: { theme: Theme }) => ({
+ marginTop: theme.spacing(4),
+ marginBottom: theme.spacing(2)
+}));
+
+const Adopters = () => {
+ return (
+
+
+ Adopters
+
+
+ Our open source projects drive innovation across a broad spectrum of industries and on both private and public clouds — enabling organizations of all shapes and sizes to accelerate cloud native development with world-class tools.
+
+
+
+
+
+
+ );
+}
+
+export default Adopters;
\ No newline at end of file
diff --git a/website/src/components/adopters-list.tsx b/website/src/components/adopters-list.tsx
new file mode 100644
index 000000000..5333d5d00
--- /dev/null
+++ b/website/src/components/adopters-list.tsx
@@ -0,0 +1,163 @@
+/********************************************************************************
+ * Copyright (c) 2023 TypeFox and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+
+import React, { FunctionComponent, useState, useEffect, useContext } from 'react';
+import { CircularProgress, Grid, Box, Link, Typography } from '@mui/material';
+import { styled, Theme } from '@mui/material/styles';
+import { MainContext } from 'openvsx-webui/lib/context';
+
+interface Project {
+ project_id: string;
+ name: string;
+ url: string;
+ logo: string;
+ adopters: Adopter[];
+}
+
+interface Adopter {
+ name: string;
+ logo: string;
+ projects: string[];
+ homepage_url: string;
+ logo_white: string;
+}
+
+const AdoptersList: FunctionComponent = () => {
+ const [loaded, setLoaded] = useState(false);
+ const [adopters, setAdopters] = useState([]);
+
+ useEffect(() => {
+ if (loaded) return;
+
+ const abortController = new AbortController();
+ fetch(`https://api.eclipse.org/adopters/projects?working_group=cloud-development-tools`, {
+ signal: abortController.signal,
+ })
+ .then(async (res) => {
+ if (!res.ok) throw new Error('Failed to fetch adopters');
+
+ const projects = await res.json() as Project[];
+ const project = projects.find((p) => p.project_id == 'ecd.openvsx');
+ if(project) {
+ setAdopters(project.adopters);
+ }
+ })
+ .catch((err) => {
+ if (err instanceof DOMException && err.name === 'AbortError') return;
+ console.error(err);
+ })
+ .finally(() => abortController.signal.aborted || setLoaded(true));
+
+ return () => abortController.abort();
+ }, [loaded]);
+
+ if (adopters.length === 0) return ;
+ return (
+
+ { adopters.map(adopter =>
+
+ )}
+
+ );
+};
+
+export default AdoptersList;
+
+interface AdopterItemProps {
+ name: string;
+ logo?: string;
+ logoWhite?: string;
+ url?: string;
+}
+
+const bordered = (theme: Theme) => {
+ return {
+ border: '1px solid',
+ borderColor: theme.palette.mode === 'light'
+ ? theme.palette.grey['300']
+ : theme.palette.grey['800']
+ };
+};
+
+const HeaderBox = styled(Box)(({ theme }: { theme: Theme }) => ({
+ ...bordered(theme),
+ display: 'flex',
+ alignItems: 'center',
+ minHeight: '6rem',
+ backgroundColor: theme.palette.mode === 'light'
+ ? theme.palette.grey['300']
+ : theme.palette.grey['800']
+}));
+
+const BodyBox = styled(Box)(({ theme }: { theme: Theme }) => ({
+ ...bordered(theme),
+ display: 'flex',
+ height: '100%',
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: theme.palette.background.default
+}));
+
+const GridContainer = styled(Grid)({
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'stretch',
+ height: '18rem',
+ textAlign: 'center',
+});
+
+const AdopterItem: FunctionComponent = ({ name, logo, logoWhite, url }) => {
+ const { pageSettings } = useContext(MainContext);
+ const styles = {
+ heading: {
+ width: '100%',
+ },
+ logoContainer: {
+ width: '100%',
+ maxWidth: '8rem',
+ maxHeight: '8rem',
+ },
+ logo: {
+ width: '100%',
+ height: '100%',
+ objectFit: 'contain',
+ }
+ };
+
+ let logoUrl = pageSettings.themeType == 'dark' ? logoWhite : logo;
+ if(logoUrl) {
+ logoUrl = 'https://api.eclipse.org/adopters/assets/images/adopters/' + logoUrl;
+ }
+
+ return (
+
+
+ { url
+ ? {name}
+ : {name}
+ }
+
+
+
+ { logoUrl
+ ?
+ : {name}
+ }
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/website/src/menu-content.tsx b/website/src/menu-content.tsx
index 1a4c445bb..18069223d 100644
--- a/website/src/menu-content.tsx
+++ b/website/src/menu-content.tsx
@@ -8,18 +8,20 @@
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
-import React, { FunctionComponent, PropsWithChildren } from 'react';
-import { Theme, Typography, MenuItem, Link, Button } from '@mui/material';
+import React, { FunctionComponent, PropsWithChildren, useState, useRef } from 'react';
+import { Theme, Typography, Menu, MenuItem, Link, Button, Accordion, AccordionDetails, AccordionSummary } from '@mui/material';
import { styled } from '@mui/material/styles';
import { Link as RouteLink } from 'react-router-dom';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import GitHubIcon from '@mui/icons-material/GitHub';
import MenuBookIcon from '@mui/icons-material/MenuBook';
-import HelpIcon from '@mui/icons-material/Help';
-import ForumIcon from '@mui/icons-material/Forum';
import InfoIcon from '@mui/icons-material/Info';
import StarIcon from '@mui/icons-material/Star';
import StatusIcon from '@mui/icons-material/NetworkCheck';
import PublishIcon from '@mui/icons-material/Publish';
+import GroupWorkIcon from '@mui/icons-material/GroupWork';
+import PeopleAltIcon from '@mui/icons-material/PeopleAlt';
+import HubIcon from '@mui/icons-material/Hub';
import { UserSettingsRoutes } from 'openvsx-webui';
//-------------------- Mobile View --------------------//
@@ -71,19 +73,41 @@ export const MobileMenuContent: FunctionComponent = () => {
-
-
+
+ }
+ aria-controls="working-group-content"
+ id="working-group-header"
+ >
-
- FAQ
+
+ Working Group
-
-
+
+
+
+
+
+
+ Members
+
+
+
+
+
+
+
+ Adopters
+
+
+
+
+
-
+
-
- Community
+
+ Sponsor
@@ -95,14 +119,6 @@ export const MobileMenuContent: FunctionComponent = () => {
-
-
-
-
- Sponsor
-
-
-
{
!location.pathname.startsWith(UserSettingsRoutes.ROOT)
?
@@ -135,29 +151,62 @@ const headerItem = ({ theme }: { theme: Theme }) => ({
}
});
+const headerTypography = ({ theme }: { theme: Theme }) => ({
+ ...headerItem({theme}),
+ cursor: 'pointer'
+});
+
const MenuLink = styled(Link)(headerItem);
const MenuRouteLink = styled(RouteLink)(headerItem);
+const MenuTypography = styled(Typography)(headerTypography);
+
+const subMenuItem = ({ theme }: { theme: Theme }) => ({
+ '&:focus, &:hover': {
+ background: 'transparent'
+ }
+});
+
+const subMenuLink = ({ theme }: { theme: Theme }) => ({
+ ...headerItem({theme}),
+ margin: theme.spacing(0.5)
+});
+
+const SubMenuItem = styled(MenuItem)(subMenuItem);
+const SubMenuLink = styled(Link)(subMenuLink);
+
export const DefaultMenuContent: FunctionComponent = () => {
+ const [workingGroupMenuOpen, setWorkingGroupOpen] = useState(false);
+ const workingGroupMenuEl = useRef(null);
+ const toggleWorkingGroupMenu = () => setWorkingGroupOpen(!workingGroupMenuOpen);
+ const closeWorkingGroupMenu = () => setWorkingGroupOpen(false);
+
return <>
Documentation
-
- FAQ
-
Status
-
- Community
+ Working Group
+
+
+ Sponsor
About
-
- Sponsor
-
diff --git a/website/src/page-settings.tsx b/website/src/page-settings.tsx
index 4ba377054..3a912d471 100644
--- a/website/src/page-settings.tsx
+++ b/website/src/page-settings.tsx
@@ -20,6 +20,7 @@ import OpenVSXLogo from './openvsx-registry-logo';
import footerContent from './footer-content';
import { Document } from './document';
import About from './about';
+import Adopters from './adopters';
import Members from './members';
export default function createPageSettings(theme: Theme, prefersDarkMode: boolean): PageSettings {
@@ -64,6 +65,7 @@ export default function createPageSettings(theme: Theme, prefersDarkMode: boolea
} />
} />
} />
+ } />
>;
//---------- REPORT ABUSE LINK