Skip to content

Commit d76ba4b

Browse files
Merge pull request #90 from solo-io/charlesthebird/imageUrlCustomizations
Additional image url and logo customizations
2 parents c702ed2 + c3e31d3 commit d76ba4b

File tree

15 files changed

+112
-6
lines changed

15 files changed

+112
-6
lines changed

Dockerfile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ ENV VITE_PORTAL_SERVER_URL=$VITE_PORTAL_SERVER_URL \
99
VITE_OIDC_AUTH_CODE_CONFIG_CALLBACK_PATH=$VITE_OIDC_AUTH_CODE_CONFIG_CALLBACK_PATH \
1010
VITE_OIDC_AUTH_CODE_CONFIG_LOGOUT_PATH=$VITE_OIDC_AUTH_CODE_CONFIG_LOGOUT_PATH \
1111
VITE_SWAGGER_CONFIG_URL=$VITE_SWAGGER_CONFIG_URL \
12-
VITE_AUDIENCE=$VITE_AUDIENCE
12+
VITE_AUDIENCE=$VITE_AUDIENCE \
13+
VITE_HOME_IMAGE_URL=$VITE_HOME_IMAGE_URL \
14+
VITE_APIS_IMAGE_URL=$VITE_APIS_IMAGE_URL \
15+
VITE_LOGO_IMAGE_URL=$VITE_LOGO_IMAGE_URL \
16+
VITE_COMPANY_NAME=$VITE_COMPANY_NAME
1317

1418
# Copy files for build
1519
WORKDIR /app
@@ -34,4 +38,8 @@ ENTRYPOINT VITE_PORTAL_SERVER_URL=$VITE_PORTAL_SERVER_URL \
3438
VITE_OIDC_AUTH_CODE_CONFIG_LOGOUT_PATH=$VITE_OIDC_AUTH_CODE_CONFIG_LOGOUT_PATH \
3539
VITE_SWAGGER_CONFIG_URL=$VITE_SWAGGER_CONFIG_URL \
3640
VITE_AUDIENCE=$VITE_AUDIENCE \
41+
VITE_HOME_IMAGE_URL=$VITE_HOME_IMAGE_URL \
42+
VITE_APIS_IMAGE_URL=$VITE_APIS_IMAGE_URL \
43+
VITE_LOGO_IMAGE_URL=$VITE_LOGO_IMAGE_URL \
44+
VITE_COMPANY_NAME=$VITE_COMPANY_NAME \
3745
yarn build && yarn run vite preview --port 4000 --host

Makefile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,34 @@ ifneq ($(VITE_AUDIENCE),)
7676
else ifneq ($(AUDIENCE),)
7777
UI_ARGS += VITE_AUDIENCE=$(AUDIENCE)
7878
endif
79+
#
80+
# HOME_IMAGE_URL
81+
ifneq ($(VITE_HOME_IMAGE_URL),)
82+
UI_ARGS += VITE_HOME_IMAGE_URL=$(VITE_HOME_IMAGE_URL)
83+
else ifneq ($(HOME_IMAGE_URL),)
84+
UI_ARGS += VITE_HOME_IMAGE_URL=$(HOME_IMAGE_URL)
85+
endif
86+
#
87+
# APIS_IMAGE_URL
88+
ifneq ($(VITE_APIS_IMAGE_URL),)
89+
UI_ARGS += VITE_APIS_IMAGE_URL=$(VITE_APIS_IMAGE_URL)
90+
else ifneq ($(APIS_IMAGE_URL),)
91+
UI_ARGS += VITE_APIS_IMAGE_URL=$(APIS_IMAGE_URL)
92+
endif
93+
#
94+
# LOGO_IMAGE_URL
95+
ifneq ($(VITE_LOGO_IMAGE_URL),)
96+
UI_ARGS += VITE_LOGO_IMAGE_URL=$(VITE_LOGO_IMAGE_URL)
97+
else ifneq ($(LOGO_IMAGE_URL),)
98+
UI_ARGS += VITE_LOGO_IMAGE_URL=$(LOGO_IMAGE_URL)
99+
endif
100+
#
101+
# COMPANY_NAME
102+
ifneq ($(VITE_COMPANY_NAME),)
103+
UI_ARGS += VITE_COMPANY_NAME=$(VITE_COMPANY_NAME)
104+
else ifneq ($(COMPANY_NAME),)
105+
UI_ARGS += VITE_COMPANY_NAME=$(COMPANY_NAME)
106+
endif
79107

80108

81109

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
This is an example Solo.io Gloo Platform Dev Portal frontend app, built with [Vite](https://vitejs.dev/), and configured to use React and Typescript. It can be used to view information about your APIs and usage plans, add or delete API keys, and view your OpenAPI schemas using an embedded [Redoc UI](https://github.com/Redocly/redoc) or [Swagger UI](https://swagger.io/tools/swagger-ui/) view. It also can be personalized with images and colors to match your branding and preferences.
66

7+
![homepage](readme_assets/banner.png "The home page with the default images.")
8+
79
## Setup
810

911
**For the full setup instructions, including the required Gloo Gateway Kubernetes resources, please check the [solo.io docs site](https://docs.solo.io/gloo-gateway/main/portal/dev-portal/frontend/portal-frontend/). The following steps assume that these resources are already applied.**
@@ -123,6 +125,7 @@ All icons can be found, as the others, in the `/Assets` folder, inside `/Icons`.
123125

124126
You can add these environment variables to a `.env.local` file in the `projects/ui` folder. All Vite environment variables need to start with `VITE_` in order for the app to be able to read them.
125127

128+
- `VITE_COMPANY_NAME` - This is the company name that is used for your Portal.
126129
- `VITE_PORTAL_SERVER_URL` - This is the URL for the Gloo Platform Portal REST server. The default value is "/v1".
127130
- Note: If using the example `RouteTable` for the "oidcAuthorizationCode" `ExtAuthPolicy` configuration, this should be set to "/portal-server/v1"
128131
- `VITE_SWAGGER_CONFIG_URL` - This is an optional URL for your Swagger configuration file. The URL can be an absolute or relative path, and can be a JSON or YAML file. If you would like to configure the Swagger UI using the [Swagger UI configuration options](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/), you can do this by:
@@ -131,6 +134,9 @@ You can add these environment variables to a `.env.local` file in the `projects/
131134
3. verifying your changes (with the `make run-ui` command),
132135
4. rebuilding the project.
133136
- `VITE_AUDIENCE` - This is an optional parameter if using Auth0 and need to send an audience parameter in your authorization requests. This should not be URL encoded, since it will be URL encoded when the request is sent.
137+
- `VITE_HOME_IMAGE_URL` - This is an optional parameter to set the image URL on the home page.
138+
- `VITE_APIS_IMAGE_URL` - This is an optional parameter to set the image URL on the apis page.
139+
- `VITE_LOGO_IMAGE_URL` - This is an optional parameter to set the image URL for the logo in the upper left.
134140

135141
#### Environment Variables for PKCE Authorization Flow
136142

@@ -156,3 +162,11 @@ In your Keycloak administration console, make sure that "Direct Access Grants" i
156162
## Creating Releases
157163

158164
When making a new release, use the GitHub UI, and name your release in the format: v1.2.3. When the release is published, a new branch will be made (v1.2.x), and a build of that version will be tagged and published to gcr.io/solo-public/docs/portal-frontend:v1.2.3 (replacing v1.2.3 with your tag name).
165+
166+
## Screenshots
167+
168+
![homepage](readme_assets/homepage.png "The home page with the default images.")
169+
170+
![apis page](readme_assets/apis.png "The apis page with the default images.")
171+
172+
![api details page](readme_assets/api-details.png "An API details page with the default images.")

projects/ui/src/Components/Apis/gloo-gateway-components/GG_ApisPage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Box } from "@mantine/core";
22
import { Icon } from "../../../Assets/Icons";
3+
import { apisImageURL } from "../../../user_variables.tmplr";
34
import { BannerHeading } from "../../Common/Banner/BannerHeading";
45
import { BannerHeadingTitle } from "../../Common/Banner/BannerHeadingTitle";
56
import { PageContainer } from "../../Common/PageContainer";
@@ -56,6 +57,7 @@ export function GG_ApisPage() {
5657
return (
5758
<PageContainer>
5859
<BannerHeading
60+
bgImageURL={apisImageURL}
5961
title={<BannerHeadingTitle text={"APIs"} logo={<Icon.CodeGear />} />}
6062
description={
6163
"Browse the list of APIs and documentation in this portal. From here you can get the information you need to make API calls."

projects/ui/src/Components/Apis/gloo-mesh-gateway-components/GMG_ApisPage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useState } from "react";
22
import { Icon } from "../../../Assets/Icons";
3+
import { apisImageURL } from "../../../user_variables.tmplr";
34
import { BannerHeading } from "../../Common/Banner/BannerHeading";
45
import { BannerHeadingTitle } from "../../Common/Banner/BannerHeadingTitle";
56
import { ErrorBoundary } from "../../Common/ErrorBoundary";
@@ -29,6 +30,7 @@ export function GMG_ApisPage() {
2930
return (
3031
<PageContainer>
3132
<BannerHeading
33+
bgImageURL={apisImageURL}
3234
title={<BannerHeadingTitle text={"APIs"} logo={<Icon.CodeGear />} />}
3335
description={
3436
"Browse the list of APIs and documentation in this portal. From here you can get the information you need to make API calls."

projects/ui/src/Components/Common/Banner/BannerHeading.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,11 @@ export function BannerHeading({
4545
</Styles.BannerContent>
4646

4747
<Styles.BannerImageContainer pageContentIsWide={pageContentIsWide}>
48-
<img src={bgImageURL ?? Banner} alt="background" role="banner" />
48+
<img
49+
src={!!bgImageURL ? bgImageURL : Banner}
50+
alt="background"
51+
role="banner"
52+
/>
4953
</Styles.BannerImageContainer>
5054
</Styles.BannerHeadingContentContainer>
5155
</>

projects/ui/src/Components/Common/CustomPagination.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface CustomPaginationData<T> {
1616
onPageSizeChange: (value: string | null) => void;
1717
totalPages: number;
1818
totalItems: number;
19+
pageOptions: PageOptions;
1920
}
2021

2122
interface PageOptions {
@@ -80,6 +81,7 @@ export function useCustomPagination<T>(
8081
},
8182
totalPages: Math.ceil(data.length / pageSize),
8283
totalItems: data.length,
84+
pageOptions: pageOptions,
8385
};
8486
}
8587

@@ -122,10 +124,15 @@ const CustomPagination = ({
122124
pageSizeOptions,
123125
onPageSizeChange,
124126
totalItems,
127+
pageOptions,
125128
},
126129
}: {
127130
customPaginationData: CustomPaginationData<any>;
128131
}) => {
132+
// If there aren't enough items to be able to use pagination, don't show anything.
133+
if (pageOptions.options.length > 0 && totalItems <= pageOptions.options[0]) {
134+
return null;
135+
}
129136
return (
130137
<Flex align="center" justify={"space-between"} gap={"10px"}>
131138
<TotalText>Total: {totalItems}</TotalText>

projects/ui/src/Components/Home/HomePage.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Box } from "@mantine/core";
22
import { useContext } from "react";
33
import { NavLink } from "react-router-dom";
44
import { AuthContext } from "../../Context/AuthContext";
5-
import { companyName } from "../../user_variables.tmplr";
5+
import { companyName, homeImageURL } from "../../user_variables.tmplr";
66
import { BannerHeading } from "../Common/Banner/BannerHeading";
77
import { BannerHeadingTitle } from "../Common/Banner/BannerHeadingTitle";
88
import { Button } from "../Common/Button";
@@ -22,6 +22,7 @@ export function HomePage() {
2222
<PageContainer>
2323
<div>
2424
<BannerHeading
25+
bgImageURL={homeImageURL}
2526
title={<BannerHeadingTitle text={"Developers Welcome!"} />}
2627
description={`Welcome to the ${companyName} Developer Portal. Connect, partner, and build with us to create the next generation of digital experiences.`}
2728
additionalContent={

projects/ui/src/Components/Structure/Header.style.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import styled from "@emotion/styled";
33
import { ContentWidthNav } from "../../Styles/ContentWidthHelpers";
44

55
export namespace HeaderStyles {
6+
export const StyledLogoImg = styled.img`
7+
height: 90px;
8+
padding: 5px 0px;
9+
`;
10+
611
export const StyledTopNavHeader = styled.header(
712
({ theme }) => css`
813
grid-area: header;
@@ -84,7 +89,9 @@ export namespace HeaderStyles {
8489
8590
color: ${theme.externalLinkColor};
8691
border-bottom: 4px solid white;
87-
transition: background-color 0.25s, border-bottom-color 0.25s,
92+
transition:
93+
background-color 0.25s,
94+
border-bottom-color 0.25s,
8895
color 0.25s;
8996
&.active,
9097
&.active:hover,

projects/ui/src/Components/Structure/Header.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Link, NavLink, useLocation } from "react-router-dom";
33
import { ReactComponent as Logo } from "../../Assets/logo.svg";
44
import { AppContext } from "../../Context/AppContext";
55
import { AuthContext } from "../../Context/AuthContext";
6+
import { logoImageURL } from "../../user_variables.tmplr";
67
import { ErrorBoundary } from "../Common/ErrorBoundary";
78
import { HeaderStyles } from "./Header.style";
89
import HeaderSectionLoggedIn from "./HeaderSectionLoggedIn";
@@ -63,7 +64,11 @@ export function Header() {
6364
<HeaderStyles.StyledTopNavContent pageContentIsWide={pageContentIsWide}>
6465
<div className="logoContainer">
6566
<Link to="/" aria-hidden="true">
66-
<Logo />
67+
{!!logoImageURL ? (
68+
<HeaderStyles.StyledLogoImg src={logoImageURL} alt="logo" />
69+
) : (
70+
<Logo />
71+
)}
6772
</Link>
6873
</div>
6974
<div className="siteNavigating">

projects/ui/src/user_variables.tmplr.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ function templateString(templateString: string, ...defaultValues: string[]) {
3232
//
3333
export const companyName = templateString(
3434
"{{ tmplr.company_name }}",
35-
"Acme Co."
35+
import.meta.env.VITE_COMPANY_NAME,
36+
"Example Company"
3637
);
3738
document.title = companyName + " Portal";
3839

@@ -124,3 +125,30 @@ export const audience = templateString(
124125
import.meta.env.VITE_AUDIENCE,
125126
""
126127
);
128+
129+
/**
130+
* This is optional. Used on the home ("/") page.
131+
*/
132+
export const homeImageURL = templateString(
133+
"{{ tmplr.homeImageURL }}",
134+
import.meta.env.VITE_HOME_IMAGE_URL,
135+
""
136+
);
137+
138+
/**
139+
* This is optional. Used on the API's ("/apis") page.
140+
*/
141+
export const apisImageURL = templateString(
142+
"{{ tmplr.apisImageURL }}",
143+
import.meta.env.VITE_APIS_IMAGE_URL,
144+
""
145+
);
146+
147+
/**
148+
* This is optional. Used on the upper left corder of the website.
149+
*/
150+
export const logoImageURL = templateString(
151+
"{{ tmplr.logoImageURL }}",
152+
import.meta.env.VITE_LOGO_IMAGE_URL,
153+
""
154+
);

readme_assets/api-details.png

1.6 MB
Loading

readme_assets/apis.png

1.74 MB
Loading

readme_assets/banner.png

2.14 MB
Loading

readme_assets/homepage.png

3.92 MB
Loading

0 commit comments

Comments
 (0)