Update/fix some web stuff. (#1429)
* Update/fix some web stuff. Also added lefthook with some linting config. * Add note about lefthook. * Enable sort imports eslint rule. * This statement is untrue * Remove cypress video, add to gitignore * Add web CI action * Set the right dir here * Try this
This commit is contained in:
parent
1296ab8517
commit
bd5b7c87fa
|
@ -0,0 +1,27 @@
|
|||
name: Web CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js 18
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: npm
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
- run: npm ci
|
||||
working-directory: web
|
||||
- run: npm run lint
|
||||
working-directory: web
|
||||
- run: npm run build --if-present
|
||||
working-directory: web
|
||||
- run: npm run e2e:headless
|
||||
working-directory: web
|
|
@ -4,4 +4,4 @@ module.exports = {
|
|||
singleQuote: true,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
};
|
||||
}
|
|
@ -22,7 +22,16 @@ _Patches submitted in issues, email, or elsewhere may be ignored._
|
|||
|
||||
## Coding Style
|
||||
|
||||
Code should be formatted using `clang-format`. By configuring Conky with `cmake -DCHECK_CODE_QUALITY=ON`, you will be able to run `make clang-format` to automatically format code. If code in your PR is not formatted according to [`.clang-format`](.clang-format), the checks will not pass.
|
||||
Code should be formatted using `clang-format`. By configuring Conky with `cmake -DCHECK_CODE_QUALITY=ON`, you will be able to run `make clang-format` to automatically format code.
|
||||
|
||||
## Git hooks
|
||||
|
||||
To make life easier, you can use
|
||||
[lefthook](https://github.com/evilmartians/lefthook) to handle some basic
|
||||
linting with a pre-commit hook, as defined in [lefthook.yml](lefthook.yml).
|
||||
Follow the [installation guide for
|
||||
lefhook](https://github.com/evilmartians/lefthook/blob/master/docs/install.md),
|
||||
then run `lefthook install` to enable the hooks.
|
||||
|
||||
## Unit Testing
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
pre-commit:
|
||||
commands:
|
||||
web-linter:
|
||||
parallel: true
|
||||
run: |
|
||||
npx eslint --fix {staged_files} \
|
||||
&& git add {staged_files}
|
||||
root: web/
|
||||
glob: '*.{ts,tsx,js,jsx}'
|
||||
cpp-linter:
|
||||
run: |
|
||||
clang-format -i {staged_files} \
|
||||
&& git add {staged_files}
|
||||
glob: '*.{c,cc,cxx,h,cpp}'
|
||||
misc-linter:
|
||||
run: |
|
||||
npx prettier --write {staged_files} \
|
||||
&& git add {staged_files}
|
||||
glob: '*.{md,json,yml,yaml}'
|
|
@ -1,7 +1,16 @@
|
|||
{
|
||||
"extends": ["next/core-web-vitals", "prettier"],
|
||||
"settings": {
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"next/core-web-vitals",
|
||||
"prettier"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"root": true,
|
||||
"settings": {
|
||||
"mdx/code-blocks": true,
|
||||
"mdx/language-mapper": {}
|
||||
"mdx/language-mapper": {},
|
||||
"sort-imports": "error"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,3 +39,6 @@ yarn-error.log*
|
|||
|
||||
# IDEs
|
||||
.vscode/
|
||||
|
||||
# Cypress videos
|
||||
cypress/videos
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import Link from 'next/link'
|
||||
import { Url } from 'url'
|
||||
|
||||
interface CustomLinkProps {
|
||||
as: Url
|
||||
href: Url
|
||||
}
|
||||
|
||||
export default function CustomLink({
|
||||
as,
|
||||
href,
|
||||
...otherProps
|
||||
}: CustomLinkProps) {
|
||||
return (
|
||||
<>
|
||||
<Link as={as} href={href}>
|
||||
<a {...otherProps} />
|
||||
</Link>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -32,9 +32,7 @@ export default function Docs({ docs, braces, assign }: DocsProps) {
|
|||
<div className="flex">
|
||||
<div className="px-2 py-3">
|
||||
<Link href={`#${doc.name}`}>
|
||||
<a>
|
||||
<LinkIcon size={20} />
|
||||
</a>
|
||||
<LinkIcon size={20} />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex-col p-1">
|
||||
|
|
|
@ -13,7 +13,8 @@ type HeaderProps = {
|
|||
|
||||
import * as React from 'react'
|
||||
import Search from './Search'
|
||||
import { SearchIndex } from '../utils/search'
|
||||
import { SearchIndex, SearchItem } from '../utils/search'
|
||||
import Fuse from 'fuse.js'
|
||||
|
||||
interface NavLinkProps {
|
||||
href: string
|
||||
|
@ -26,12 +27,11 @@ const NavLink: React.FunctionComponent<NavLinkProps> = (props) => {
|
|||
? 'bg-rose-100 dark:bg-rose-900'
|
||||
: ''
|
||||
return (
|
||||
<Link href={props.href}>
|
||||
<a
|
||||
className={`m-0.5 p-1 self-end hover:ring-1 ring-black dark:ring-white hover:bg-rose-300 dark:hover:bg-rose-700 ${bg} rounded`}
|
||||
>
|
||||
{props.name}
|
||||
</a>
|
||||
<Link
|
||||
href={props.href}
|
||||
className={`m-0.5 p-1 self-end hover:ring-1 ring-black dark:ring-white hover:bg-rose-300 dark:hover:bg-rose-700 ${bg} rounded`}
|
||||
>
|
||||
{props.name}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
@ -43,14 +43,21 @@ export default function Header({
|
|||
searchIndex,
|
||||
}: HeaderProps) {
|
||||
const router = useRouter()
|
||||
const fuse = React.useMemo(() => {
|
||||
const options: Fuse.IFuseOptions<SearchItem> = {}
|
||||
return new Fuse(
|
||||
searchIndex.list,
|
||||
options,
|
||||
Fuse.parseIndex(searchIndex.index)
|
||||
)
|
||||
}, [searchIndex])
|
||||
|
||||
return (
|
||||
<div className="border-b-1 backdrop-blur-lg bg-white dark:bg-black bg-opacity-20 dark:bg-opacity-20 transition">
|
||||
<header className="max-w-3xl mx-auto m-0 p-1 grow flex w-full">
|
||||
<h1 className="px-2 text-3xl dark:text-white self-end">
|
||||
<Link href="/">
|
||||
<a>
|
||||
<strong>{name}</strong>
|
||||
</a>
|
||||
<strong>{name}</strong>
|
||||
</Link>
|
||||
</h1>
|
||||
{router.asPath != '/' && (
|
||||
|
@ -61,7 +68,7 @@ export default function Header({
|
|||
</div>
|
||||
)}
|
||||
<LineChart width={380} height={40} darkMode={darkMode} />
|
||||
<Search index={searchIndex} />
|
||||
<Search fuse={fuse} />
|
||||
<div className="flex">
|
||||
<div className="border-r mx-1 px-1 border-slate-700">
|
||||
<a href="https://github.com/brndnmtthws/conky">
|
||||
|
|
|
@ -34,7 +34,7 @@ export default function Layout({ children, searchIndex }: LayoutProps) {
|
|||
}, [darkMode])
|
||||
|
||||
useEffect(() => {
|
||||
var darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
const darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
|
||||
darkQuery.onchange = (e) => {
|
||||
if (e.matches) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useEffect, useMemo, useRef } from 'react'
|
||||
import * as d3 from 'd3'
|
||||
import { random } from 'colord'
|
||||
|
||||
|
@ -40,12 +40,12 @@ function fetchData() {
|
|||
const data = JSON.parse(storedData)
|
||||
return data || []
|
||||
}
|
||||
var data = fetchData()
|
||||
const data = fetchData()
|
||||
|
||||
export const LineChart = ({ width, height, darkMode }: LineChartProps) => {
|
||||
const timerRef = useRef<NodeJS.Timeout>()
|
||||
const svgRef = useRef(null)
|
||||
const [stroke, setStroke] = useState(random())
|
||||
const stroke = useMemo(() => random(), [])
|
||||
|
||||
useEffect(() => {
|
||||
const doIt = (data: DataPoint[]) => {
|
||||
|
@ -59,7 +59,7 @@ export const LineChart = ({ width, height, darkMode }: LineChartProps) => {
|
|||
.range([height, 0])
|
||||
|
||||
// X axis
|
||||
const [xMin, xMax] = d3.extent(data, (d) => d.x)
|
||||
const [, xMax] = d3.extent(data, (d) => d.x)
|
||||
const xScale = d3
|
||||
.scaleLinear()
|
||||
.domain([(xMax || 0) - width, xMax || 0])
|
||||
|
@ -83,7 +83,7 @@ export const LineChart = ({ width, height, darkMode }: LineChartProps) => {
|
|||
.attr('x', (d) => xScale(d.x))
|
||||
.attr('y', (d) => yScale(d.y))
|
||||
.attr('height', (d) => yScale((max || 0) - d.y))
|
||||
.attr('width', (d) => 1),
|
||||
.attr('width', () => 1),
|
||||
(update) =>
|
||||
update
|
||||
.transition()
|
||||
|
@ -95,7 +95,7 @@ export const LineChart = ({ width, height, darkMode }: LineChartProps) => {
|
|||
.attr('x', (d) => xScale(d.x))
|
||||
.attr('y', (d) => yScale(d.y))
|
||||
.attr('height', (d) => yScale((max || 0) - d.y))
|
||||
.attr('width', (d) => 1),
|
||||
.attr('width', () => 1),
|
||||
(exit) => exit.call((d) => d.transition().remove())
|
||||
)
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import Fuse from 'fuse.js'
|
||||
import React, { Fragment, useCallback, useEffect, useState } from 'react'
|
||||
import { Search as SearchIcon } from 'react-feather'
|
||||
import { SearchIndex, SearchItem } from '../utils/search'
|
||||
import { SearchItem } from '../utils/search'
|
||||
import { Dialog, Transition, Combobox } from '@headlessui/react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export interface SearchProps {
|
||||
index: SearchIndex
|
||||
fuse: Fuse<SearchItem>
|
||||
}
|
||||
|
||||
interface SearchResultProps {
|
||||
|
@ -57,23 +57,13 @@ const SearchResult: React.FunctionComponent<SearchResultProps> = (props) => {
|
|||
)
|
||||
}
|
||||
|
||||
const Search: React.FunctionComponent<SearchProps> = (props) => {
|
||||
const Search: React.FunctionComponent<SearchProps> = ({ fuse }) => {
|
||||
const router = useRouter()
|
||||
const [searchText, setSearchText] = useState('')
|
||||
const [selected, setSelected] = useState<
|
||||
Fuse.FuseResult<SearchItem> | undefined
|
||||
>(undefined)
|
||||
const [searchResults, setSearchResults] = useState<
|
||||
Fuse.FuseResult<SearchItem>[]
|
||||
>([])
|
||||
const [fuse, setFuse] = useState(() => {
|
||||
const options: Fuse.IFuseOptions<SearchItem> = {}
|
||||
return new Fuse(
|
||||
props.index.list,
|
||||
options,
|
||||
Fuse.parseIndex(props.index.index)
|
||||
)
|
||||
})
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const handleKeyPress = useCallback(
|
||||
(event: KeyboardEvent) => {
|
||||
|
@ -159,7 +149,7 @@ const Search: React.FunctionComponent<SearchProps> = (props) => {
|
|||
<div className="fixed inset-0">
|
||||
<div className="flex h-screen w-screen items-start justify-center p-16 text-center">
|
||||
<Dialog.Panel className="flex flex-col max-h-full w-full max-w-2xl p-1 bg-gray-200 dark:bg-gray-800 transform rounded-xl text-left align-middle shadow transition-all border border-gray-800 dark:border-white border-opacity-10 dark:border-opacity-10">
|
||||
<Combobox value={selected} nullable onChange={onChange}>
|
||||
<Combobox nullable onChange={onChange}>
|
||||
<div className="flex">
|
||||
<Combobox.Label className="flex items-center ml-2">
|
||||
<SearchIcon size={32} />
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { Dispatch, SetStateAction } from 'react'
|
||||
|
||||
const sunIcon = (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,18 +11,20 @@
|
|||
"url": "https://github.com/brndnmtthws/conky/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"dev": "next dev",
|
||||
"dev:watch": "next-remote-watch ./documents",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"export": "next build && next export",
|
||||
"lint": "next lint"
|
||||
"lint": "next lint",
|
||||
"e2e": "start-server-and-test dev http://localhost:3000 \"cypress open --e2e\"",
|
||||
"e2e:headless": "start-server-and-test dev http://localhost:3000 \"cypress run --e2e\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/fira-code": "^4.5.13",
|
||||
"@fontsource/inter": "^4.5.15",
|
||||
"@fontsource/newsreader": "^4.5.10",
|
||||
"@headlessui/react": "^1.7.11",
|
||||
"@headlessui/react": "^1.7.12",
|
||||
"@mapbox/rehype-prism": "^0.8.0",
|
||||
"@netlify/plugin-nextjs": "^4.30.4",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
|
@ -32,7 +34,7 @@
|
|||
"fuse.js": "^6.6.2",
|
||||
"gray-matter": "^4.0.3",
|
||||
"inter-ui": "^3.19.3",
|
||||
"next": "^13.1.6",
|
||||
"next": "^13.2.1",
|
||||
"prismjs": "^1.29.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
@ -41,23 +43,25 @@
|
|||
"devDependencies": {
|
||||
"@types/d3": "^7.4.0",
|
||||
"@types/mapbox__rehype-prism": "^0.8.0",
|
||||
"@types/node": "^18.14.0",
|
||||
"@types/node": "^18.14.1",
|
||||
"@types/react": "^18.0.28",
|
||||
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
||||
"@typescript-eslint/parser": "^5.53.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"cypress": "^12.6.0",
|
||||
"cypress": "^12.7.0",
|
||||
"eslint": "^8.34.0",
|
||||
"eslint-config-next": "^13.1.6",
|
||||
"eslint-config-next": "^13.2.1",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-mdx": "^2.0.5",
|
||||
"js-yaml": "^4.1.0",
|
||||
"netlify-plugin-cypress": "^2.2.0",
|
||||
"netlify-plugin-cypress": "^2.2.1",
|
||||
"next-mdx-remote": "^4.3.0",
|
||||
"next-remote-watch": "2.0.0",
|
||||
"postcss": "^8.4.21",
|
||||
"rehype-stringify": "^9.0.3",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"start-server-and-test": "^1.15.4",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"tslint": "^6.1.3",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,18 +7,19 @@ import {
|
|||
|
||||
import { MDXRemote, MDXRemoteProps } from 'next-mdx-remote'
|
||||
import Head from 'next/head'
|
||||
import CustomLink from '../../components/CustomLink'
|
||||
import Layout from '../../components/Layout'
|
||||
import SEO from '../../components/SEO'
|
||||
import { GetStaticProps } from 'next'
|
||||
import { getSearchIndex, SearchIndex } from '../../utils/search'
|
||||
import Link from 'next/link'
|
||||
import { MDXComponents } from 'mdx/types'
|
||||
|
||||
// Custom components/renderers to pass to MDX.
|
||||
// Since the MDX files aren't loaded by webpack, they have no knowledge of how
|
||||
// to handle import statements. Instead, you must include components in scope
|
||||
// here.
|
||||
const components = {
|
||||
a: CustomLink,
|
||||
a: Link,
|
||||
// It also works with dynamically-imported components, which is especially
|
||||
// useful for conditionally loading components for certain routes.
|
||||
// See the notes in README.md for more details.
|
||||
|
@ -58,7 +59,7 @@ export default function DocumentPage({
|
|||
</header>
|
||||
<main>
|
||||
<article className="prose dark:prose-invert prose-lg lg:prose-xl">
|
||||
<MDXRemote {...source} components={components as any} />
|
||||
<MDXRemote {...source} components={components as MDXComponents} />
|
||||
</article>
|
||||
</main>
|
||||
</article>
|
||||
|
|
|
@ -4,7 +4,6 @@ import Layout from '../components/Layout'
|
|||
import ArrowIcon from '../components/ArrowIcon'
|
||||
import SEO from '../components/SEO'
|
||||
import { getSearchIndex, SearchIndex } from '../utils/search'
|
||||
import { Url } from 'url'
|
||||
|
||||
const pages = [
|
||||
{
|
||||
|
@ -34,14 +33,14 @@ interface IndexItemProps {
|
|||
const IndexItem: React.FunctionComponent<IndexItemProps> = (props) => {
|
||||
return (
|
||||
<div className="md:first:rounded-t-lg md:last:rounded-b-lg backdrop-blur-lg bg-slate-300 dark:bg-black dark:bg-opacity-30 bg-opacity-10 hover:bg-opacity-30 dark:hover:bg-opacity-50 transition border border-gray-800 dark:border-white border-opacity-10 dark:border-opacity-10 border-b-0 last:border-b hover:border-b hovered-sibling:border-t-0">
|
||||
<Link as={props.as} href={props.href}>
|
||||
<a className="py-2 lg:py-4 px-2 lg:px-4 block focus:outline-none focus:ring-4">
|
||||
<h2 className="text-xl md:text-2xl">{props.title}</h2>
|
||||
{props.desc && (
|
||||
<p className="mt-3 text-lg opacity-60">{props.desc}</p>
|
||||
)}
|
||||
<ArrowIcon className="mt-4" />
|
||||
</a>
|
||||
<Link
|
||||
as={props.as}
|
||||
href={props.href}
|
||||
className="py-2 lg:py-4 px-2 lg:px-4 block focus:outline-none focus:ring-4"
|
||||
>
|
||||
<h2 className="text-xl md:text-2xl">{props.title}</h2>
|
||||
{props.desc && <p className="mt-3 text-lg opacity-60">{props.desc}</p>}
|
||||
<ArrowIcon className="mt-4" />
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -5,4 +5,4 @@ module.exports = {
|
|||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
|
@ -19,12 +15,6 @@
|
|||
"isolatedModules": true,
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue