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 + + + + Members + + + + + Adopters + + + + + 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