Updated the UI to look like the Figma UI (#81)

* Updated the UI application to look like the latest Figma Mock-ups

Signed-off-by: Amelia-Maria Breda <ameliamaria.breda@dxc.com>
This commit is contained in:
Amelia-Maria Breda 2022-09-15 14:47:36 +03:00 committed by GitHub
parent a94293874e
commit 10a349fdcd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 749 additions and 342 deletions

View File

@ -71,7 +71,7 @@ describe('Sign in form', () => {
it('should log in the user and navigate to homepage if login is successful',async () => {
render(<SignIn isAuthEnabled={true} setIsAuthEnabled={() => { }} isLoggedIn={false} setIsLoggedIn={() => { }} />);
const submitButton = await screen.findByText(/^Continue/i);
const submitButton = await screen.findByText('Continue');
// @ts-ignore
jest.spyOn(api,"get").mockResolvedValue({status:200, data:{data:{}}});
fireEvent.click(submitButton);
@ -82,7 +82,7 @@ describe('Sign in form', () => {
it('should should display login error if login not successful',async () => {
render(<SignIn isAuthEnabled={true} setIsAuthEnabled={() => { }} isLoggedIn={false} setIsLoggedIn={() => { }} />);
const submitButton = await screen.findByText(/^Continue/i);
const submitButton = await screen.findByText('Continue');
jest.spyOn(api,"get").mockRejectedValue();;
fireEvent.click(submitButton);
const errorDisplay = await screen.findByText(/Authentication Failed/i);

View File

@ -2,6 +2,13 @@ import { fireEvent, render, screen } from '@testing-library/react';
import Tags from 'components/Tags';
import React from 'react';
const mockedUsedNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
// @ts-ignore
...jest.requireActual('react-router-dom'),
useNavigate: () => mockedUsedNavigate,
}));
const mockedTagsData = {
name: 'test',
tags: [

View File

@ -61,8 +61,8 @@ const api = {
};
const endpoints = {
imageList: '/v2/_zot/ext/search?query={RepoListWithNewestImage () { NewestImage {RepoName Tag LastUpdated Description Licenses Vendor Size Labels} }}',
detailedRepoInfo: (name) => `/v2/_zot/ext/search?query={ExpandedRepoInfo(repo:"${name}"){Images {Digest Tag Layers {Size Digest}} Summary {Name LastUpdated Size Platforms {Os Arch} Vendors NewestTag {Tag}}}}`
imageList: '/v2/_zot/ext/search?query={RepoListWithNewestImage(){ NewestImage {RepoName Tag LastUpdated Description Licenses Vendor Size Labels} }}',
detailedRepoInfo: (name) => `/v2/_zot/ext/search?query={ExpandedRepoInfo(repo:"${name}"){Images {Digest Tag Layers {Size Digest}} Summary {Name LastUpdated Size Platforms {Os Arch} Vendors NewestImage {Tag}}}}`
}
export {api, endpoints};

BIN
src/assets/Git.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/assets/Google.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,9 @@
<svg width="511" height="152" viewBox="0 0 511 152" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M78.1694 124.2C51.5207 124.2 22.8865 119.2 22.8865 108.2C22.8865 97.2002 51.5207 92.2002 78.1694 92.2002C104.818 92.2002 133.452 97.2002 133.452 108.2C133.557 119.2 104.818 124.2 78.1694 124.2ZM78.1694 98.5002C64.5838 98.5002 51.8342 99.8002 42.2198 102.2C31.7694 104.8 29.4703 107.6 29.4703 108.2C29.4703 108.8 31.7694 111.6 42.2198 114.2C51.7297 116.6 64.5838 117.9 78.1694 117.9C91.7549 117.9 104.504 116.6 114.119 114.2C124.569 111.6 126.868 108.8 126.868 108.2C126.868 107.6 124.569 104.8 114.119 102.2C104.609 99.8002 91.7549 98.5002 78.1694 98.5002Z" fill="#0F2139"/>
<path d="M78.1694 59.5C51.5207 59.5 22.8865 54.5 22.8865 43.5C22.8865 32.5 51.5207 27.5 78.1694 27.5C104.818 27.5 133.452 32.5 133.452 43.5C133.557 54.5 104.818 59.5 78.1694 59.5ZM78.1694 33.8C64.5838 33.8 51.8342 35.1 42.2198 37.5C31.7694 40.1 29.4703 42.9 29.4703 43.5C29.4703 44.1 31.7694 46.9 42.2198 49.5C51.7297 51.9 64.5838 53.2 78.1694 53.2C91.7549 53.2 104.504 51.9 114.119 49.5C124.569 46.9 126.868 44.1 126.868 43.5C126.868 42.9 124.569 40.1 114.119 37.5C104.609 35.1 91.7549 33.8 78.1694 33.8Z" fill="#0F2139"/>
<path d="M124.151 71.2998C86.4253 113.6 63.0163 119.4 57.7911 119.4C57.4776 119.4 29.3658 113.5 29.2613 113.5L28.3208 108.2C50.7893 105.9 92.0686 98.6998 124.151 71.2998Z" fill="#0F2139"/>
<path d="M86.1118 87.3C93.9497 83.8 113.387 66.5 111.193 54.5L133.452 43.5C133.557 72 92.6956 83.9 86.1118 87.3Z" fill="#0F2139"/>
<path d="M195.6 101.4H241.4V97.6002C241.4 93.4002 241.9 90.7002 242.8 89.5002C243.8 88.3002 245.5 87.6002 248 87.6002C250.1 87.6002 251.7 88.1002 252.8 89.1002C253.8 90.1002 254.4 91.5002 254.4 93.5002V105.6C254.4 107.8 253.6 109.4 252 110.3C250.4 111.3 247.6 111.7 243.5 111.7H187.8C184.4 111.7 181.8 111.1 180 110C178.2 108.9 177.3 107.2 177.3 105.1C177.3 103.8 177.7 102.5 178.4 101.4C179.2 100.2 181 98.5002 183.8 96.3002L236.4 54.5002H192.5V58.2002C192.5 62.5002 192 65.2002 191.1 66.4002C190.1 67.6002 188.4 68.2002 185.9 68.2002C183.7 68.2002 182 67.7002 180.9 66.7002C179.8 65.7002 179.2 64.3002 179.2 62.3002V50.0002C179.2 48.0002 180.2 46.5002 182.3 45.6002C184.4 44.7002 187.6 44.2002 192 44.2002H241.2C245.5 44.2002 248.7 44.8002 250.9 46.1002C253.1 47.3002 254.2 49.2002 254.2 51.6002C254.2 53.0002 253.5 54.6002 252.1 56.4002C250.7 58.2002 248.7 60.1002 245.9 62.2002L195.6 101.4Z" fill="#0F2139"/>
<path d="M376.9 77.9996C376.9 88.3996 372.4 96.9996 363.5 103.6C354.5 110.2 342.9 113.5 328.6 113.5C314.4 113.5 302.8 110.2 293.8 103.6C284.8 96.9996 280.4 88.3996 280.4 77.9996C280.4 67.5996 284.9 59.0996 293.8 52.4996C302.8 45.8996 314.3 42.5996 328.6 42.5996C342.8 42.5996 354.4 45.8996 363.4 52.4996C372.4 59.0996 376.9 67.5996 376.9 77.9996ZM328.6 103.2C338 103.2 345.8 100.8 351.8 96.0996C357.8 91.3996 360.9 85.2996 360.9 77.9996C360.9 70.6996 357.9 64.5996 351.8 59.7996C345.7 54.9996 338 52.5996 328.6 52.5996C319.2 52.5996 311.5 54.9996 305.5 59.7996C299.5 64.5996 296.4 70.6996 296.4 77.9996C296.4 85.3996 299.4 91.4996 305.4 96.1996C311.5 100.8 319.2 103.2 328.6 103.2Z" fill="#0F2139"/>
<path d="M466.8 48.2998C469.8 48.2998 472 48.6998 473.4 49.4998C474.8 50.2998 475.5 51.5998 475.5 53.3998C475.5 55.0998 474.9 56.3998 473.6 57.1998C472.3 58.0998 470.4 58.4998 467.8 58.4998H430.5V82.9998C430.5 90.9998 431.8 96.2998 434.4 98.7998C437 101.3 441.5 102.6 447.8 102.6C453.4 102.6 460.1 101.3 467.9 98.6998C475.7 96.0998 480.5 94.7998 482.3 94.7998C484 94.7998 485.5 95.2998 486.7 96.2998C487.9 97.2998 488.5 98.4998 488.5 99.8998C488.5 101.5 487.7 102.9 486.2 104.1C484.7 105.3 482.1 106.5 478.5 107.6C472.5 109.5 467.1 110.9 462.3 111.8C457.5 112.7 453 113.1 448.7 113.1C441.5 113.1 435.5 112.2 430.6 110.4C425.7 108.6 422.1 105.9 419.7 102.3C418.5 100.6 417.6 98.5998 417.1 96.1998C416.6 93.8998 416.3 90.2998 416.3 85.3998V82.9998V58.5998H400.7C398.1 58.5998 396.3 58.1998 395.1 57.3998C393.9 56.5998 393.4 55.2998 393.4 53.4998C393.4 51.4998 394.2 50.0998 395.8 49.3998C397.4 48.6998 400.8 48.2998 406 48.2998H416.4V33.2998V29.3998C416.4 27.2998 417 25.7998 418.1 24.7998C419.2 23.7998 421 23.2998 423.4 23.2998C426.1 23.2998 428 23.8998 429 25.0998C430 26.2998 430.6 29.0998 430.6 33.3998V48.1998H466.8V48.2998Z" fill="#0F2139"/>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

9
src/assets/Zot-white.svg Normal file
View File

@ -0,0 +1,9 @@
<svg width="511" height="152" viewBox="0 0 511 152" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M78.1696 124.2C51.521 124.2 22.8867 119.2 22.8867 108.2C22.8867 97.2002 51.521 92.2002 78.1696 92.2002C104.818 92.2002 133.452 97.2002 133.452 108.2C133.557 119.2 104.818 124.2 78.1696 124.2ZM78.1696 98.5002C64.584 98.5002 51.8345 99.8002 42.2201 102.2C31.7696 104.8 29.4705 107.6 29.4705 108.2C29.4705 108.8 31.7696 111.6 42.2201 114.2C51.73 116.6 64.584 117.9 78.1696 117.9C91.7552 117.9 104.505 116.6 114.119 114.2C124.57 111.6 126.869 108.8 126.869 108.2C126.869 107.6 124.57 104.8 114.119 102.2C104.609 99.8002 91.7552 98.5002 78.1696 98.5002Z" fill="white"/>
<path d="M78.1696 59.5C51.521 59.5 22.8867 54.5 22.8867 43.5C22.8867 32.5 51.521 27.5 78.1696 27.5C104.818 27.5 133.452 32.5 133.452 43.5C133.557 54.5 104.818 59.5 78.1696 59.5ZM78.1696 33.8C64.584 33.8 51.8345 35.1 42.2201 37.5C31.7696 40.1 29.4705 42.9 29.4705 43.5C29.4705 44.1 31.7696 46.9 42.2201 49.5C51.73 51.9 64.584 53.2 78.1696 53.2C91.7552 53.2 104.505 51.9 114.119 49.5C124.57 46.9 126.869 44.1 126.869 43.5C126.869 42.9 124.57 40.1 114.119 37.5C104.609 35.1 91.7552 33.8 78.1696 33.8Z" fill="white"/>
<path d="M124.151 71.2998C86.4253 113.6 63.0163 119.4 57.7911 119.4C57.4776 119.4 29.3658 113.5 29.2613 113.5L28.3208 108.2C50.7893 105.9 92.0686 98.6998 124.151 71.2998Z" fill="white"/>
<path d="M86.1118 87.3C93.9497 83.8 113.387 66.5 111.193 54.5L133.452 43.5C133.557 72 92.6956 83.9 86.1118 87.3Z" fill="white"/>
<path d="M195.6 101.4H241.4V97.6002C241.4 93.4002 241.9 90.7002 242.8 89.5002C243.8 88.3002 245.5 87.6002 248 87.6002C250.1 87.6002 251.7 88.1002 252.8 89.1002C253.8 90.1002 254.4 91.5002 254.4 93.5002V105.6C254.4 107.8 253.6 109.4 252 110.3C250.4 111.3 247.6 111.7 243.5 111.7H187.8C184.4 111.7 181.8 111.1 180 110C178.2 108.9 177.3 107.2 177.3 105.1C177.3 103.8 177.7 102.5 178.4 101.4C179.2 100.2 181 98.5002 183.8 96.3002L236.4 54.5002H192.5V58.2002C192.5 62.5002 192 65.2002 191.1 66.4002C190.1 67.6002 188.4 68.2002 185.9 68.2002C183.7 68.2002 182 67.7002 180.9 66.7002C179.8 65.7002 179.2 64.3002 179.2 62.3002V50.0002C179.2 48.0002 180.2 46.5002 182.3 45.6002C184.4 44.7002 187.6 44.2002 192 44.2002H241.2C245.5 44.2002 248.7 44.8002 250.9 46.1002C253.1 47.3002 254.2 49.2002 254.2 51.6002C254.2 53.0002 253.5 54.6002 252.1 56.4002C250.7 58.2002 248.7 60.1002 245.9 62.2002L195.6 101.4Z" fill="white"/>
<path d="M376.9 77.9996C376.9 88.3996 372.4 96.9996 363.5 103.6C354.5 110.2 342.9 113.5 328.6 113.5C314.4 113.5 302.8 110.2 293.8 103.6C284.8 96.9996 280.4 88.3996 280.4 77.9996C280.4 67.5996 284.9 59.0996 293.8 52.4996C302.8 45.8996 314.3 42.5996 328.6 42.5996C342.8 42.5996 354.4 45.8996 363.4 52.4996C372.4 59.0996 376.9 67.5996 376.9 77.9996ZM328.6 103.2C338 103.2 345.8 100.8 351.8 96.0996C357.8 91.3996 360.9 85.2996 360.9 77.9996C360.9 70.6996 357.9 64.5996 351.8 59.7996C345.7 54.9996 338 52.5996 328.6 52.5996C319.2 52.5996 311.5 54.9996 305.5 59.7996C299.5 64.5996 296.4 70.6996 296.4 77.9996C296.4 85.3996 299.4 91.4996 305.4 96.1996C311.5 100.8 319.2 103.2 328.6 103.2Z" fill="white"/>
<path d="M466.8 48.2998C469.8 48.2998 472 48.6998 473.4 49.4998C474.8 50.2998 475.5 51.5998 475.5 53.3998C475.5 55.0998 474.9 56.3998 473.6 57.1998C472.3 58.0998 470.4 58.4998 467.8 58.4998H430.5V82.9998C430.5 90.9998 431.8 96.2998 434.4 98.7998C437 101.3 441.5 102.6 447.8 102.6C453.4 102.6 460.1 101.3 467.9 98.6998C475.7 96.0998 480.5 94.7998 482.3 94.7998C484 94.7998 485.5 95.2998 486.7 96.2998C487.9 97.2998 488.5 98.4998 488.5 99.8998C488.5 101.5 487.7 102.9 486.2 104.1C484.7 105.3 482.1 106.5 478.5 107.6C472.5 109.5 467.1 110.9 462.3 111.8C457.5 112.7 453 113.1 448.7 113.1C441.5 113.1 435.5 112.2 430.6 110.4C425.7 108.6 422.1 105.9 419.7 102.3C418.5 100.6 417.6 98.5998 417.1 96.1998C416.6 93.8998 416.3 90.2998 416.3 85.3998V82.9998V58.5998H400.7C398.1 58.5998 396.3 58.1998 395.1 57.3998C393.9 56.5998 393.4 55.2998 393.4 53.4998C393.4 51.4998 394.2 50.0998 395.8 49.3998C397.4 48.6998 400.8 48.2998 406 48.2998H416.4V33.2998V29.3998C416.4 27.2998 417 25.7998 418.1 24.7998C419.2 23.7998 421 23.2998 423.4 23.2998C426.1 23.2998 428 23.8998 429 25.0998C430 26.2998 430.6 29.0998 430.6 33.3998V48.1998H466.8V48.2998Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -19,7 +19,7 @@ import FilterCard from './FilterCard.jsx';
const useStyles = makeStyles(() => ({
gridWrapper: {
// backgroundColor: "#fff",
paddingTop:"2rem",
},
nodataWrapper: {
backgroundColor: "#fff",
@ -34,7 +34,15 @@ const useStyles = makeStyles(() => ({
justifyContent:"space-between",
alignItems:"center",
color:"#00000099"
}
},
results:{
marginLeft: '1rem'
},
sortForm:{
backgroundColor: '#ffffff',
borderColor: "#E0E0E0",
borderRadius: "6px",
},
}));
function Explore ({ keywords, data, updateData }) {
@ -141,8 +149,8 @@ function Explore ({ keywords, data, updateData }) {
</Grid>
<Grid item xs={9}>
<Stack direction="row" className={classes.resultsRow}>
<Typography variant="body2" >Results {filteredData.length}</Typography>
<FormControl sx={{m:'1', minWidth:"4.6875rem"}} size="small">
<Typography variant="body2" className={classes.results}>Results {filteredData.length}</Typography>
<FormControl sx={{m:'1', minWidth:"4.6875rem"}} className={classes.sortForm} size="small">
<InputLabel>Sort</InputLabel>
<Select label="Sort" value={sortFilter} onChange={handleSortChange} MenuProps={{disableScrollLock: true}}>
<MenuItem value='relevance'>Relevance</MenuItem>

View File

@ -1,9 +1,10 @@
// react global
import {Link, useLocation} from "react-router-dom";
import {Link, useLocation, useNavigate} from "react-router-dom";
// components
import {Typography, Breadcrumbs} from '@mui/material';
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
// styling
@ -15,13 +16,16 @@ const useStyles = makeStyles((theme) => {
exploreHeader: {
backgroundColor: "#FFFFFF",
minHeight: 50,
paddingLeft: 5,
paddingLeft: "3rem",
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "center"
justifyContent: "space-between",
padding: "2rem"
},
explore: {
color: '#00000099',
color: '#52637A',
fontSize: "1rem",
letterSpacing: "0.009375rem"
}
}
@ -29,15 +33,18 @@ const useStyles = makeStyles((theme) => {
function ExploreHeader() {
const classes = useStyles();
const navigate = useNavigate();
const location = useLocation();
const path = location.pathname;
return (
<div className={classes.exploreHeader}>
<ArrowBackIcon sx={{color: "#14191F",fontSize: "2rem", cursor: "pointer"}} onClick={() => navigate(-1)}/>
<Breadcrumbs separator="/" aria-label="breadcrumb">
<Link to="/"><Typography variant="body1" className={classes.explore}>Home</Typography></Link>
{ path.includes('/image/') && <Typography className={classes.explore} variant="body1">{path.replace('/image/', '')}</Typography> }
</Breadcrumbs>
<div></div>
</div>
);
}

View File

@ -9,7 +9,9 @@ const useStyles = makeStyles(() => ({
alignItems:'flex-start',
background:"#FFFFFF",
boxShadow:"0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)",
borderRadius: "1.5rem"
borderColor: "#FFFFFF",
borderRadius: "1.5rem",
color: "#14191F",
}
}));

View File

@ -9,7 +9,7 @@ import Avatar from '@mui/material/Avatar';
// styling
import makeStyles from '@mui/styles/makeStyles';
import logo from '../assets/Zot2.svg';
import logo from '../assets/Zot-white-text.svg';
import placeholderProfileButton from '../assets/Profile_button_placeholder.svg';
@ -38,7 +38,7 @@ const useStyles = makeStyles((theme) => ({
flexDirection: "row"
},
searchIcon: {
color: "#A53692",
color: "#52637A",
paddingRight: "3%"
},
input: {
@ -57,12 +57,12 @@ const useStyles = makeStyles((theme) => ({
logoWrapper: {
},
logo: {
height: 64,
width: 64,
width: "143px",
},
userAvatar:{
height:46,
width:46
width:46,
},
link: {
color: "#000",

View File

@ -1,61 +1,74 @@
import { Grid, Stack, Typography } from '@mui/material';
import { makeStyles } from '@mui/styles';
import { api, endpoints } from 'api';
import { host } from '../host';
import {isEmpty} from 'lodash';
import React, { useEffect, useState } from 'react';
import PreviewCard from './PreviewCard';
import RepoCard from './RepoCard';
import { Grid, Stack, Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
import { api, endpoints } from "api";
import { host } from "../host";
import { isEmpty } from "lodash";
import React, { useEffect, useState } from "react";
import PreviewCard from "./PreviewCard";
import RepoCard from "./RepoCard";
const useStyles = makeStyles(() => ({
gridWrapper: {
marginTop:10
marginTop: 10,
},
nodataWrapper: {
backgroundColor: "#fff",
height: '100vh',
height: "100vh",
},
exploreText: {
color: '#C0C0C0',
color: "#C0C0C0",
display: "flex",
alignItems: "left",
},
resultsRow: {
justifyContent:"space-between",
alignItems:"center",
color:"#00000099"
justifyContent: "space-between",
alignItems: "center",
color: "#00000099",
},
title: {
fontWeight:"700",
color:"#000000DE",
width:"100%",
fontWeight: "700",
color: "#0F2139",
width: "100%",
display: "inline",
fontSize: "2.5rem",
textAlign: "center",
letterSpacing: "-0.02rem",
},
sectionTitle:{
fontWeight:"700",
color:"#000000DE",
width:"100%"
titleRed: {
fontWeight: "700",
color: "#D83C0E",
width: "100%",
display: "inline",
fontSize: "2.5rem",
textAlign: "center",
letterSpacing: "-0.02rem",
},
sectionTitle: {
fontWeight: "700",
color: "#000000DE",
width: "100%",
},
subtitle: {
color:"#00000099",
fontWeight:400,
fontSize:"1rem",
textAlign:"center",
lineHeight:"150%",
letterSpacing:"0.009375rem",
width:"65%",
}
color: "#00000099",
fontWeight: 400,
fontSize: "1rem",
textAlign: "center",
lineHeight: "150%",
letterSpacing: "0.009375rem",
width: "65%",
},
}));
function Home ({ keywords, data, updateData }) {
function Home({ keywords, data, updateData }) {
const [isLoading, setIsLoading] = useState(true);
const [homeData, setHomeData] = useState([]);
const filterStr = keywords && keywords.toLocaleLowerCase();
const classes = useStyles();
useEffect(() => {
api.get(`${host()}${endpoints.imageList}`)
.then(response => {
api
.get(`${host()}${endpoints.imageList}`)
.then((response) => {
if (response.data && response.data.data) {
let imageList = response.data.data.RepoListWithNewestImage;
let imagesData = imageList.map((image) => {
@ -67,7 +80,7 @@ function Home ({ keywords, data, updateData }) {
licenses: image.NewestImage.Licenses,
size: image.NewestImage.Size,
vendor: image.NewestImage.Vendor,
lastUpdated: image.NewestImage.LastUpdated
lastUpdated: image.NewestImage.LastUpdated,
};
});
updateData(imagesData);
@ -76,38 +89,50 @@ function Home ({ keywords, data, updateData }) {
})
.catch((e) => {
console.error(e);
})
},[])
});
}, []);
useEffect(() => {
setIsLoading(false);
}, []);
useEffect(() => {
const filtered = data && data.filter((item) => {
const filtered =
data &&
data.filter((item) => {
return (
isEmpty(keywords) ||
(item.name && item.name.toLocaleLowerCase().indexOf(filterStr) >= 0 ) ||
(item.appID && item.appID.toLocaleLowerCase().indexOf(filterStr) >= 0) ||
(item.name &&
item.name.toLocaleLowerCase().indexOf(filterStr) >= 0) ||
(item.appID &&
item.appID.toLocaleLowerCase().indexOf(filterStr) >= 0) ||
(item.appId && item.appId.toLocaleLowerCase().indexOf(filterStr) >= 0)
)
);
});
setHomeData(filtered);
}, [keywords, data]);
const renderPreviewCards = () => {
return homeData && homeData.slice(0,4).map((item, index) => {
return (
<Grid item xs={3} key={index}><PreviewCard name={item.name} lastUpdated={item.lastUpdated}/></Grid>
)
});
homeData &&
homeData.slice(0, 4).map((item, index) => {
return (
<Grid item xs={3} key={index}>
<PreviewCard name={item.name} lastUpdated={item.lastUpdated} />
</Grid>
);
})
);
};
const renderBookmarks = () => {
return homeData && homeData.slice(0,2).map((item,index) => {
return (
<RepoCard name={item.name}
homeData &&
homeData.slice(0, 2).map((item, index) => {
return (
<RepoCard
name={item.name}
version={item.latestVersion}
description={item.description}
tags={item.tags}
@ -117,15 +142,20 @@ function Home ({ keywords, data, updateData }) {
key={index}
data={item}
lastUpdated={item.lastUpdated}
shown={true}/>
)
});
}
shown={true}
/>
);
})
);
};
const renderRecentlyUpdated = () => {
return homeData && homeData.slice(0,2).map((item,index) => {
return (
<RepoCard name={item.name}
homeData &&
homeData.slice(0, 2).map((item, index) => {
return (
<RepoCard
name={item.name}
version={item.latestVersion}
description={item.description}
tags={item.tags}
@ -135,25 +165,37 @@ function Home ({ keywords, data, updateData }) {
key={index}
data={item}
lastUpdated={item.lastUpdated}
shown={true}/>
)
});
}
shown={true}
/>
);
})
);
};
return (
<Stack spacing={4} alignItems="center" className={classes.gridWrapper}>
<Grid container item xs={12}>
<Stack direction="column" alignItems="center" spacing={4}>
<Typography variant="h3" className={classes.title}>Most popular repositories</Typography>
<Typography variant="body1" className={classes.subtitle} align="center">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Amet, dis pellentesque posuere nulla tortor ac eu arcu nunc. A potenti ridiculus vitae, ut venenatis in ut interdum eros.</Typography>
<Grid container item xs={12} sx={{mt:2, mb:1}} justifyContent="center">
<Stack sx={{display: "inline"}} direction="row" justifyContent="center" spacing={1}>
<Typography variant="h3" className={classes.title}>
Most popular
</Typography>
<Typography variant="h3" className={classes.titleRed}>
images
</Typography>
</Stack>
</Grid>
<Grid container spacing={1}>
<Grid container spacing={1} >
{renderPreviewCards()}
</Grid> <Grid >
</Grid>
<Typography variant="h4" align="left" className={classes.sectionTitle}>Bookmarks</Typography>
<Typography variant="h4" align="left" className={classes.sectionTitle}>
Bookmarks
</Typography>
{renderBookmarks()}
<Typography variant="h4" align="left" className={classes.sectionTitle}>Recently updated repositories</Typography>
<Stack></Stack>
<Typography variant="h4" align="left" className={classes.sectionTitle}>
Recently updated repositories
</Typography>
{renderRecentlyUpdated()}
</Stack>
);

View File

@ -1,8 +1,13 @@
import { Card, CardActionArea, CardContent, CardMedia, Grid, Stack, Typography } from '@mui/material';
import { Card, CardActionArea, CardContent, CardMedia, Grid, Stack, Typography, Box } from '@mui/material';
import { makeStyles } from '@mui/styles';
import React from 'react';
import { useNavigate } from 'react-router-dom';
import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined';
import BookmarkBorderOutlinedIcon from '@mui/icons-material/BookmarkBorderOutlined';
import PestControlOutlinedIcon from '@mui/icons-material/PestControlOutlined';
import PestControlIcon from '@mui/icons-material/PestControl';
import GppBadOutlinedIcon from '@mui/icons-material/GppBadOutlined';
import GppGoodOutlinedIcon from '@mui/icons-material/GppGoodOutlined';
import GppMaybeOutlinedIcon from '@mui/icons-material/GppMaybeOutlined';
// placeholder images
import repocube1 from '../assets/repocube-1.png';
@ -29,6 +34,7 @@ const useStyles = makeStyles(() => ({
background: "#FFFFFF",
boxShadow: "0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)",
borderRadius: "1.5rem",
borderColor: "#FFFFFF",
flex: "none",
alignSelf: "stretch",
flexGrow: 0,
@ -60,6 +66,11 @@ const useStyles = makeStyles(() => ({
}
}));
//function that returns a random element from an array
function getRandom (list) {
return list[Math.floor((Math.random()*list.length))];
}
function PreviewCard(props) {
const classes = useStyles();
const navigate = useNavigate();
@ -69,8 +80,25 @@ function PreviewCard(props) {
navigate(`/image/${name}`);
};
const verifiedCheck = () => {
return (<CheckCircleOutlineOutlinedIcon sx={{ color: "#388E3C!important", height:"2rem", width:"2rem" }} />);
const vulnerabilityCheck = () => {
const noneVulnerability = <PestControlOutlinedIcon sx={{ color: "#43A047!important", padding:"0.2rem", background: "#E8F5E9", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
const unknownVulnerability = <PestControlOutlinedIcon sx={{ color: "#52637A!important", padding:"0.2rem", background: "#ECEFF1", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
const lowVulnerability = <PestControlOutlinedIcon sx={{ color: "#FB8C00!important", padding:"0.2rem", background: "#FFF3E0", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
const mediumVulnerability = <PestControlIcon sx={{ color: "#FB8C00!important", padding:"0.2rem", background: "#FFF3E0", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
const highVulnerability = <PestControlOutlinedIcon sx={{ color: "#E53935!important", padding:"0.2rem", background: "#FEEBEE", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
const criticalVulnerability = <PestControlIcon sx={{ color: "#E53935!important", padding:"0.2rem", background: "#FEEBEE", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
const arrVulnerability = [noneVulnerability, unknownVulnerability, lowVulnerability, mediumVulnerability, highVulnerability, criticalVulnerability]
return(getRandom(arrVulnerability));
}
const signatureCheck = () => {
const unverifiedSignature = <GppBadOutlinedIcon sx={{ color: "#E53935!important", padding:"0.2rem", background: "#FEEBEE", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
const untrustedSignature = <GppMaybeOutlinedIcon sx={{ color: "#52637A!important", padding:"0.2rem", background: "#ECEFF1", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
const verifiedSignature = <GppGoodOutlinedIcon sx={{ color: "#43A047!important", padding:"0.2rem", background: "#E8F5E9", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
const arrSignature = [unverifiedSignature, untrustedSignature, verifiedSignature]
return(getRandom(arrSignature));
}
return (
@ -91,17 +119,17 @@ function PreviewCard(props) {
<Typography variant="h5" component="div" sx={{size:"1.5rem", lineHeight:"2rem", color:"#220052"}}>
{name}
</Typography>
{verifiedCheck()}
{vulnerabilityCheck()}
{signatureCheck()}
</Stack>
</Grid>
<Grid container item xs={12} mt={2}>
<Typography variant="body2" sx={{fontSize:"0.875rem", lineHeight:"143%", letterSpacing:"0.010625rem"}}>Official*PH</Typography>
</Grid>
<Grid container item xs={12}>
</Grid>
<Grid container item xs={12}>
<Typography variant="subtitle2" sx={{ color: "#7C4DFF" }}>Discover more</Typography>
<Grid item xs={12} mt={2}>
<Stack alignItems="flex-end" justifyContent="space-between" direction="row">
<Typography variant="body2" sx={{fontSize:"0.875rem", lineHeight:"143%", letterSpacing:"0.010625rem"}}>Official</Typography>
<BookmarkBorderOutlinedIcon/>
</Stack>
</Grid>
</Grid>
</CardContent>
</CardActionArea>

View File

@ -3,22 +3,35 @@ import React from "react";
import { useNavigate } from "react-router-dom";
// utility
import { DateTime } from 'luxon';
import { DateTime } from "luxon";
// components
import { Card, CardActionArea, CardMedia, CardContent, Typography, Stack, Chip, Grid } from '@mui/material';
import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined';
import BookmarkIcon from '@mui/icons-material/Bookmark';
import makeStyles from '@mui/styles/makeStyles';
import {
Card,
CardActionArea,
CardMedia,
CardContent,
Typography,
Stack,
Chip,
Grid,
} from "@mui/material";
import PestControlOutlinedIcon from "@mui/icons-material/PestControlOutlined";
import PestControlIcon from "@mui/icons-material/PestControl";
import GppBadOutlinedIcon from "@mui/icons-material/GppBadOutlined";
import GppGoodOutlinedIcon from "@mui/icons-material/GppGoodOutlined";
import GppMaybeOutlinedIcon from "@mui/icons-material/GppMaybeOutlined";
import BookmarkIcon from "@mui/icons-material/Bookmark";
import makeStyles from "@mui/styles/makeStyles";
// placeholder images
import repocube1 from '../assets/repocube-1.png';
import repocube2 from '../assets/repocube-2.png';
import repocube3 from '../assets/repocube-3.png';
import repocube4 from '../assets/repocube-4.png';
import repocube1 from "../assets/repocube-1.png";
import repocube2 from "../assets/repocube-2.png";
import repocube3 from "../assets/repocube-3.png";
import repocube4 from "../assets/repocube-4.png";
// temporary utility to get image
const randomIntFromInterval = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) + min)
return Math.floor(Math.random() * (max - min + 1) + min);
};
const randomImage = () => {
@ -33,67 +46,122 @@ const useStyles = makeStyles(() => ({
flexDirection: "row",
alignItems: "center",
background: "#FFFFFF",
boxShadow: "0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)",
borderColor: "#FFFFFF",
borderRadius: "1.5rem",
flex: "none",
alignSelf: "stretch",
flexGrow: 0,
order: 0,
width: "100%",
maxWidth: "72rem"
maxWidth: "72rem",
},
avatar: {
height: "1.4375rem",
width: "1.4375rem"
width: "1.4375rem",
},
cardBtn: {
height: "100%",
width: "100%"
width: "100%",
},
media: {
borderRadius: '3.125rem',
borderRadius: "3.125rem",
},
content: {
textAlign: "left",
color: "#606060",
maxHeight: "9.25rem"
maxHeight: "9.25rem",
},
contentRight: {
height: "100%"
height: "100%",
},
signedBadge: {
color: '#9ccc65',
height: '1.375rem',
width: '1.375rem',
color: "#9ccc65",
height: "1.375rem",
width: "1.375rem",
marginLeft: 10,
}
},
vendor: {
color: "#14191F",
fontSize: "1rem",
},
versionLast: {
color: "#52637A",
fontSize: "1rem",
},
}));
function RepoCard(props) {
const classes = useStyles();
const navigate = useNavigate();
const { name, vendor, description, lastUpdated, downloads, rating, version } = props;
const { name, vendor, description, lastUpdated, downloads, rating, version } =
props;
//function that returns a random element from an array
function getRandom(list) {
return list[Math.floor(Math.random() * list.length)];
}
const goToDetails = (repo) => {
navigate(`/image/${name}`);
}
};
const verifiedCheck = () => {
return (<CheckCircleOutlineOutlinedIcon sx={{ color: "#388E3C!important" }} />);
const vulnerabilityCheck = () => {
const noneVulnerability = <Chip label="None Vulnerability" sx={{backgroundColor: "#E8F5E9",color: "#388E3C",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#388E3C!important" }} />}/>;
const unknownVulnerability = <Chip label="Unknown Vulnerability" sx={{backgroundColor: "#ECEFF1",color: "#52637A",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#52637A!important" }} />}/>;
const lowVulnerability = <Chip label="Low Vulnerability" sx={{backgroundColor: "#FFF3E0",color: "#FB8C00",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#FB8C00!important" }} />}/>;
const mediumVulnerability = <Chip label="Medium Vulnerability" sx={{backgroundColor: "#FFF3E0",color: "#FB8C00",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlIcon sx={{ color: "#FB8C00!important" }} />}/>;
const highVulnerability = <Chip label="High Vulnerability" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#E53935!important" }} />}/>;
const criticalVulnerability = <Chip label="Critical Vulnerability" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlIcon sx={{ color: "#E53935!important" }} />}/>;
const arrVulnerability = [noneVulnerability, unknownVulnerability, lowVulnerability, mediumVulnerability, highVulnerability, criticalVulnerability]
return(getRandom(arrVulnerability));
};
const signatureCheck = () => {
const unverifiedSignature = <Chip label="Unverified Signature" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppBadOutlinedIcon sx={{ color: "#E53935!important" }} />}/>;
const untrustedSignature = <Chip label="Untrusted Signature" sx={{backgroundColor: "#ECEFF1",color: "#52637A",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppMaybeOutlinedIcon sx={{ color: "#52637A!important" }} />}/>;
const verifiedSignature = <Chip label="Verified Signature" sx={{backgroundColor: "#E8F5E9",color: "#388E3C",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppGoodOutlinedIcon sx={{ color: "#388E3C!important" }} />}/>;
const arrSignature = [unverifiedSignature, untrustedSignature, verifiedSignature]
return(getRandom(arrSignature));
}
const platformChips = () => {
// if platforms not received, mock data
const platforms = props.platforms || ["Windows", "PowerPC64LE", "IBM Z", "Linux"];
const platforms = props.platforms || [
"Windows",
"PowerPC64LE",
"IBM Z",
"Linux",
];
return platforms.map((platform, index) => (
<Chip key={index} label={platform} sx={{ backgroundColor: "#EDE7F6", color: "#311B92" }} />
<Chip
key={index}
label={platform}
sx={{
backgroundColor: "#E0E5EB",
color: "#52637A",
fontSize: "0.8125rem",
}}
/>
));
}
};
const getVendorLastPublish = () => {
const lastDate = lastUpdated ? DateTime.fromISO(lastUpdated) : DateTime.now().minus({ days: 1 });
return `${vendor || 'andrewc'} • published ${version}${lastDate.toRelative({ unit: 'days' })}`;
}
const getVendor = () => {
return `${vendor || "andrewc"}`;
};
const getVersion = () => {
const lastDate = lastUpdated
? DateTime.fromISO(lastUpdated)
: DateTime.now().minus({ days: 1 });
return `published ${version}`;
};
const getLast = () => {
const lastDate = lastUpdated
? DateTime.fromISO(lastUpdated)
: DateTime.now().minus({ days: 1 });
return `${lastDate.toRelative({ unit: "days" })}`;
};
return (
<Card variant="outlined" className={classes.card}>
@ -102,7 +170,8 @@ function RepoCard(props) {
<Grid container>
<Grid item xs={10}>
<Stack alignItems="center" direction="row" spacing={2}>
<CardMedia classes={{
<CardMedia
classes={{
root: classes.media,
img: classes.avatar,
}}
@ -113,25 +182,50 @@ function RepoCard(props) {
<Typography variant="h5" component="div">
{name}
</Typography>
<Chip label="Verified license" sx={{ backgroundColor: "#E8F5E9", color: "#388E3C" }} variant="filled" onDelete={() => { return }} deleteIcon={verifiedCheck()} />
{vulnerabilityCheck()}
{signatureCheck()}
{/* <Chip label="Verified licensee" sx={{ backgroundColor: "#E8F5E9", color: "#388E3C" }} variant="filled" onDelete={() => { return }} deleteIcon={vulnerabilityCheck()} /> */}
</Stack>
<Typography pt={1} sx={{ fontSize: 12 }} gutterBottom>
{description || 'The complete solution for node.js command-line programs'}
<Typography
className={classes.versionLast}
pt={1}
sx={{ fontSize: 12 }}
gutterBottom
>
{description ||
"The complete solution for node.js command-line programs"}
</Typography>
<Stack alignItems="center" direction="row" spacing={2} pt={1}>
{platformChips()}
</Stack>
<Typography variant="body2" pt={1}>
{getVendorLastPublish()}
<Stack alignItems="center" direction="row" spacing={1} pt={2}>
<Typography className={classes.vendor} variant="body2">
{getVendor()}
</Typography>
<Typography className={classes.versionLast} variant="body2">
{getVersion()}
</Typography>
<Typography className={classes.versionLast} variant="body2">
{getLast()}
</Typography>
</Grid>
<Grid item xs={2} >
<Stack alignItems="flex-end" justifyContent="space-between" direction="column" className={classes.contentRight}>
<Stack direction="column" alignItems="flex-end">
<Typography variant="body2">Downloads {downloads || '-'}</Typography>
<Typography variant="body2">Rating {rating || '-'}</Typography>
</Stack>
<BookmarkIcon />
</Grid>
<Grid item xs={2}>
<Stack
alignItems="flex-end"
justifyContent="space-between"
direction="column"
className={classes.contentRight}
>
<Stack direction="column" alignItems="flex-end">
<Typography variant="body2">
Downloads {downloads || "-"}
</Typography>
<Typography variant="body2">
Rating {rating || "-"}
</Typography>
</Stack>
<BookmarkIcon sx={{color:"#52637A"}}/>
</Stack>
</Grid>
</Grid>

View File

@ -11,7 +11,11 @@ import Tags from './Tags.jsx'
import {Box, Card, CardContent, CardMedia, Chip, FormControl, Grid, IconButton, InputAdornment, OutlinedInput, Stack, Tab, Typography} from '@mui/material';
import makeStyles from '@mui/styles/makeStyles';
import { host } from '../host';
import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined';
import PestControlOutlinedIcon from "@mui/icons-material/PestControlOutlined";
import PestControlIcon from "@mui/icons-material/PestControl";
import GppBadOutlinedIcon from "@mui/icons-material/GppBadOutlined";
import GppGoodOutlinedIcon from "@mui/icons-material/GppGoodOutlined";
import GppMaybeOutlinedIcon from "@mui/icons-material/GppMaybeOutlined";
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import BookmarkIcon from '@mui/icons-material/Bookmark';
@ -22,6 +26,7 @@ import repocube3 from '../assets/repocube-3.png';
import repocube4 from '../assets/repocube-4.png';
import { TabContext, TabList, TabPanel } from '@mui/lab';
import RepoDetailsMetadata from './RepoDetailsMetadata';
import { padding } from '@mui/system';
// @ts-ignore
const useStyles = makeStyles((theme) => ({
@ -36,9 +41,9 @@ const useStyles = makeStyles((theme) => ({
backgroundColor: "#FFFFFF",
},
repoName: {
fontWeight:"400",
fontSize:"3rem",
color:"#220052"
fontWeight:"700",
fontSize:"2.5rem",
color:"#0F2139"
},
avatar: {
height:"3rem",
@ -52,26 +57,24 @@ const useStyles = makeStyles((theme) => ({
borderRadius: '3.125em',
},
tabs: {
marginTop: "5%",
border: 1,
borderColor: 'divider',
marginTop: "3rem",
padding:"0.5rem",
boxShadow: "0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)",
borderRadius:"2rem",
height: "100%"
},
tabContent:{
height:"100%"
},
selectedTab: {
background:"#A53692",
background:"#D83C0E",
borderRadius:"1.5rem"
},
tabPanel: {
height:"100%"
height:"100%",
paddingLeft: "0rem!important"
},
metadata: {
padding:"1.5rem"
marginTop: "8rem",
paddingLeft:"1.5rem",
},
card: {
marginBottom: 2,
@ -79,13 +82,14 @@ const useStyles = makeStyles((theme) => ({
flexDirection:"row",
alignItems:"start",
background:"#FFFFFF",
boxShadow:"0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)",
borderRadius:"1.5rem",
border: "1px solid #E0E5EB",
borderRadius:"2rem",
flex:"none",
alignSelf:"stretch",
flexGrow:0,
order:0,
width:"100%"
width:"100%",
boxShadow: "none!important"
},
platformText:{
backgroundColor:"#EDE7F6",
@ -94,6 +98,18 @@ const useStyles = makeStyles((theme) => ({
fontSize:'0.8125rem',
lineHeight:'1.125rem',
letterSpacing:'0.01rem'
},
inputForm:{
'& fieldset':{
border: "2px solid #52637A",
},
},
cardRoot:{
boxShadow: "none!important",
},
header:{
paddingLeft:"2rem"
}
}));
@ -142,9 +158,30 @@ function RepoDetails (props) {
setRepoDetailData({});
});
}, [name])
//function that returns a random element from an array
function getRandom(list) {
return list[Math.floor(Math.random() * list.length)];
}
const verifiedCheck = () => {
return (<CheckCircleOutlineOutlinedIcon sx={{color:"#388E3C!important"}}/>);
const vulnerabilityCheck = () => {
const noneVulnerability = <Chip label="None Vulnerability" sx={{backgroundColor: "#E8F5E9",color: "#388E3C",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#388E3C!important" }} />}/>;
const unknownVulnerability = <Chip label="Unknown Vulnerability" sx={{backgroundColor: "#ECEFF1",color: "#52637A",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#52637A!important" }} />}/>;
const lowVulnerability = <Chip label="Low Vulnerability" sx={{backgroundColor: "#FFF3E0",color: "#FB8C00",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#FB8C00!important" }} />}/>;
const mediumVulnerability = <Chip label="Medium Vulnerability" sx={{backgroundColor: "#FFF3E0",color: "#FB8C00",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlIcon sx={{ color: "#FB8C00!important" }} />}/>;
const highVulnerability = <Chip label="High Vulnerability" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#E53935!important" }} />}/>;
const criticalVulnerability = <Chip label="Critical Vulnerability" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlIcon sx={{ color: "#E53935!important" }} />}/>;
const arrVulnerability = [noneVulnerability, unknownVulnerability, lowVulnerability, mediumVulnerability, highVulnerability, criticalVulnerability]
return(getRandom(arrVulnerability));
};
const signatureCheck = () => {
const unverifiedSignature = <Chip label="Unverified Signature" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppBadOutlinedIcon sx={{ color: "#E53935!important" }} />}/>;
const untrustedSignature = <Chip label="Untrusted Signature" sx={{backgroundColor: "#ECEFF1",color: "#52637A",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppMaybeOutlinedIcon sx={{ color: "#52637A!important" }} />}/>;
const verifiedSignature = <Chip label="Verified Signature" sx={{backgroundColor: "#E8F5E9",color: "#388E3C",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppGoodOutlinedIcon sx={{ color: "#388E3C!important" }} />}/>;
const arrSignature = [unverifiedSignature, untrustedSignature, verifiedSignature]
return(getRandom(arrSignature));
}
const platformChips = () => {
@ -152,7 +189,11 @@ function RepoDetails (props) {
// @ts-ignore
const platforms = repoDetailData.platforms || ["Windows","PowerPC64LE","IBM Z","Linux"];
return platforms.map((platform, index) => (
<Chip key={index} label={platform.Os} className={classes.platformText}/>
<Chip key={index} label={platform.Os} sx={{
backgroundColor: "#E0E5EB",
color: "#52637A",
fontSize: "0.8125rem",
}}/>
));
}
@ -166,7 +207,7 @@ function RepoDetails (props) {
<Card className={classes.card} data-testid='overview-container'>
<CardContent>
<Typography variant="h4" align="left">{overviewTitle || 'Quickstart'}</Typography>
<Typography variant="body1" sx={{color:"rgba(0, 0, 0, 0.6)", fontSize:"1rem",lineHeight:"150%", marginTop:"5%"}}>{description || mockData.loremIpsum}</Typography>
<Typography variant="body1" sx={{color:"rgba(0, 0, 0, 0.6)", fontSize:"1rem",lineHeight:"150%", marginTop:"5%", alignSelf:"stretch"}}>{description || mockData.loremIpsum}</Typography>
</CardContent>
</Card>
);
@ -199,10 +240,10 @@ function RepoDetails (props) {
return (
<div className={classes.pageWrapper}>
<Card>
<Card className={classes.cardRoot}>
<CardContent>
<Grid container>
<Grid item xs={7}>
<Grid container className={classes.header}>
<Grid item xs={8}>
<Stack alignItems="center" direction="row" spacing={2}>
<CardMedia classes={{
root: classes.media,
@ -215,23 +256,26 @@ function RepoDetails (props) {
<Typography variant="h3" className={classes.repoName}>
{name}
</Typography>
<Chip label="Verified license" sx={{backgroundColor:"#E8F5E9", color:"#388E3C"}} variant="filled" onDelete={() => {return}} deleteIcon={verifiedCheck()}/>
<BookmarkIcon/>
{vulnerabilityCheck()}
{signatureCheck()}
<BookmarkIcon sx={{color:"#52637A"}}/>
</Stack>
<Typography pt={1} sx={{ fontSize: 16,lineHeight:"1.5rem", color:"rgba(0, 0, 0, 0.6)" }} gutterBottom align="left">
<Typography pt={1} sx={{ fontSize: 16,lineHeight:"1.5rem", color:"rgba(0, 0, 0, 0.6)", paddingLeft:"4rem"}} gutterBottom align="left">
{description || 'The complete solution for node.js command-line programs'}
</Typography>
<Stack alignItems="center" direction="row" spacing={2} pt={1}>
<Stack alignItems="center" sx={{ paddingLeft:"4rem"}} direction="row" spacing={2} pt={1}>
{platformChips()}
</Stack>
</Grid>
<Grid item xs={5} pt={2}>
<Typography variant="body1" sx={{color:"rgba(0, 0, 0, 0.6)"}}>Copy and pull to pull this image</Typography>
<FormControl sx={{ m: 1, width: '25ch' }} variant="outlined">
<Grid item xs={4} >
<Typography variant="body1" sx={{color:"#52637A", fontSize: "1rem"}}>Copy and pull to pull this image</Typography>
<FormControl sx={{ m: 1, paddingLeft:"1.5rem"}} variant="outlined">
<OutlinedInput
value={`Pull ${name}`}
className={classes.inputForm}
sx={{ m: 1, width: '20.625rem', borderRadius: "8px", color: "#14191F"}}
endAdornment={
<InputAdornment position="end">
<InputAdornment position="end" >
<IconButton aria-label='copy' edge="end" onClick={() => navigator.clipboard.writeText(`Pull ${name}`)} data-testid='pullcopy-btn'>
<ContentCopyIcon/>
</IconButton>
@ -245,12 +289,14 @@ function RepoDetails (props) {
</FormControl>
</Grid>
</Grid>
<Grid container>
<Grid item xs={8} className={classes.tabs}>
<TabContext value={selectedTab}>
<Box className={classes.tabs}>
<Box >
<TabList
onChange={handleTabChange}
TabIndicatorProps={{ className: classes.selectedTab }}
sx={{ "& button.Mui-selected": {color:"#A53692"}}}
sx={{ "& button.Mui-selected": {color:"#14191F", fontWeight:"600"}}}
>
<Tab value="Overview" label="Overview" className={classes.tabContent}/>
<Tab value="Tags" label="Tags" className={classes.tabContent}/>
@ -262,7 +308,7 @@ function RepoDetails (props) {
<Tab value="8" label="Tab 8" className={classes.tabContent}/> */}
</TabList>
<Grid container>
<Grid item xs={8}>
<Grid item xs={12}>
<TabPanel value="Overview" className={classes.tabPanel}>
{renderOverview()}
</TabPanel>
@ -279,6 +325,10 @@ function RepoDetails (props) {
{renderVulnerabilities()}
</TabPanel> */}
</Grid>
</Grid>
</Box>
</TabContext>
</Grid>
<Grid item xs={4} className={classes.metadata}>
<RepoDetailsMetadata
// @ts-ignore
@ -290,8 +340,6 @@ function RepoDetails (props) {
/>
</Grid>
</Grid>
</Box>
</TabContext>
</CardContent>
</Card>
</div>

View File

@ -1,65 +1,110 @@
// react global
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { host } from '../host';
import { host } from "../host";
// utility
import { api, endpoints } from '../api';
import { api, endpoints } from "../api";
// components
import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline';
import TextField from '@mui/material/TextField';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Alert from '@mui/material/Alert';
import CircularProgress from '@mui/material/CircularProgress';
import TermsOfService from './TermsOfService';
import Button from "@mui/material/Button";
import CssBaseline from "@mui/material/CssBaseline";
import TextField from "@mui/material/TextField";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Alert from "@mui/material/Alert";
import CircularProgress from "@mui/material/CircularProgress";
import TermsOfService from "./TermsOfService";
import google from '../assets/Google.png';
import git from '../assets/Git.png';
// styling
import { makeStyles } from '@mui/styles';
import { Card, CardContent } from '@mui/material';
import { makeStyles } from "@mui/styles";
import { Card, CardContent } from "@mui/material";
const useStyles = makeStyles((theme) => ({
cardContainer: {
display: "flex",
alignItems: "center",
justifyContent: "center"
justifyContent: "center",
margin: "0 auto",
padding: "10px",
position: "relative",
},
loginCard: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
marginTop: "20%",
width: "60%",
height: "60%",
background: '#FFFFFF',
gap: '0.625em',
boxShadow: '0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)',
borderRadius: '1.5rem'
background: "#FFFFFF",
gap: "0.625em",
boxShadow: "0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)",
borderRadius: "1.5rem",
},
loginCardContent: {
alignItems: 'center',
justifyContent: 'center',
display: 'flex',
flexDirection: 'column',
border: '0.1875rem black',
maxWidth: '73%',
height: '90%'
alignItems: "center",
justifyContent: "center",
display: "flex",
flexDirection: "column",
border: "0.1875rem black",
maxWidth: "73%",
height: "90%",
},
text: {
color: "#383838",
width: "100%"
color: "#14191F",
width: "100%",
fontSize: "1.5rem"
},
subtext: {
color: "rgba(0, 0, 0, 0.6)",
width: "100%"
color: "#52637A",
width: "100%",
fontSize: "1rem"
},
textField: {
borderRadius: "4px",
},
button: {
textTransform: "none",
color: "##FFFFFF",
fontSize: "1.4375rem",
fontWeight: "500",
height: "50px",
borderRadius: "4px",
letterSpacing:"0.01rem",
},
gitLogo: {
height: "24px",
borderRadius: "4px",
paddingLeft: "1rem",
},
line: {
width: "100%",
textAlign: "center",
borderBottom: "1px solid #C2CBD6",
lineHeight: "0.1rem",
margin: "10px 0 20px",
},
lineSpan:{
background: "#ffffff",
color: "#C2CBD6",
padding: "0 10px",
fontSize: "1rem",
fontWeight: "400",
paddingLeft: "1rem",
paddingRight: "1rem"
}
}));
export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, setIsLoggedIn }) {
export default function SignIn({
isAuthEnabled,
setIsAuthEnabled,
isLoggedIn,
setIsLoggedIn,
}) {
const [usernameError, setUsernameError] = useState(null);
const [passwordError, setPasswordError] = useState(null);
const [username, setUsername] = useState(null);
@ -73,17 +118,18 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se
if (isAuthEnabled && isLoggedIn) {
navigate("/home");
} else {
api.get(`${host()}/v2/`)
.then(response => {
api
.get(`${host()}/v2/`)
.then((response) => {
if (response.status === 200) {
setIsAuthEnabled(false);
setIsLoggedIn(true);
navigate("/home");
}
})
.catch(e => {
.catch((e) => {
setIsAuthEnabled(true);
})
});
}
}, []);
@ -92,19 +138,20 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se
setRequestProcessing(true);
let cfg = {};
if (isAuthEnabled) {
const token = btoa(username + ':' + password);
const token = btoa(username + ":" + password);
cfg = {
headers: {
'Authorization': `Basic ${token}`,
}
Authorization: `Basic ${token}`,
},
};
}
api.get(`${host()}${endpoints.imageList}`, cfg)
.then(response => {
api
.get(`${host()}${endpoints.imageList}`, cfg)
.then((response) => {
if (response.data && response.data.data) {
if (isAuthEnabled) {
const token = btoa(username + ':' + password);
localStorage.setItem('token', token);
const token = btoa(username + ":" + password);
localStorage.setItem("token", token);
setRequestProcessing(false);
setRequestError(false);
}
@ -112,32 +159,32 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se
navigate("/home");
}
})
.catch(e => {
.catch((e) => {
setRequestError(true);
setRequestProcessing(false);
});
}
};
const handleChange = (event, type) => {
event.preventDefault();
setRequestError(false);
const val = event.target.value;
const isEmpty = val === '';
const isEmpty = val === "";
switch (type) {
case 'username':
case "username":
setUsername(val);
if (isEmpty) {
setUsernameError('Please enter a username');
setUsernameError("Please enter a username");
} else {
setUsernameError(null);
}
break;
case 'password':
case "password":
setPassword(val);
if (isEmpty) {
setPasswordError('Please enter a password');
setPasswordError("Please enter a password");
} else {
setPasswordError(null);
}
@ -145,20 +192,78 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se
default:
break;
}
}
};
return (
<Box className={classes.cardContainer} data-testid="signin-container">
<Card className={classes.loginCard} >
<Card className={classes.loginCard}>
<CardContent className={classes.loginCardContent}>
<CssBaseline />
<Typography align="left" className={classes.text} component="h1" variant="h4">
<Typography
align="left"
className={classes.text}
component="h1"
variant="h4"
>
Sign in
</Typography>
<Typography align="left" className={classes.subtext} variant="body1" gutterBottom>
<Typography
align="left"
className={classes.subtext}
variant="body1"
gutterBottom
>
Welcome back! Please enter your details.
</Typography><Box component="form" onSubmit={null} noValidate autoComplete='off' sx={{ mt: 1 }}>
</Typography>
<Box
component="form"
onSubmit={null}
noValidate
autoComplete="off"
sx={{ mt: 1 }}
>
<div>
<Button
fullWidth
variant="contained"
className={classes.button}
sx={{
mt: 3,
mb: 1,
background: "#161614",
"&:hover": {
backgroundColor: '#1565C0',
color: '#FFFFFF'
}
}}
>
{" "}
Continue with GitHub
<img src={git} alt="git logo" className={classes.gitLogo}></img>
</Button>
<Button
fullWidth
variant="contained"
className={classes.button}
sx={{
mt: 1,
mb: 1,
background: "transparent",
color: "#52637A",
"&:hover": {
backgroundColor: '#1565C0',
color: '#FFFFFF'
}
}}
>
{" "}
Continue with Google
<img src={google} alt="google logo" className={classes.gitLogo}></img>
</Button>
</div>
<br></br>
<h2 className={classes.line}><span className={classes.lineSpan}>or</span></h2>
<TextField
margin="normal"
required
@ -166,9 +271,11 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se
id="username"
label="Username"
name="username"
onInput={(e) => handleChange(e, 'username')}
className={classes.textField}
onInput={(e) => handleChange(e, "username")}
error={usernameError != null}
helperText={usernameError} />
helperText={usernameError}
/>
<TextField
margin="normal"
required
@ -177,18 +284,54 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se
label="Enter password"
type="password"
id="password"
onInput={(e) => handleChange(e, 'password')}
className={classes.textField}
onInput={(e) => handleChange(e, "password")}
error={passwordError != null}
helperText={passwordError} />
{requestProcessing && <CircularProgress style={{ marginTop: 20 }} color="secondary" />}
{requestError && <Alert style={{ marginTop: 20 }} severity="error">Authentication Failed. Please try again.</Alert>}
helperText={passwordError}
/>
{requestProcessing && (
<CircularProgress style={{ marginTop: 20 }} color="secondary" />
)}
{requestError && (
<Alert style={{ marginTop: 20 }} severity="error">
Authentication Failed. Please try again.
</Alert>
)}
<div>
<Button
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2, background: "#7C4DFF", border: 'white' }}
className={classes.button}
sx={{
mt: 3,
mb: 1,
background: "#1479FF",
"&:hover": {
backgroundColor: '#1565C0',
}
}}
onClick={handleClick}
> Continue
>
{" "}
Continue
</Button>
<Button
fullWidth
variant="contained"
className={classes.button}
sx={{
mt: 1,
mb: 1,
background: "transparent",
color: "#52637A",
"&:hover": {
backgroundColor: '#EFEFEF',
color: '#52637A'
}
}}
>
{" "}
Continue as guest
</Button>
</div>
</Box>

View File

@ -1,9 +1,9 @@
import {Stack, Typography } from '@mui/material';
import {makeStyles} from '@mui/styles';
import React from 'react';
import logoWhite from '../assets/Zot1.png';
import loginDrawing from '../assets/login-drawing.svg';
import backgroundImage from '../assets/presentation-background.png';
import logoWhite from '../assets/Zot-white.svg';
import loginDrawing from '../assets/codeReviewSignIn.png';
import backgroundImage from '../assets/backgroundSignIn.png';
const useStyles = makeStyles(() => ({
container: {
@ -13,8 +13,8 @@ const useStyles = makeStyles(() => ({
alignItems:"center",
},
logo: {
maxHeight:120,
maxWidth: 120,
maxHeight:96,
maxWidth: 320,
marginTop:"17%"
},
loginDrawing: {
@ -26,12 +26,14 @@ const useStyles = makeStyles(() => ({
color: "#FFFFFF",
fontWeight: 700,
maxWidth:"45%",
marginTop:"4%"
marginTop:"4%",
fontSize: "2.5rem"
},
captionText: {
color: "rgba(255, 255, 255, 0.7)",
maxWidth:"48%",
marginTop:"2%"
marginTop:"2%",
fontSize: "1.1875rem"
}
}));

View File

@ -6,10 +6,18 @@ import { Stack, Typography } from '@mui/material';
const useStyles = makeStyles((theme) => ({
subtext: {
color: "rgba(0, 0, 0, 0.6)",
margin: 0,
fontSize:"0.75rem",
lineHeight:"166%",
color: "#52637A",
fontSize: "0.8125rem",
fontWeight: "400",
lineHeight:"154%",
letterSpacing:"0.025rem",
marginBottom: "0"
},
text: {
color: "#0F2139",
fontSize:"0.8125rem",
lineHeight:"154%",
fontWeight: "600",
letterSpacing:"0.025rem"
}
}));
@ -19,9 +27,9 @@ export default function TermsOfService(props) {
return (
<Stack spacing={0}>
<Typography variant="caption" className={classes.subtext} align="justify" {...props} pb={6}>
By creating an account, you agree to the Terms of Service. For more information about our privacy practices, see the zot's Privacy Policy.
By creating an account, you agree to the Terms of Service. For more information about our privacy practices, see the ZOT's Privacy Policy.
</Typography>
<Typography variant="caption" className={classes.subtext} align="center" {...props}>
<Typography variant="caption" className={classes.text} align="center" {...props}>
Privacy Policy | Terms of Service
</Typography>
</Stack>

View File

@ -7,7 +7,7 @@ body {
-moz-osx-font-smoothing: grayscale;
min-height: 100vh;
/* background-image: url(./assets/background.png); */
background-color: #F5F5F5 !important;
background-color: #F6F7F9 !important;
}
code {

View File

@ -11,7 +11,7 @@ import SigninPresentation from 'components/SignInPresentation';
const useStyles = makeStyles((theme) => ({
container: {
minHeight: "100vh",
backgroundColor: "#F5F5F5",
backgroundColor: "#F6F7F9",
},
}));