Skip to content

Commit

Permalink
Add code insights page & components (#122)
Browse files Browse the repository at this point in the history
* Add code insights page and related components

* Fix styles on code insights charts components

* Set height on tab carousel and clean up some styles
  • Loading branch information
katjuell authored Apr 28, 2022
1 parent fbc91ca commit c5da67e
Show file tree
Hide file tree
Showing 43 changed files with 3,375 additions and 78 deletions.
13 changes: 13 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"lint": "yarn eslint && yarn typecheck",
"typecheck": "tsc -p .",
"eslint": "eslint '**/*.{ts,tsx}'",
"eslint:fix": "yarn eslint --fix",
"ci": "yarn install --immutable --immutable-cache --check-cache",
"prettier": "prettier '**/{*.{js?(on),ts?(x),md,scss},.*.js?(on)}' --write --list-different",
"prettier:check": "yarn -s prettier --write=false"
Expand Down Expand Up @@ -39,6 +40,12 @@
}
},
"dependencies": {
"@visx/grid": "^2.6.0",
"@visx/group": "^2.1.0",
"@visx/responsive": "^2.8.0",
"@visx/scale": "^2.2.2",
"@visx/text": "^2.3.0",
"@visx/xychart": "^2.9.0",
"gray-matter": "^4.0.3",
"lodash": "^4.17.21",
"next": "^12.1.0",
Expand All @@ -48,11 +55,17 @@
"rehype-autolink-headings": "^6.1.1",
"rehype-slug": "^5.0.1",
"remark-gfm": "^3.0.1",
"ts-loader": "^9.2.8",
"d3-format": "^3.1.0",
"d3-time-format": "^4.1.0",
"rxjs": "^7.5.5",
"ts-node": "^10.7.0"
},
"devDependencies": {
"@sourcegraph/eslint-config": "^0.27.0",
"@sourcegraph/prettierrc": "^3.0.3",
"@types/d3-format": "^3.0.1",
"@types/d3-time-format": "^4.0.0",
"@types/lodash": "^4.14.180",
"@types/node": "^17.0.23",
"@types/react": "^17.0.43",
Expand Down
46 changes: 0 additions & 46 deletions src/components/Blockquote.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,49 +118,3 @@ export const BlockquoteWithBorder: FunctionComponent<{
)}
</>
)

export const Blockquote: FunctionComponent<{
quote: string
headline?: string
author?: string | ReactFragment
logoHref?: string
logoImage?: string
logoAlt?: string
linkText?: string
link?: string
bold?: boolean
}> = ({ quote, headline, author, logoHref, logoImage, linkText, link, logoAlt, bold }) => (
<>
{headline && <h1 className="font-weight-bold">{headline}</h1>}
<blockquote className="p-3 rounded rounded-lg d-flex flex-column bg-transparent">
<h3 className={bold ? 'font-weight-bold' : 'font-weight-bold'}>&ldquo;{quote}&rdquo;</h3>
{author && <figcaption className="pt-3 text-muted text-center">&mdash; {author}</figcaption>}
</blockquote>
{logoImage && logoAlt && (
<div className="d-flex justify-content-center">
{logoHref ? (
<a href={logoHref} className="btn">
<img src={logoImage} width="110px" alt={logoAlt} />
</a>
) : (
<img src={logoImage} width="110px" alt={logoAlt} />
)}
</div>
)}
{linkText && link && link.includes('http') && (
<a href={link} target="_blank" rel="nofollow noopener noreferrer">
{linkText}
<ArrowRightIcon className="icon-inline ml-1" />
</a>
)}
{linkText && link && !link.includes('http') && (
<Link href={link} passHref={true}>
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<a className="d-flex justify-content-center mt-3">
<p className="font-weight-bold">{linkText}</p>
<ArrowRightIcon className="icon-inline ml-1" />
</a>
</Link>
)}
</>
)
8 changes: 4 additions & 4 deletions src/components/Carousels/CustomCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const CustomCarousel: FunctionComponent<CarouselProps> = props => {
? classNames(
carouselMainStyles,
currentCarousel.currentItem?.backgroundClass,
'justify-content-between h-xl-450 h-lg-350 h-md-300 h-sm-300 h-300'
'justify-content-between h-xl-450 h-lg-250 h-md-250 h-sm-auto h-auto'
)
: autoAdvance
? classNames(
Expand Down Expand Up @@ -125,9 +125,9 @@ export const CustomCarousel: FunctionComponent<CarouselProps> = props => {
<div
className={
autoAdvance && props.smallPanel
? classNames(carouselRightPanelStyles, 'h-xl-500 h-lg-300 h-md-300 h-sm-300 h-300')
? classNames(carouselRightPanelStyles, 'h-xl-500 h-lg-300 h-md-300 h-sm-250 h-250')
: autoAdvance
? classNames(carouselRightPanelStyles, 'h-xl-500 h-lg-500 h-md-500 h-sm-450 h-450')
? classNames(carouselRightPanelStyles, 'h-xl-500 h-lg-500 h-md-500 h-sm-500 h-500')
: classNames(carouselRightPanelStyles)
}
>
Expand All @@ -146,7 +146,7 @@ export const CustomCarousel: FunctionComponent<CarouselProps> = props => {
))}
</div>

<div className="carousel-nav-mobile mx-auto">
<div className="carousel-nav-mobile mx-auto my-4">
<ArrowLeftIcon
className="mr-4"
onClick={() => carouselHook.moveCarousel('decrement')}
Expand Down
70 changes: 70 additions & 0 deletions src/components/CodeInsights/CodeInsightsExamples.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
.card {
--border-radius: 3px;
--color-bg-1: #ffffff;
--border-color-2: #dbe2f0;
--primary: #1c7ed6;
--body-bg: #fcfcff;
--border-color: #e2e4e8;
--body-color: #343a4d;
--text-muted: #5e6e8c;
--box-shadow: 0 0.25rem 0.5rem #{rgba(#343a4d, 0.07)};

flex: 1;
flex-basis: 25rem;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
}

/* Need to override autogenerated styles.
Also see https://github.com/sourcegraph/about/blob/40fe7625efa20c29b1563ae2a320f07b5afc27dd/website/src/components/code-insights/components/line-chart/LineChartContent.module.scss#L56
*/

.searchChart {
height: 200px !important;
}

.chart {
min-height: 13rem;
flex-grow: 1;
width: 100%;
position: relative;
flex-basis: 13rem;
}

.chartContent {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}

.actionLink {
margin-top: -0.25rem;
flex-shrink: 0;
}

.legend {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin: 1rem 0 0 0;

&--horizontal {
flex-direction: column;
}
}

.legendMigrationItem {
min-width: 7.5rem;
font-size: 12px;
}

.captureGroup {
display: flex;
height: 100%;
}

.keyword {
color: var(--primary);
}
97 changes: 97 additions & 0 deletions src/components/CodeInsights/CodeInsightsExamples.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react'

import { ParentSize } from '@visx/responsive'
import classNames from 'classnames'

import { CodeInsightsQueryBlock } from './components/CodeInsightsQueryBlock'
import { LegendBlock, LegendItem } from './components/legend/CodeInsightLegend'
import { getLineStroke } from './components/line-chart/constants'
import { LineChart } from './components/line-chart/LineChart'
import { LineChartSeries } from './components/line-chart/types'
import { View } from './components/view/View'
import { CaptureGroupInsightData, CodeInsightExampleType, SearchInsightData } from './types'

import styles from './CodeInsightsExamples.module.scss'

export type CodeInsightExampleProps = CodeInsightSearchExampleProps | CodeInsightCaptureExampleProps

export interface CodeInsightSearchExampleProps {
type: CodeInsightExampleType.Search
data: SearchInsightData
className?: string
}

export interface CodeInsightCaptureExampleProps {
type: CodeInsightExampleType.Capture
data: CaptureGroupInsightData
className?: string
}

export const CodeInsightExample: React.FunctionComponent<CodeInsightExampleProps> = props => {
const { type } = props

if (type === CodeInsightExampleType.Search) {
return <CodeInsightSearchExample {...(props as CodeInsightSearchExampleProps)} />
}

return <CodeInsightCaptureExample {...(props as CodeInsightCaptureExampleProps)} />
}

const CodeInsightSearchExample: React.FunctionComponent<CodeInsightSearchExampleProps> = props => {
const { className, data } = props

return (
<View
title={data.title}
subtitle={<CodeInsightsQueryBlock className="mt-1">{data.repositories}</CodeInsightsQueryBlock>}
className={classNames(className, styles.card)}
>
<div className={styles.chart}>
<ParentSize className={styles.searchChart}>
{({ width, height }) => <LineChart {...data} width={width} height={height} />}
</ParentSize>
</div>

<LegendBlock className={styles.legend}>
{data.series.map(line => (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
<LegendItem key={line.dataKey.toString()} color={getLineStroke<any>(line)}>
<span className={classNames(styles.legendMigrationItem, 'flex-shrink-0 mr-2')}>
{line.name}
</span>
<CodeInsightsQueryBlock>{line.query}</CodeInsightsQueryBlock>
</LegendItem>
))}
</LegendBlock>
</View>
)
}

const CodeInsightCaptureExample: React.FunctionComponent<CodeInsightCaptureExampleProps> = props => {
const { className, data } = props

return (
<View
title={data.title}
subtitle={<CodeInsightsQueryBlock className="mt-1">All repositories</CodeInsightsQueryBlock>}
className={classNames(className, styles.card)}
>
<div className={styles.captureGroup}>
<div className={styles.chart}>
<ParentSize className={styles.chartContent}>
{({ width, height }) => <LineChart {...data} width={width} height={height} />}
</ParentSize>
</div>

<LegendBlock className={classNames(styles.legend, 'horizontal')}>
{data.series.map(line => (
<LegendItem key={line.dataKey.toString()} color={getLineStroke<LineChartSeries<string>>(line)}>
{line.name}
</LegendItem>
))}
</LegendBlock>
</div>
<CodeInsightsQueryBlock className="mt-2">{data.query}</CodeInsightsQueryBlock>
</View>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.query {
display: inline-block;
width: 100%;
margin: 0;
padding: 0.25rem 0.5rem;
font-size: 11px;
border-radius: 3px;
background-color: #f9fafb;
font-family: sfmono-regular, consolas, menlo, dejavu sans mono, monospace;
word-break: break-word;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react'

import classNames from 'classnames'

import styles from './CodeInsightsQueryBlock.module.scss'

export const CodeInsightsQueryBlock: React.FunctionComponent<React.HTMLAttributes<HTMLSpanElement>> = props => (
<span {...props} className={classNames(props.className, styles.query)} />
)
22 changes: 22 additions & 0 deletions src/components/CodeInsights/components/card/Card.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.card {
--card-bg: var(--color-bg-1);
--card-border-color: var(--border-color-2);
--card-border-radius: var(--border-radius);

// Added inset box shadow to prevent interactive card jump on hover and focus
--hover-box-shadow: 0 0 0 1px var(--primary) inset;
--card-spacer-y: 0.5rem;
--card-spacer-x: 0.5rem;

position: relative;
display: flex;
flex-direction: column;
min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106
word-wrap: break-word;
background-color: var(--card-bg);
background-clip: border-box;
border-width: 1px;
border-style: solid;
border-color: var(--card-border-color);
border-radius: var(--card-border-radius);
}
16 changes: 16 additions & 0 deletions src/components/CodeInsights/components/card/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react'

import classNames from 'classnames'

import styles from './Card.module.scss'

export interface CardProps extends React.HTMLAttributes<HTMLElement> {}

/**
* Card Element
*/
export const Card: React.FunctionComponent<CardProps> = ({ children, className, ...attributes }) => (
<div className={classNames(styles.card, className)} {...attributes}>
{children}
</div>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.legendList {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;

// Reset ul styles (bullets, paddings, margins)
list-style: none;
margin: 0;
padding: 0;
line-height: 1.2;
}

.legendItem {
display: flex;
align-items: baseline;
font-size: 12px;

@media only screen and (max-width: 768px) {
max-width: 100%;
flex-wrap: wrap;
}
}

.legendMark {
align-self: baseline;
width: 0.5rem;
height: 0.5rem;
flex-shrink: 0;
margin-right: 0.25rem;
border-radius: 50%;
}
Loading

0 comments on commit c5da67e

Please sign in to comment.