Пересобранный и видоизмененный conky для ОСГОС
This commit is contained in:
commit
3a48cf8c86
738 changed files with 217718 additions and 0 deletions
16
web/.eslintrc.json
Normal file
16
web/.eslintrc.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"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": {},
|
||||
"sort-imports": "error"
|
||||
}
|
||||
}
|
||||
47
web/.gitignore
vendored
Normal file
47
web/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
*.tsbuildinfo
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# netlify
|
||||
.netlify
|
||||
|
||||
# IDEs
|
||||
.vscode/
|
||||
|
||||
# Cypress videos
|
||||
cypress/videos
|
||||
|
||||
# Fuse.js index (we generate this on the fly)
|
||||
public/static/fuse-index.json
|
||||
24
web/components/ArrowIcon.tsx
Normal file
24
web/components/ArrowIcon.tsx
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
interface ArrowIconProps {
|
||||
className: string
|
||||
}
|
||||
|
||||
export default function ArrowIcon({ className }: ArrowIconProps) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
className="stroke-current text-primary"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M5 12h14M12 19l7-7-7-7"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
36
web/components/CopyleftIcon.tsx
Normal file
36
web/components/CopyleftIcon.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
interface CopyleftIconProps {
|
||||
className?: string
|
||||
width?: number
|
||||
height?: number
|
||||
}
|
||||
|
||||
export default function CopyleftIcon({
|
||||
className,
|
||||
width,
|
||||
height,
|
||||
}: CopyleftIconProps) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={width || 980}
|
||||
height={height || 980}
|
||||
fill="none"
|
||||
viewBox="0 0 980 980"
|
||||
className={className}
|
||||
>
|
||||
<circle
|
||||
cx="490"
|
||||
cy="490"
|
||||
r="440"
|
||||
fill="none"
|
||||
strokeWidth="100"
|
||||
className="stroke-current"
|
||||
/>
|
||||
<path
|
||||
d="M219,428H350a150,150 0 1 1 0,125H219a275,275 0 1 0 0-125z"
|
||||
strokeWidth="1"
|
||||
className="stroke-current fill-current"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
82
web/components/Docs.tsx
Normal file
82
web/components/Docs.tsx
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import { Documentation } from '../utils/doc-utils'
|
||||
import { Link as LinkIcon } from 'react-feather'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export interface DocsProps {
|
||||
docs: Documentation
|
||||
braces: boolean
|
||||
assign: boolean
|
||||
}
|
||||
|
||||
export default function Docs({ docs, braces, assign }: DocsProps) {
|
||||
const router = useRouter()
|
||||
return (
|
||||
<div className="prose dark:prose-invert prose-lg w-full max-w-3xl">
|
||||
<div className="px-2 lg:px-4" dangerouslySetInnerHTML={{ __html: docs.desc_md }} />
|
||||
|
||||
<div className="divide-y divide-gray-700/25 dark:divide-gray-300/25">
|
||||
{docs.values.map((doc) => {
|
||||
const target = router.asPath.endsWith(`#${doc.name}`)
|
||||
return (
|
||||
<div
|
||||
id={doc.name}
|
||||
key={doc.name}
|
||||
className={
|
||||
'pt-4 scroll-mt-16 overflow-auto ' +
|
||||
(target
|
||||
? 'bg-rose-300 dark:bg-rose-900'
|
||||
: 'bg-slate-200 dark:bg-slate-800 target:bg-rose-300 target:dark:bg-rose-900') +
|
||||
' hover:bg-opacity-25 dark:hover:bg-opacity-25 hover:ring-1 ring-black dark:ring-white ring-inset'
|
||||
}
|
||||
>
|
||||
<div className="flex">
|
||||
<div className="px-2 lg:pl-4 py-3">
|
||||
<Link href={`#${doc.name}`} data-anchor-name={doc.name}>
|
||||
<LinkIcon size={20} />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex-col p-1 pr-2 lg:pr-4">
|
||||
<div>
|
||||
{braces && <code>${</code>}
|
||||
<code className="text-lg p-1 mx-1 bg-fuchsia-200 dark:bg-fuchsia-900 font-bold">
|
||||
{doc.name}
|
||||
</code>
|
||||
{typeof doc.args != 'undefined' && doc.args.length > 0 && (
|
||||
<>
|
||||
{assign && <code>=</code>}
|
||||
<em>
|
||||
{doc.args.map((arg) => (
|
||||
<code
|
||||
className="text-lg p-1 mx-1 bg-slate-200 dark:bg-slate-800"
|
||||
key={arg}
|
||||
>
|
||||
{arg}
|
||||
</code>
|
||||
))}
|
||||
</em>
|
||||
</>
|
||||
)}
|
||||
{braces && <code>}</code>}
|
||||
</div>
|
||||
<div
|
||||
className="py-2"
|
||||
dangerouslySetInnerHTML={{ __html: doc.desc_md }}
|
||||
/>
|
||||
{typeof doc.default != 'undefined' && (
|
||||
<div>
|
||||
Default:{' '}
|
||||
<code className="px-1 mx-1 bg-slate-200 dark:bg-slate-800">
|
||||
{doc.default}
|
||||
</code>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
87
web/components/Doggy.tsx
Normal file
87
web/components/Doggy.tsx
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
import * as React from 'react'
|
||||
|
||||
const Doggy: React.FunctionComponent = () => {
|
||||
return (
|
||||
// from https://undraw.co/
|
||||
<svg className="w-full" width="656" height="447.5061" viewBox="0 0 656 447.5061">
|
||||
<path
|
||||
d="M108.40148,315.94602c-3.16093,.3401-6.60921,.85055-10.27718,1.59744-15.55246,3.16687-15.87526,13.72736-15.73896,16.14847l-.10566-.06586c-1.56382,2.50859-2.54325,5.0473-3.13519,7.44337l-.71221-32.36652c.46052-.9602,.87954-2.04896,1.22889-3.16494,1.16419,3.58504,3.07256,6.97195,4.7176,6.74748,2.13909-.2919,3.07167-6.58596,2.67265-11.05881,2.72016,3.50314,7.2981,7.24972,9.02511,6.09446,1.38001-.92313,.56173-4.72359-.94492-8.17871,3.13929,1.89132,6.61613,3.13439,7.69503,1.93342,1.47227-1.63885-2.05557-7.23082-5.30905-10.35235,4.35496,.40613,9.89372-.28771,10.25684-2.26977,.2992-1.6331-2.99722-3.69384-6.5255-5.02014,3.5439-.93441,6.85789-2.56256,6.74798-4.17324-.13057-1.91338-5.05068-3.19543-9.29526-3.39051,3.20154-2.50471,6.14321-5.96711,5.24362-7.53303-.82704-1.43962-4.67439-.88198-8.22406,.38596,2.10064-3.00326,3.5775-6.38742,2.45277-7.54556-1.40106-1.44266-6.37359,1.04738-9.76711,3.79978,.66062-4.28797,.32665-9.70052-1.59659-10.19022-1.60895-.40967-3.88929,2.73886-5.4527,6.16866-.69097-3.59931-2.08979-7.01645-3.7042-7.01645-2.29982,0-4.16418,6.93399-4.16418,11.45149,0,.25536,.00677,.49574,.01843,.72541-.23083-.26761-.49538-.54719-.79707-.84018-3.24076-3.14728-9.51391-6.64064-11.11616-4.99082-1.12474,1.15814,.35212,4.5423,2.45277,7.54556-3.54967-1.26794-7.39702-1.82559-8.22406-.38596-1.11127,1.93439,3.63883,6.76323,7.4999,9.10499-.2321-.02796-.47595-.0515-.73547-.0692-4.50701-.30752-11.55183,1.08049-11.7084,3.37497-.10991,1.61067,3.20409,3.23883,6.74798,4.17324-3.52829,1.3263-6.8247,3.38704-6.5255,5.02014,.36312,1.98206,5.90188,2.6759,10.25684,2.26977-3.25348,3.12154-6.78132,8.7135-5.30905,10.35235,1.0789,1.20097,4.55573-.0421,7.69503-1.93342-1.50665,3.45512-2.32492,7.25558-.94492,8.17871,1.82373,1.21996,6.82541-3.02601,9.4625-6.67949-.2687,4.46965,.80077,10.61004,2.9228,10.85236,.88742,.10134,1.82777-.84507,2.67643-2.3023l-2.40356,34.79012c-.56184,4.05159,3.03199,6.69542,3.35318,8.36434l.51842,23.5593c-.58508-1.67794-1.37316-3.3952-2.43548-5.09933l-.10566,.0659c.13628-2.42136-.18675-12.98155-15.73896-16.14836-3.66797-.74689-7.11625-1.25734-10.27718-1.59744-3.73116-.40145-5.1866,4.70611-1.81595,6.35581,4.88144,2.38917,9.4733,5.39935,11.86668,8.96403,6.11901,9.11359,14.5737,3.84542,15.77578,3.0275,1.34266,2.23509,2.22306,4.48687,2.77913,6.62945l.27531,12.51144c-.06744,.2959-.11414,.46159-.11777,.47403l.12902,.03782,.66628,30.27884,6.18057-.04965-2.21068-30.94947c.37149-1.66957,1.51435-7.35722,0-13.26406l-2.21068-24.31744h0c-.0055-.01877,.12548,.63842,0,0l-2.8837-9.55504c.41933-2.95604,1.3925-6.28098,3.36894-9.57097,1.20206,.81791,9.65677,6.08611,15.77579-3.0275,2.39338-3.56469,6.98524-6.57486,11.86668-8.96403,3.37065-1.64971,1.91521-6.75726-1.81595-6.35581Zm-28.23342,71.6385l-.11651-5.2952c.23499,2.00214,.2231,3.80933,.11651,5.2952Z"
|
||||
fill="#f2f2f2"
|
||||
/>
|
||||
<path
|
||||
d="M581.40148,315.94602c-3.16093,.3401-6.60921,.85055-10.27718,1.59744-15.55246,3.16687-15.87526,13.72736-15.73896,16.14847l-.10566-.06586c-1.56382,2.50859-2.54325,5.0473-3.13519,7.44337l-.71221-32.36652c.46052-.9602,.87954-2.04896,1.22889-3.16494,1.16419,3.58504,3.07256,6.97195,4.7176,6.74748,2.13909-.2919,3.07167-6.58596,2.67265-11.05881,2.72016,3.50314,7.2981,7.24972,9.02511,6.09446,1.38001-.92313,.56173-4.72359-.94492-8.17871,3.13929,1.89132,6.61613,3.13439,7.69503,1.93342,1.47227-1.63885-2.05557-7.23082-5.30905-10.35235,4.35496,.40613,9.89372-.28771,10.25684-2.26977,.2992-1.6331-2.99722-3.69384-6.5255-5.02014,3.5439-.93441,6.85789-2.56256,6.74798-4.17324-.13057-1.91338-5.05068-3.19543-9.29526-3.39051,3.20154-2.50471,6.14321-5.96711,5.24362-7.53303-.82704-1.43962-4.67439-.88198-8.22406,.38596,2.10064-3.00326,3.5775-6.38742,2.45277-7.54556-1.40106-1.44266-6.37359,1.04738-9.76711,3.79978,.66062-4.28797,.32665-9.70052-1.59659-10.19022-1.60895-.40967-3.88929,2.73886-5.4527,6.16866-.69097-3.59931-2.08979-7.01645-3.7042-7.01645-2.29982,0-4.16418,6.93399-4.16418,11.45149,0,.25536,.00677,.49574,.01843,.72541-.23083-.26761-.49538-.54719-.79707-.84018-3.24076-3.14728-9.51391-6.64064-11.11616-4.99082-1.12474,1.15814,.35212,4.5423,2.45277,7.54556-3.54967-1.26794-7.39702-1.82559-8.22406-.38596-1.11127,1.93439,3.63883,6.76323,7.4999,9.10499-.2321-.02796-.47595-.0515-.73547-.0692-4.50701-.30752-11.55183,1.08049-11.7084,3.37497-.10991,1.61067,3.20409,3.23883,6.74798,4.17324-3.52829,1.3263-6.8247,3.38704-6.5255,5.02014,.36312,1.98206,5.90188,2.6759,10.25684,2.26977-3.25348,3.12154-6.78132,8.7135-5.30905,10.35235,1.0789,1.20097,4.55573-.0421,7.69503-1.93342-1.50665,3.45512-2.32492,7.25558-.94492,8.17871,1.82373,1.21996,6.82541-3.02601,9.4625-6.67949-.2687,4.46965,.80077,10.61004,2.9228,10.85236,.88742,.10134,1.82777-.84507,2.67643-2.3023l-2.40356,34.79012c-.56184,4.05159,3.03199,6.69542,3.35318,8.36434l.51842,23.5593c-.58508-1.67794-1.37316-3.3952-2.43548-5.09933l-.10566,.0659c.13628-2.42136-.18675-12.98155-15.73896-16.14836-3.66797-.74689-7.11625-1.25734-10.27718-1.59744-3.73116-.40145-5.1866,4.70611-1.81595,6.35581,4.88144,2.38917,9.4733,5.39935,11.86668,8.96403,6.11901,9.11359,14.5737,3.84542,15.77578,3.0275,1.34266,2.23509,2.22306,4.48687,2.77913,6.62945l.27531,12.51144c-.06744,.2959-.11414,.46159-.11777,.47403l.12902,.03782,.66628,30.27884,6.18057-.04965-2.21068-30.94947c.37149-1.66957,1.51435-7.35722,0-13.26406l-2.21068-24.31744h0c-.0055-.01877,.12548,.63842,0,0l-2.8837-9.55504c.41933-2.95604,1.3925-6.28098,3.36894-9.57097,1.20206,.81791,9.65677,6.08611,15.77579-3.0275,2.39338-3.56469,6.98524-6.57486,11.86668-8.96403,3.37065-1.64971,1.91521-6.75726-1.81595-6.35581Zm-28.23342,71.6385l-.11651-5.2952c.23499,2.00214,.2231,3.80933,.11651,5.2952Z"
|
||||
fill="#f2f2f2"
|
||||
/>
|
||||
<path
|
||||
d="M485.44292,216.85712l-2.89819-69.09314s-3.25537-41.01923-5.85986-55.34344c-2.60437-14.32416-20.18408-10.4176-20.18408-10.4176l1.95337,41.01929,8.42773,41.97778,6.55957,57.16211c-.33789,1.6535-.5293,3.45087-.5293,5.33789,0,8.00812,3.34424,14.5,7.46973,14.5s7.46973-6.49188,7.46973-14.5c0-4.21252-.93103-7.99371-2.40869-10.64288Z"
|
||||
fill="#ffb6b6"
|
||||
/>
|
||||
<path
|
||||
d="M344.36666,198.95449c3.08175-3.6707,6.77264-6.1651,10.08696-7.12522l38.98077-44.06526s3.2555-41.01927,5.8599-55.34346c2.6044-14.32419,20.18408-10.41759,20.18408-10.41759l-1.9533,41.01927-11.06869,44.27477-45.61337,38.72532c-.79655,1.45114-1.77304,2.90165-2.94266,4.29478-5.54929,6.60955-13.07747,9.42409-16.81477,6.28638-3.73715-3.13771-2.2682-11.03944,3.28109-17.64899Z"
|
||||
fill="#ffb6b6"
|
||||
/>
|
||||
<polygon
|
||||
points="430.13131 76.46862 434.65312 59.08516 452.2687 58.23783 457.53901 82.20035 430.13131 76.46862"
|
||||
fill="#ffb6b6"
|
||||
/>
|
||||
<polygon
|
||||
points="430.13131 76.46862 434.65312 59.08516 452.2687 58.23783 457.53901 82.20035 430.13131 76.46862"
|
||||
opacity=".1"
|
||||
/>
|
||||
<g>
|
||||
<polygon
|
||||
points="385.1488 361.25683 368.64994 360.3143 370.81424 410.94912 381.99418 411.58853 385.1488 361.25683"
|
||||
fill="#ffb6b6"
|
||||
/>
|
||||
<path
|
||||
d="M369.38449,394.93938l5.72891,2.61332-.00743,3.47275s1.38213-4.01923,8.80109-4.89615l.88559,3.36705s2.87736,3.30264,2.38384,9.27645l-1.8885,15.99763-5.59502-.12882-.90369-11.132s-1.5413-2.52606-8.64068,9.47718c0,0-7.82052,1.9711-19.93118-2.08958-1.66453-.55811-2.82078-2.11212-2.79901-3.86759,.01202-.96878,.39069-1.8641,1.60549-2.18526,3.0922-.8175,6.11176,.21911,8.10866-2.24898,1.9969-2.46809,12.25193-17.656,12.25193-17.656Z"
|
||||
fill="#2f2e41"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon
|
||||
points="473.69834 361.25683 457.19947 360.3143 459.36377 410.94912 470.54371 411.58853 473.69834 361.25683"
|
||||
fill="#ffb6b6"
|
||||
/>
|
||||
<path
|
||||
d="M457.93402,394.93938l5.72891,2.61332-.00743,3.47275s1.38213-4.01923,8.80109-4.89615l.88559,3.36705s2.87736,3.30264,2.38384,9.27645l-1.8885,15.99763-5.59502-.12882-.90369-11.132s-1.5413-2.52606-8.64068,9.47718c0,0-7.82052,1.9711-19.93118-2.08958-1.66453-.55811-2.82078-2.11212-2.79901-3.86759,.01202-.96878,.39069-1.8641,1.60549-2.18526,3.0922-.8175,6.11176,.21911,8.10866-2.24898,1.9969-2.46809,12.25193-17.656,12.25193-17.656Z"
|
||||
fill="#2f2e41"
|
||||
/>
|
||||
</g>
|
||||
<circle cx="443.67515" cy="49.78935" r="19.53299" fill="#ffb6b6" />
|
||||
<path
|
||||
d="M454.75196,53.03639s-8.58797-14.05193-17.1846-12.50095c-8.59662,1.55098-13.07809,2.95128-13.07809,2.95128,0,0-3.50075-11.20367,8.25239-16.57884,0,0-16.63273-13.92589,1.09406-22.86307,17.72679-8.93718,28.7577-.27561,28.7577-.27561,0,0,14.67194,12.44289-1.59513,23.95832,0,0,14.07934,16.03785-.14106,31.35764,0,0,2.5104-11.66516-.9046-9.27374-3.41501,2.39142-5.20067,3.22497-5.20067,3.22497Z"
|
||||
fill="#2f2e41"
|
||||
/>
|
||||
<path
|
||||
d="M456.82639,77.77082l-26.69508-3.2555-20.50963,16.60304s-10.20026,28.4207-2.6044,45.57697c.18201,.4111,.32555,28.97393,.32555,28.97393h56.71743s-.05495-19.44142,2.11224-26.48271c.3096-1.0059,.66455-1.75873,1.07149-2.16567,3.2555-3.2555,11.06869-24.09068,7.16209-33.20607-3.9066-9.11539-17.57969-26.04398-17.57969-26.04398Z"
|
||||
fill="#6c63ff"
|
||||
/>
|
||||
<polygon
|
||||
points="407.01728 164.36705 371.20681 278.30947 363.39361 368.1612 385.20545 368.1612 403.76178 284.82046 429.31616 236.57758 454.54754 374.67219 476.56445 374.67219 476.03383 187.80663 464.01412 164.36705 407.01728 164.36705"
|
||||
fill="#2f2e41"
|
||||
/>
|
||||
<rect y="422.15664" width="656" height="2" fill="#3f3d56" />
|
||||
<g>
|
||||
<path
|
||||
d="M336.26362,187.42757c-6.50229-10.47037-21.67223-12.93381-32.93992-7.93906-11.26769,4.99475-19.0565,15.64429-24.35105,26.77426-5.29455,11.12996-8.62502,23.12151-14.06681,34.18023-16.01157,32.53845-48.43603,53.78965-68.83256,83.77469-15.32504,22.52941-23.44045,49.88437-22.88108,77.12621,.21426,10.43456,1.9016,21.41209,8.41343,29.56819,9.66535,12.1059,26.77774,14.58924,42.18653,16.18335,8.95057,.92597,19.93647,.89956,24.54601-6.82846,1.82337-3.05693-17.77064-13.72146-17.45627-17.26697,1.69638-19.13259,23.34373-31.28271,25.04011-50.41531,2.6597,13.33132-.7489,27.0942-.2109,40.67759,.53799,13.58339,7.23345,28.94778,20.53418,31.75641,4.10444,.86671,8.73862,.26717,11.84946-2.54713,3.11084-2.81429,4.01941-8.13071,1.24812-11.27992,2.83767,2.89821,7.62638,3.6514,11.21672,1.76422,3.59034-1.88718,5.68538-6.25866,4.90727-10.23943-.5722-2.92733-2.46138-5.38952-4.0973-7.88359-8.86167-13.51019-11.17027-31.11518-6.09158-46.45342,8.97777-27.11391,38.45973-44.81167,43.45404-72.93321,3.70897-20.88416-6.8726-44.54836,4.35624-62.54329,5.06032-8.10949,13.65271-13.22163,20.50586-19.88533,6.85315-6.6637,12.21238-16.85889,8.29043-25.57606l-35.02913-.03819"
|
||||
fill="#3f3d56"
|
||||
/>
|
||||
<path
|
||||
d="M228.23833,426.7864c-.87183,0-1.76514-.23291-2.62842-.6958-1.98853-1.06641-3.48804-3.1748-3.82056-5.37207-.55322-3.6543,1.1875-7.20312,2.58618-10.05469,3.82593-7.79883,7.60791-16.13818,8.16528-24.80273,.60889-9.46045-3.22852-18.22949-9.77563-22.34082-4.86572-3.05469-11.36255-3.84033-18.29248-2.21045-6.13794,1.44336-11.6521,4.39404-17.71045,7.81689-.4812,.27197-1.09082,.10254-1.36255-.37891-.27173-.48047-.10205-1.09082,.37866-1.3623,5.96631-3.37109,11.85034-6.521,18.23633-8.02295,7.45483-1.75195,14.49146-.87793,19.81396,2.46436,7.16016,4.49609,11.36328,13.98047,10.70824,24.1626-.58104,9.03027-4.45141,17.57617-8.36596,25.55518-1.34229,2.73682-2.86377,5.83887-2.40405,8.87451,.23779,1.57129,1.35815,3.14209,2.78833,3.90869,.69653,.37402,1.75879,.71045,2.86206,.19727,.50146-.23438,1.0957-.0166,1.32886,.48389s.0166,1.0957-.48413,1.32861c-.64282,.2998-1.32617,.44873-2.02368,.44873Z"
|
||||
fill="#2f2e41"
|
||||
/>
|
||||
<path
|
||||
d="M304.87324,186.74131c-1.30944,3.58632,.43745,7.60574,2.85869,10.55768,2.42124,2.95194,5.531,5.3258,7.66451,8.49194,4.47207,6.63654,3.80132,15.70946,.36506,22.93685-3.43625,7.22739-9.22913,13.01799-14.91052,18.65402,.41995-2.41674-.80214-4.85632-2.46745-6.65736s-3.7617-3.13792-5.62402-4.73441c-8.67234-7.43441-11.3852-20.98221-6.24412-31.18266"
|
||||
fill="#2f2e41"
|
||||
/>
|
||||
<path
|
||||
d="M186.42241,400.10863c-7.34594-.9001-13.55119,5.70986-20.88233,6.72341-8.47755,1.17204-16.27381-5.53591-20.04567-13.21807-3.77186-7.68216-4.73983-16.40208-7.33471-24.55739-2.59488-8.15531-7.60116-16.41523-15.75739-19.00722-3.42187-1.08745-7.29353-1.02838-10.47242,.64087-3.17889,1.66926-5.50871,5.07712-5.4292,8.66675,.09784,4.41706,3.4851,7.95244,5.53718,11.8651,3.26521,6.2257,3.16378,13.59894,4.60607,20.47941,3.46765,16.54261,16.92397,30.57084,33.30801,34.72366,8.47267,2.14754,17.95749,1.6559,25.29692-3.09078s11.81291-14.30671,9.09603-22.61434"
|
||||
fill="#3f3d56"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default Doggy
|
||||
34
web/components/Footer.tsx
Normal file
34
web/components/Footer.tsx
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import getConfig from 'next/config'
|
||||
import CopyleftIcon from './CopyleftIcon'
|
||||
import Link from 'next/link'
|
||||
|
||||
const Footer: React.FunctionComponent = () => {
|
||||
const { publicRuntimeConfig } = getConfig()
|
||||
const { modifiedDate, modifiedYear, gitHash } = publicRuntimeConfig
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto flex py-4 items-center">
|
||||
<div className="px-2 lg:px-4">
|
||||
<CopyleftIcon width={20} height={20} />
|
||||
</div>
|
||||
<div className="pl-1 pr-2 lg:pr-4 font-sans text-xs">
|
||||
<p>
|
||||
{modifiedYear} Conky developers, updated{' '}
|
||||
{new Date(modifiedDate).toLocaleString()} UTC
|
||||
{gitHash && (
|
||||
<>
|
||||
{' '}
|
||||
<Link
|
||||
target="_blank"
|
||||
href={`https://github.com/brndnmtthws/conky/commit/${gitHash}`}
|
||||
>
|
||||
{`(${gitHash})`}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Footer
|
||||
19
web/components/GitHub.tsx
Normal file
19
web/components/GitHub.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
export default function GitHub() {
|
||||
return (
|
||||
<div className="flex rounded-3xl p-1">
|
||||
<svg
|
||||
height="32"
|
||||
width="32"
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 16 16"
|
||||
data-view-component="true"
|
||||
className="fill-current stroke-0"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
74
web/components/Header.tsx
Normal file
74
web/components/Header.tsx
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import GitHub from './GitHub'
|
||||
import ThemeSwitcher from './ThemeSwitcher'
|
||||
|
||||
import * as React from 'react'
|
||||
import Search from './Search'
|
||||
|
||||
type HeaderProps = {
|
||||
name: string
|
||||
setDarkMode: (state: boolean) => void
|
||||
}
|
||||
|
||||
interface NavLinkProps {
|
||||
href: string
|
||||
name: string
|
||||
}
|
||||
|
||||
const NavLink: React.FunctionComponent<NavLinkProps> = (props) => {
|
||||
const router = useRouter()
|
||||
const bg = router.asPath.startsWith(props.href)
|
||||
? 'bg-rose-100 dark:bg-rose-900'
|
||||
: ''
|
||||
return (
|
||||
<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>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Header({ name, setDarkMode }: HeaderProps) {
|
||||
const router = useRouter()
|
||||
|
||||
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 py-1 px-2 lg:px-4 grow flex w-full">
|
||||
<h1 className="text-3xl dark:text-white self-end mr-1">
|
||||
<Link href="/" className="font-bold" data-cy="top-link">
|
||||
{name}
|
||||
</Link>
|
||||
</h1>
|
||||
{router.asPath != '/' && (
|
||||
<div className="hidden sm:flex text-md items-stretch self-stretch mr-1">
|
||||
<NavLink href="/variables" name="Vars" />
|
||||
<NavLink href="/config_settings" name="Config" />
|
||||
<NavLink href="/lua" name="Lua" />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-grow" />
|
||||
<Search />
|
||||
<div className="flex">
|
||||
<div className="flex items-center border-r mx-1 px-1 border-slate-700">
|
||||
<a href="https://github.com/brndnmtthws/conky">
|
||||
<GitHub />
|
||||
</a>
|
||||
</div>
|
||||
<div className="ml-1 pl-1 flex place-content-center place-items-center">
|
||||
<ThemeSwitcher setDarkMode={setDarkMode} />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{router.asPath != '/' && (
|
||||
<div className="flex sm:hidden text-md items-stretch self-stretch px-1 pb-1">
|
||||
<NavLink href="/variables" name="Vars" />
|
||||
<NavLink href="/config_settings" name="Config" />
|
||||
<NavLink href="/lua" name="Lua" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
61
web/components/Layout.tsx
Normal file
61
web/components/Layout.tsx
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import Footer from './Footer'
|
||||
import Header from './Header'
|
||||
|
||||
function darkModeDefault() {
|
||||
if (typeof window === 'undefined') {
|
||||
return false
|
||||
} else {
|
||||
const theme = localStorage.getItem('theme')
|
||||
return (
|
||||
theme === 'dark' ||
|
||||
(!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
interface LayoutProps {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export default function Layout({ children }: LayoutProps) {
|
||||
const [darkMode, setDarkMode] = useState(darkModeDefault())
|
||||
|
||||
useEffect(() => {
|
||||
if (darkMode) {
|
||||
document.documentElement.classList.add('dark')
|
||||
localStorage.setItem('theme', 'dark')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
localStorage.setItem('theme', 'light')
|
||||
}
|
||||
}, [darkMode])
|
||||
|
||||
useEffect(() => {
|
||||
const darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
|
||||
darkQuery.onchange = (e) => {
|
||||
if (e.matches) {
|
||||
setDarkMode(true)
|
||||
} else {
|
||||
setDarkMode(false)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="sticky top-0 z-10">
|
||||
<Header name="Conky" setDarkMode={setDarkMode} />
|
||||
</div>
|
||||
<div className="relative pb-4 md:pt-4">
|
||||
<div className="flex flex-col items-center max-w-3xl w-full mx-auto">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
16
web/components/SEO.tsx
Normal file
16
web/components/SEO.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import Head from 'next/head'
|
||||
|
||||
interface SEOProps {
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export default function SEO({ title, description }: SEOProps) {
|
||||
return (
|
||||
<Head>
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description} />
|
||||
<meta property="og:title" content={title} />
|
||||
</Head>
|
||||
)
|
||||
}
|
||||
213
web/components/Search.tsx
Normal file
213
web/components/Search.tsx
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
import Fuse, { FuseResult } 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 { Dialog, Transition, Combobox } from '@headlessui/react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export interface SearchProps {}
|
||||
|
||||
interface SearchResultProps {
|
||||
result: FuseResult<SearchItem>
|
||||
selected: boolean
|
||||
active: boolean
|
||||
}
|
||||
|
||||
const SearchResult: React.FunctionComponent<SearchResultProps> = (props) => {
|
||||
const excerpt = (s: string) => {
|
||||
if (s.length < 120) {
|
||||
return <>{s}</>
|
||||
} else {
|
||||
return <>{s.substring(0, 120)}…</>
|
||||
}
|
||||
}
|
||||
const bg_for = (s: string) => {
|
||||
const bg = 'p-1 rounded bg-opacity-20 '
|
||||
if (s === 'var') {
|
||||
return bg + 'bg-blue-500'
|
||||
}
|
||||
if (s === 'config') {
|
||||
return bg + 'bg-green-500'
|
||||
}
|
||||
if (s === 'lua') {
|
||||
return bg + 'bg-red-500'
|
||||
}
|
||||
return bg
|
||||
}
|
||||
const selection = props.active ? 'bg-slate-300 dark:bg-slate-700' : ''
|
||||
|
||||
return (
|
||||
<div className={`m-1 rounded flex flex-col p-2 ${selection}`}>
|
||||
<hr className="border-black/10 dark:border-white/10 mb-2"/>
|
||||
<div className="flex justify-between">
|
||||
<div>
|
||||
<code className="text-lg p-1 mx-1 bg-fuchsia-200 dark:bg-fuchsia-900 font-bold">
|
||||
{props.result.item.name}
|
||||
</code>
|
||||
</div>
|
||||
<div className={bg_for(props.result.item.kind)}>
|
||||
{props.result.item.kind}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p className="w-11/12">{excerpt(props.result.item.desc)}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Search: React.FunctionComponent<SearchProps> = () => {
|
||||
const router = useRouter()
|
||||
const [searchText, setSearchText] = useState('')
|
||||
const [searchResults, setSearchResults] = useState<FuseResult<SearchItem>[]>(
|
||||
[]
|
||||
)
|
||||
const [fuse, setFuse] = React.useState<Fuse<SearchItem> | undefined>(
|
||||
undefined
|
||||
)
|
||||
const fusePromise = async () => {
|
||||
const data = await fetch('/static/fuse-index.json')
|
||||
console.log(data)
|
||||
const searchIndex: SearchIndex = await data.json()
|
||||
console.log(searchIndex)
|
||||
return new Fuse(searchIndex.list, {}, Fuse.parseIndex(searchIndex.index))
|
||||
}
|
||||
React.useEffect(() => {
|
||||
fusePromise().then((fuse) => setFuse(fuse))
|
||||
}, [])
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const handleKeyPress = useCallback(
|
||||
(event: KeyboardEvent) => {
|
||||
if (event.key === 'k' && (event.metaKey || event.ctrlKey) && isOpen) {
|
||||
setIsOpen(false)
|
||||
event.preventDefault()
|
||||
} else if (
|
||||
(event.key == '/' ||
|
||||
(event.key === 'k' && (event.metaKey || event.ctrlKey))) &&
|
||||
!isOpen
|
||||
) {
|
||||
setIsOpen(true)
|
||||
event.preventDefault()
|
||||
}
|
||||
},
|
||||
[isOpen]
|
||||
)
|
||||
useEffect(() => {
|
||||
document.addEventListener('keydown', handleKeyPress)
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyPress)
|
||||
}
|
||||
}, [handleKeyPress])
|
||||
|
||||
if (!fuse) {
|
||||
return (
|
||||
<div className="flex items-center ml-2">
|
||||
<SearchIcon size={32} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const setSearch = (value: string) => {
|
||||
setSearchText(value)
|
||||
const searchResult = fuse.search(value)
|
||||
setSearchResults(searchResult)
|
||||
}
|
||||
const onChange = (value?: FuseResult<SearchItem>) => {
|
||||
if (value) {
|
||||
if (value.item.kind === 'var') {
|
||||
router.push(`/variables#${value.item.name}`, undefined, {
|
||||
scroll: false,
|
||||
})
|
||||
}
|
||||
if (value.item.kind === 'config') {
|
||||
router.push(`/config_settings#${value.item.name}`, undefined, {
|
||||
scroll: false,
|
||||
})
|
||||
}
|
||||
if (value.item.kind === 'lua') {
|
||||
router.push(`/lua#${value.item.name}`, undefined, { scroll: false })
|
||||
}
|
||||
setIsOpen(false)
|
||||
}
|
||||
}
|
||||
|
||||
const closeModal = () => {
|
||||
setIsOpen(false)
|
||||
}
|
||||
|
||||
const openModal = () => {
|
||||
setIsOpen(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center ml-2">
|
||||
<button onClick={openModal} title="Search (/ or ⌘K)">
|
||||
<SearchIcon size={32} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
<Dialog as="div" className="relative z-10" onClose={closeModal}>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
>
|
||||
<div className="fixed inset-0 bg-black bg-opacity-25 backdrop-blur-sm" />
|
||||
</Transition.Child>
|
||||
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
>
|
||||
<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 nullable onChange={onChange}>
|
||||
<div className="flex">
|
||||
<Combobox.Label className="flex items-center ml-2">
|
||||
<SearchIcon size={32} />
|
||||
</Combobox.Label>
|
||||
<Combobox.Input
|
||||
placeholder="Search docs (/ or ⌘K)"
|
||||
className="mx-1 p-2 w-full bg-gray-200 dark:bg-gray-800 outline-none"
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Combobox.Options className="flex flex-col h-full overflow-auto">
|
||||
{searchResults.length === 0 && searchText !== '' ? (
|
||||
<div className="relative cursor-default select-none py-2 px-4 text-gray-500">
|
||||
No results.
|
||||
</div>
|
||||
) : (
|
||||
searchResults.map((r) => (
|
||||
<Combobox.Option key={r.refIndex} value={r}>
|
||||
{({ selected, active }) => (
|
||||
<SearchResult
|
||||
result={r}
|
||||
selected={selected}
|
||||
active={active}
|
||||
/>
|
||||
)}
|
||||
</Combobox.Option>
|
||||
))
|
||||
)}
|
||||
</Combobox.Options>
|
||||
</Combobox>
|
||||
</Dialog.Panel>
|
||||
</div>
|
||||
</div>
|
||||
</Transition.Child>
|
||||
</Dialog>
|
||||
</Transition>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Search
|
||||
81
web/components/ThemeSwitcher.tsx
Normal file
81
web/components/ThemeSwitcher.tsx
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
const sunIcon = (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="25"
|
||||
height="24"
|
||||
fill="none"
|
||||
viewBox="0 0 25 24"
|
||||
className="dark:opacity-50"
|
||||
>
|
||||
<g
|
||||
stroke="#fff"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
clipPath="url(#clip0_192_823)"
|
||||
>
|
||||
<path d="M12.5 17a5 5 0 100-10 5 5 0 000 10zM12.5 1v2M12.5 21v2M4.72 4.22l1.42 1.42M18.86 18.36l1.42 1.42M1.5 12h2M21.5 12h2M4.72 19.78l1.42-1.42M18.86 5.64l1.42-1.42"></path>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_192_823">
|
||||
<path
|
||||
className="fill-current text-white"
|
||||
d="M0 0H24V24H0z"
|
||||
transform="translate(.5)"
|
||||
></path>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
|
||||
const moonIcon = (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="25"
|
||||
height="24"
|
||||
fill="none"
|
||||
viewBox="0 0 21 20"
|
||||
>
|
||||
<path
|
||||
stroke="#fff"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
className="stroke-current text-gray-400 dark:text-white"
|
||||
d="M19.5 10.79A9 9 0 119.71 1a7 7 0 009.79 9.79v0z"
|
||||
></path>
|
||||
</svg>
|
||||
)
|
||||
|
||||
type Props = {
|
||||
setDarkMode: (state: boolean) => void
|
||||
}
|
||||
export default function ThemeSwitcher({ setDarkMode }: Props) {
|
||||
return (
|
||||
<div className="flex bg-gray-200 dark:bg-gray-700 rounded-2xl">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Use Dark Mode"
|
||||
title="Use Dark Mode"
|
||||
onClick={() => {
|
||||
setDarkMode(true)
|
||||
}}
|
||||
className="flex items-center dark:bg-purple-500 rounded-3xl justify-center align-center p-1 w-10 h-full transition"
|
||||
>
|
||||
{moonIcon}
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Use Light Mode"
|
||||
title="Use Light Mode"
|
||||
onClick={() => {
|
||||
setDarkMode(false)
|
||||
}}
|
||||
className="flex items-center bg-purple-500 dark:bg-transparent rounded-3xl justify-center align-center p-1 w-10 h-full transition"
|
||||
>
|
||||
{sunIcon}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
10
web/cypress.config.js
Normal file
10
web/cypress.config.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
scrollBehavior: 'center',
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:3000',
|
||||
supportFile: false,
|
||||
},
|
||||
})
|
||||
7
web/cypress/.eslintrc.json
Normal file
7
web/cypress/.eslintrc.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": ["eslint:recommended", "plugin:cypress/recommended", "prettier"],
|
||||
"plugins": ["cypress"],
|
||||
"settings": {
|
||||
"sort-imports": "error"
|
||||
}
|
||||
}
|
||||
43
web/cypress/e2e/basic.cy.js
Normal file
43
web/cypress/e2e/basic.cy.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
describe('check index renders', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/')
|
||||
})
|
||||
|
||||
it('displays the title text', () => {
|
||||
cy.get('[data-cy="top-link"]').contains(/^Conky$/)
|
||||
})
|
||||
})
|
||||
describe('check config settings', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/config_settings')
|
||||
})
|
||||
|
||||
it('displays the title text', () => {
|
||||
cy.get('[data-cy="top-link"]').contains(/^Conky$/)
|
||||
cy.get('[data-cy="page-heading"]').contains(/^Configuration settings$/)
|
||||
})
|
||||
})
|
||||
describe('check variables', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/variables')
|
||||
})
|
||||
|
||||
it('displays the title text', () => {
|
||||
cy.get('[data-cy="top-link"]').contains(/^Conky$/)
|
||||
cy.get('[data-cy="page-heading"]').contains(/^Variables$/)
|
||||
})
|
||||
it('has anchor links and can focus on them', () => {
|
||||
cy.get('[data-anchor-name="acpiacadapter"]').click()
|
||||
cy.get('[data-anchor-name="acpiacadapter"]').and('be.visible')
|
||||
})
|
||||
})
|
||||
describe('check lua', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/lua')
|
||||
})
|
||||
|
||||
it('displays the title text', () => {
|
||||
cy.get('[data-cy="top-link"]').contains(/^Conky$/)
|
||||
cy.get('[data-cy="page-heading"]').contains(/^Lua API$/)
|
||||
})
|
||||
})
|
||||
20
web/documents/about.mdx
Normal file
20
web/documents/about.mdx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
title: About
|
||||
description: What's Conky all about?
|
||||
indexWeight: -10
|
||||
---
|
||||
|
||||
Conky is a system monitor for X. Conky can display just about anything, either
|
||||
on your root desktop or in its own window. Not only does Conky have many
|
||||
built-in objects, it can also display just about any piece of information by
|
||||
using scripts and other external programs.
|
||||
|
||||
Conky has more than 250 built in objects, including support for a plethora of OS
|
||||
stats (uname, uptime, CPU usage, mem usage, disk usage, `top` like process
|
||||
stats, and network monitoring, just to name a few), built in IMAP and POP3
|
||||
support, built in support for many popular music players (MPD, XMMS2,
|
||||
Audacious), and much much more. Conky can display this info either as text, or
|
||||
using simple progress bars and graph widgets, with different fonts and colours.
|
||||
|
||||
If you'd like to get involved, please visit the project on GitHub at
|
||||
https://github.com/brndnmtthws/conky.
|
||||
41
web/documents/compiling.mdx
Normal file
41
web/documents/compiling.mdx
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
title: Compiling
|
||||
description: How to compile Conky from source
|
||||
indexWeight: 0
|
||||
---
|
||||
|
||||
Using CMake to build Conky is pretty easy, and here is how I do it:
|
||||
|
||||
1. From the top level source dir, create a build working dir, and cd into it
|
||||
|
||||
```shell-session
|
||||
mkdir build
|
||||
cd build
|
||||
```
|
||||
|
||||
2. Run the cmake configuration process
|
||||
|
||||
```shell-session
|
||||
cmake ../ # pass the path to the sources to cmake
|
||||
```
|
||||
|
||||
OR
|
||||
|
||||
```shell-session
|
||||
ccmake ../ # you can also use the fance curses interface, or try cmake-gui
|
||||
```
|
||||
|
||||
3. Compile as usual, and enjoy the out-of-source goodness
|
||||
|
||||
```shell-session
|
||||
make
|
||||
sudo make install # if you want
|
||||
```
|
||||
|
||||
There are a number of build options for Conky, and the best way to discover
|
||||
them is to use the `ccmake` (or `cmake-gui`) CMake tool for browsing them.
|
||||
|
||||
Certain Conky build time features (such as doc generation) require third-party
|
||||
applications, which you should be notified of via CMake. In the case of doc
|
||||
generation, you'll need the docbook2X package (available on most
|
||||
distributions).
|
||||
42
web/documents/contributing.mdx
Normal file
42
web/documents/contributing.mdx
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
title: Contributing
|
||||
description: How to contribute to Conky
|
||||
indexWeight: 0
|
||||
---
|
||||
|
||||
Contributions are welcome from anyone.
|
||||
|
||||
## Pull Request Guidelines
|
||||
|
||||
When submitting PRs, please:
|
||||
|
||||
- Describe the changes, why they were necessary, etc
|
||||
- Describe how the changes affect existing behaviour
|
||||
- Describe how you tested and validated your changes
|
||||
- Include unit tests when appropriate
|
||||
- Include any relevant screenshots/evidence demonstrating that the changes work and have been tested
|
||||
- Any new source files should include a GPLv3 license header
|
||||
- All new code must be GPLv3 licensed
|
||||
- Try to leave the code better than you found it
|
||||
- PRs with failed checks may be ignored or closed; please make sure
|
||||
the build and checks pass if possible (and notify someone when the build
|
||||
system is not working)
|
||||
|
||||
_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.
|
||||
|
||||
## 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
|
||||
|
||||
Conky uses the [Catch2](https://github.com/catchorg/Catch2) unit testing framework. If you are adding new functions or methods, please consider adding unit tests for that code. Additionally, if you'd like to add tests for existing code, that would be a welcome contribution.
|
||||
83
web/documents/docker.mdx
Normal file
83
web/documents/docker.mdx
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
title: Docker
|
||||
description: A guide for running Conky with Docker
|
||||
indexWeight: 0
|
||||
---
|
||||
|
||||
## Getting the image
|
||||
|
||||
Build the image with:
|
||||
|
||||
```shell-session
|
||||
docker build --tag=conky .
|
||||
```
|
||||
|
||||
or if you want the commandline version:
|
||||
|
||||
```shell-session
|
||||
docker build --build-arg X11=no --tag=conkycmd .
|
||||
```
|
||||
|
||||
## Running the container
|
||||
|
||||
After building you can run the graphical version with:
|
||||
|
||||
```shell-session
|
||||
docker run --rm -ti --net=host -e DISPLAY -v ~/.Xauthority:/root/.Xauthority conky
|
||||
```
|
||||
|
||||
The commandline version is easier:
|
||||
|
||||
```shell-session
|
||||
docker run --rm -ti conkycmd
|
||||
```
|
||||
|
||||
If you want to pass some options to conky you can just add them if you mention
|
||||
'conky' twice. Once for the image and once for the command. For example:
|
||||
|
||||
```shell-session
|
||||
docker run --rm -ti --net=host -e DISPLAY -v ~/.Xauthority:/root/.Xauthority conky conky --version
|
||||
```
|
||||
|
||||
will show you the version of conky. Since you don't need X for this you could also do:
|
||||
|
||||
```shell-session
|
||||
docker run --rm -ti conkycmd conky --version
|
||||
```
|
||||
|
||||
If you want to fiddle around a bit with the configuration first you could do:
|
||||
|
||||
```shell-session
|
||||
docker run --rm -ti --net=host -e DISPLAY -v ~/.Xauthority:/root/.Xauthority conky bash
|
||||
```
|
||||
|
||||
_change things is in the configuration_
|
||||
|
||||
```shell-session
|
||||
conky -c configurationfile ; exit
|
||||
```
|
||||
|
||||
See the docker docs to a lot of other ways to (ab)use this container
|
||||
|
||||
## Why?
|
||||
|
||||
Disadvantages of using the docker:
|
||||
|
||||
- You'll have to install docker.
|
||||
This can be done by following the instructions in
|
||||
https://docs.docker.com/install/ to install docker CE. But just using the
|
||||
packagemanager of your distro like you would do with other software will work.
|
||||
- A lot of info will be about the current container instead of the whole system
|
||||
- At the moment our docker image is still in development fase.
|
||||
|
||||
Advantages of using docker:
|
||||
|
||||
- During the installation you won't have to care about which compilers,
|
||||
libraries, ... are installed. Neither should you care about how to use them.
|
||||
- The containerization of conky will make it a lot harder to let problems with
|
||||
conky affect the rest of the system.
|
||||
- Your Conky will run in exactly the same environment as everyone else's, so
|
||||
if it works for someone it will work for everyone. No matter which distro you
|
||||
are using or how you configured that distro. (The conky configuration itself
|
||||
will matter and also the version of conky)
|
||||
- Problems will be easier to recreate by developers causing faster debugging.
|
||||
37
web/documents/syntax-highlighting.mdx
Normal file
37
web/documents/syntax-highlighting.mdx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title: Syntax Highlighting
|
||||
description: Enabling conkyrc syntax highlighting
|
||||
indexWeight: 0
|
||||
---
|
||||
|
||||
## Gedit
|
||||
|
||||
Note: this highlights based on syntax and does **NOT** attempt to validate arguments or keywords. The syntax highlighting is unlikely to be 100% accurate and is open to improvement.
|
||||
|
||||
The syntax highlighting will automatically be applied to all files with `conky` in their name. eg. `my_config.conky` (unfortunately it also triggers for the `conky.lang` file itself, you should set it to XML manually)
|
||||
|
||||
- [`gtksourceview` Syntax Highlight documentation][1]
|
||||
- [Regex Tutorial](http://www.rexegg.com/)
|
||||
- [Regex Testing](https://regex101.com/)
|
||||
|
||||
Developers: The main context (`id="conkyrc"`) is where gedit begins. This main context then references other sub-contexts. Each context can apply styles to itself, sub-strings from its regexs, or its contents (in the case of `<start><end>` "container" contexts). If you are ever confused by something, try searching for XML attributes in the [`gtksourceview` docs][1]. If you find a particularly complex regex, try using the Regex Tester linked above, and bear in mind that `gtksourceview` adds some extra regex syntax (i.e. `\%[ ... ]` and `\%{ ... }`).
|
||||
|
||||
---
|
||||
|
||||
for medit v1.1.1:
|
||||
` /usr/share/medit/language-specs/conky.lang`
|
||||
|
||||
for medit - older versions:
|
||||
`/usr/share/medit-1/language-specs/conky.lang`
|
||||
|
||||
for gedit v2.x
|
||||
` /usr/share/gtksourceview-2.0/language-specs/conky.lang`
|
||||
or (for single user)
|
||||
` ~/.local/share/gtksourceview-2.0/language-specs/conky.lang`
|
||||
|
||||
for gedit v3.x
|
||||
` /usr/share/gtksourceview-3.0/language-specs/conky.lang`
|
||||
or (for single user)
|
||||
` ~/.local/share/gtksourceview-3.0/language-specs/conky.lang`
|
||||
|
||||
[1]: https://developer.gnome.org/gtksourceview/stable/lang-reference.html
|
||||
13
web/global.d.ts
vendored
Normal file
13
web/global.d.ts
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
declare module 'next/config' {
|
||||
type ConfigTypes = () => {
|
||||
publicRuntimeConfig: {
|
||||
modifiedDate: string
|
||||
modifiedYear: string
|
||||
gitHash: string?
|
||||
}
|
||||
}
|
||||
|
||||
declare const getConfig: ConfigTypes
|
||||
|
||||
export default getConfig
|
||||
}
|
||||
28
web/netlify.toml
Normal file
28
web/netlify.toml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
[build]
|
||||
command = "npm run build"
|
||||
publish = ".next"
|
||||
|
||||
# Include the doc dir in the build ignore command
|
||||
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF . ../doc/"
|
||||
|
||||
[build.environment]
|
||||
# cache Cypress binary in local "node_modules" folder
|
||||
# so Netlify caches it
|
||||
CYPRESS_CACHE_FOLDER = "./node_modules/CypressBinary"
|
||||
# set TERM variable for terminal output
|
||||
TERM = "xterm"
|
||||
|
||||
[[plugins]]
|
||||
package = "@netlify/plugin-nextjs"
|
||||
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-cypress"
|
||||
|
||||
# do not test the deployed URL
|
||||
[plugins.inputs]
|
||||
enable = false
|
||||
# test the local site
|
||||
[plugins.inputs.preBuild]
|
||||
enable = true
|
||||
start = 'npx netlify dev'
|
||||
wait-on = 'http://localhost:8888'
|
||||
5
web/next-env.d.ts
vendored
Normal file
5
web/next-env.d.ts
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
28
web/next.config.mjs
Normal file
28
web/next.config.mjs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// @ts-check
|
||||
import { spawn } from 'child_process'
|
||||
|
||||
const config = async (_phase, { _defaultConfig }) => {
|
||||
const gitHash = await new Promise((resolve) => {
|
||||
const git = spawn('git', ['rev-parse', '--short', 'HEAD'])
|
||||
git.stdout.on('data', (data) => {
|
||||
resolve(data.toString().trim())
|
||||
})
|
||||
git.on('error', () => {
|
||||
resolve(undefined)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* @type {import('next').NextConfig}
|
||||
*/
|
||||
const nextConfig = {
|
||||
publicRuntimeConfig: {
|
||||
modifiedDate: new Date().toISOString(),
|
||||
modifiedYear: new Date().getFullYear(),
|
||||
gitHash,
|
||||
},
|
||||
}
|
||||
return nextConfig
|
||||
}
|
||||
|
||||
export default config
|
||||
30990
web/package-lock.json
generated
Normal file
30990
web/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
73
web/package.json
Normal file
73
web/package.json
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"name": "conky-website",
|
||||
"description": "Conky website",
|
||||
"author": "Conky developers",
|
||||
"license": "GPL-3.0-only",
|
||||
"contributors": [
|
||||
"Brenden Matthews"
|
||||
],
|
||||
"homepage": "https://github.com/brndnmtthws/conky",
|
||||
"bugs": {
|
||||
"url": "https://github.com/brndnmtthws/conky/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "npm run write-search-index && next dev",
|
||||
"dev:watch": "npm run write-search-index && next-remote-watch ./documents",
|
||||
"build": "npm run write-search-index && next build",
|
||||
"start": "npm run write-search-index && next start",
|
||||
"export": "npm run write-search-index && next build && next export",
|
||||
"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\"",
|
||||
"write-search-index": "tsx ./scripts/write-search-index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource-variable/fira-code": "^5.0.17",
|
||||
"@fontsource-variable/inter": "^5.0.17",
|
||||
"@fontsource-variable/newsreader": "^5.0.18",
|
||||
"@headlessui/react": "^1.7.18",
|
||||
"@netlify/plugin-nextjs": "^5.0.0",
|
||||
"@tailwindcss/typography": "^0.5.12",
|
||||
"classnames": "^2.5.1",
|
||||
"colord": "^2.9.3",
|
||||
"follow-redirects": "^1.15.6",
|
||||
"fuse.js": "^7.0.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"inter-ui": "^4.0.2",
|
||||
"next": "^14.1.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-feather": "^2.0.10",
|
||||
"rehype-parse": "^9.0.0",
|
||||
"rehype-react": "^8.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/eslint": "^8.56.8",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^20.12.7",
|
||||
"@types/react": "^18.2.76",
|
||||
"@types/react-dom": "^18.2.25",
|
||||
"@typescript-eslint/eslint-plugin": "^7.6.0",
|
||||
"@typescript-eslint/parser": "^7.6.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"cypress": "^13.7.2",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-next": "^14.1.4",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-cypress": "^2.15.1",
|
||||
"eslint-plugin-mdx": "^3.1.5",
|
||||
"js-yaml": "^4.1.0",
|
||||
"netlify-cli": "^17.22.1",
|
||||
"netlify-plugin-cypress": "^2.2.1",
|
||||
"next-remote-watch": "2.0.0",
|
||||
"postcss": "^8.4.38",
|
||||
"rehype-stringify": "^10.0.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-rehype": "^11.1.0",
|
||||
"start-server-and-test": "^2.0.3",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tsx": "^4.7.2",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
22
web/pages/404.tsx
Normal file
22
web/pages/404.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import Layout from '../components/Layout'
|
||||
import SEO from '../components/SEO'
|
||||
import Doggy from '../components/Doggy'
|
||||
|
||||
export default function FourOhFour() {
|
||||
return (
|
||||
<Layout>
|
||||
<SEO title="Conky" description="Conky documentation" />
|
||||
<main className="w-full">
|
||||
<div className="flex flex-col items-center">
|
||||
<h1 className="text-4xl py-8 px-2 lg:px-4 font-extrabold text-center">404: Not found 😢</h1>
|
||||
<Doggy />
|
||||
<h2 className="text-3xl py-4 font-serif mb-8">Here’s a doggy 😀</h2>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export function getStaticProps() {
|
||||
return { props: {} }
|
||||
}
|
||||
11
web/pages/_app.tsx
Normal file
11
web/pages/_app.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import '@fontsource-variable/fira-code'
|
||||
import '@fontsource-variable/inter'
|
||||
import '@fontsource-variable/newsreader'
|
||||
import '../styles/globals.css'
|
||||
import { AppProps } from 'next/app'
|
||||
|
||||
function App({ Component, pageProps }: AppProps) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
|
||||
export default App
|
||||
20
web/pages/_document.tsx
Normal file
20
web/pages/_document.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import React from 'react'
|
||||
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
class MyDocument extends Document {
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en" className="theme-compiled scroll-smooth">
|
||||
<Head />
|
||||
<body
|
||||
className={`antialiased bg-white dark:bg-gray-900 dark:text-white leading-base`}
|
||||
>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyDocument
|
||||
37
web/pages/config_settings.tsx
Normal file
37
web/pages/config_settings.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import Layout from '../components/Layout'
|
||||
import SEO from '../components/SEO'
|
||||
import {
|
||||
getConfigSettings,
|
||||
Documentation,
|
||||
filterDesc,
|
||||
} from '../utils/doc-utils'
|
||||
import Docs from '../components/Docs'
|
||||
|
||||
export interface ConfigSettingsProps {
|
||||
config_settings: Documentation
|
||||
}
|
||||
|
||||
export default function ConfigSettings(props: ConfigSettingsProps) {
|
||||
return (
|
||||
<Layout>
|
||||
<SEO
|
||||
title="Conky – Config settings"
|
||||
description="Conky configuration settings"
|
||||
/>
|
||||
<main className="w-full pt-4">
|
||||
<div>
|
||||
<h1 className="text-2xl px-2 lg:px-4" data-cy="page-heading">
|
||||
Configuration settings
|
||||
</h1>
|
||||
</div>
|
||||
<Docs docs={props.config_settings} braces={false} assign={true} />
|
||||
</main>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
const config_settings = filterDesc(getConfigSettings())
|
||||
|
||||
return { props: { config_settings } }
|
||||
}
|
||||
103
web/pages/documents/[slug].tsx
Normal file
103
web/pages/documents/[slug].tsx
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import {
|
||||
getNextDocumentBySlug,
|
||||
getDocumentBySlug,
|
||||
getPreviousDocumentBySlug,
|
||||
documentFilePaths,
|
||||
} from '../../utils/mdx-utils'
|
||||
|
||||
import Layout from '../../components/Layout'
|
||||
import SEO from '../../components/SEO'
|
||||
import { GetStaticProps } from 'next'
|
||||
import Link from 'next/link'
|
||||
import { unified } from 'unified'
|
||||
import rehypeReact from 'rehype-react'
|
||||
import * as prod from 'react/jsx-runtime'
|
||||
import rehypeParse from 'rehype-parse'
|
||||
import { createElement, Fragment, useEffect, useState } from 'react'
|
||||
|
||||
const production = { Fragment: prod.Fragment, jsx: prod.jsx, jsxs: prod.jsxs }
|
||||
|
||||
interface FrontMatter {
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
interface DocumentPageProps {
|
||||
source: string
|
||||
frontMatter: FrontMatter
|
||||
}
|
||||
|
||||
export default function DocumentPage({
|
||||
source,
|
||||
frontMatter,
|
||||
}: DocumentPageProps) {
|
||||
const [children, setChildren] = useState(createElement(Fragment))
|
||||
|
||||
useEffect(
|
||||
function () {
|
||||
;(async function () {
|
||||
const file = await unified()
|
||||
.use(rehypeParse, { fragment: true })
|
||||
// @ts-expect-error: the react types are missing.
|
||||
.use(rehypeReact, { ...production, components: { a: Link } })
|
||||
.process(source)
|
||||
|
||||
setChildren(file.result)
|
||||
})()
|
||||
},
|
||||
[source]
|
||||
)
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<SEO
|
||||
title={`${frontMatter.title}`}
|
||||
description={frontMatter.description}
|
||||
/>
|
||||
<article className="p-2 pt-4 lg:p-4 w-full">
|
||||
<header>
|
||||
<h1 className="text-3xl md:text-5xl dark:text-white mb-12">
|
||||
{frontMatter.title}
|
||||
</h1>
|
||||
{frontMatter.description && (
|
||||
<p className="text-xl mb-4">{frontMatter.description}</p>
|
||||
)}
|
||||
</header>
|
||||
<main>
|
||||
<article className="prose dark:prose-invert">{children}</article>
|
||||
</main>
|
||||
</article>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export const getStaticProps: GetStaticProps = async ({ params }) => {
|
||||
if (params) {
|
||||
const { source, data } = await getDocumentBySlug(params.slug as string)
|
||||
const prevDocument = getPreviousDocumentBySlug(params.slug as string)
|
||||
const nextDocument = getNextDocumentBySlug(params.slug as string)
|
||||
|
||||
return {
|
||||
props: {
|
||||
source,
|
||||
frontMatter: data,
|
||||
prevDocument,
|
||||
nextDocument,
|
||||
},
|
||||
}
|
||||
}
|
||||
return { props: {} }
|
||||
}
|
||||
|
||||
export const getStaticPaths = async () => {
|
||||
const paths = documentFilePaths
|
||||
// Remove file extensions for page paths
|
||||
.map((path) => path.replace(/\.mdx?$/, ''))
|
||||
// Map the path into the static paths object required by Next.js
|
||||
.map((slug) => ({ params: { slug } }))
|
||||
|
||||
return {
|
||||
paths,
|
||||
fallback: false,
|
||||
}
|
||||
}
|
||||
90
web/pages/index.tsx
Normal file
90
web/pages/index.tsx
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import Link from 'next/link'
|
||||
import { getDocuments, Document } from '../utils/mdx-utils'
|
||||
import Layout from '../components/Layout'
|
||||
import ArrowIcon from '../components/ArrowIcon'
|
||||
import SEO from '../components/SEO'
|
||||
|
||||
const pages = [
|
||||
{
|
||||
slug: '/variables',
|
||||
title: 'Variables',
|
||||
desc: 'Variables let you define the various objects displayed in Conky including text, bars, graphs, and more.',
|
||||
},
|
||||
{
|
||||
slug: '/config_settings',
|
||||
title: 'Configuration settings',
|
||||
desc: 'Global configuration pramaters for Conky allow you to customize various behaviours.',
|
||||
},
|
||||
{
|
||||
slug: '/lua',
|
||||
title: 'Lua API',
|
||||
desc: 'Program wild things into your Conky with the Lua API',
|
||||
},
|
||||
]
|
||||
|
||||
interface IndexItemProps {
|
||||
href: string
|
||||
as?: string
|
||||
title: string
|
||||
desc?: string
|
||||
}
|
||||
|
||||
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}
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
interface IndexProps {
|
||||
documents: Document[]
|
||||
}
|
||||
|
||||
export default function Index({ documents }: IndexProps) {
|
||||
return (
|
||||
<Layout>
|
||||
<SEO title="Conky" description="Conky documentation" />
|
||||
<main className="w-full">
|
||||
<div className="w-full">
|
||||
{pages.map((p) => (
|
||||
<IndexItem
|
||||
key={p.slug}
|
||||
href={p.slug}
|
||||
title={p.title}
|
||||
desc={p.desc}
|
||||
/>
|
||||
))}
|
||||
{documents.map((document) => (
|
||||
<IndexItem
|
||||
key={document.filePath}
|
||||
as={`/documents/${document.filePath.replace(/\.mdx?$/, '')}`}
|
||||
href={`/documents/[slug]`}
|
||||
title={document.data.title ?? 'Untitled'}
|
||||
desc={document.data.description}
|
||||
/>
|
||||
))}
|
||||
<IndexItem
|
||||
href="https://github.com/brndnmtthws/conky/wiki"
|
||||
title="Wiki"
|
||||
desc="The Wiki (hosted on GitHub) contains a number of user configs, Lua scripts, FAQs and more."
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export function getStaticProps() {
|
||||
const documents = getDocuments()
|
||||
|
||||
return { props: { documents } }
|
||||
}
|
||||
30
web/pages/lua.tsx
Normal file
30
web/pages/lua.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import Layout from '../components/Layout'
|
||||
import SEO from '../components/SEO'
|
||||
import { getLua, Documentation, filterDesc } from '../utils/doc-utils'
|
||||
import Docs from '../components/Docs'
|
||||
|
||||
export interface LuaProps {
|
||||
lua: Documentation
|
||||
}
|
||||
|
||||
export default function Lua(props: LuaProps) {
|
||||
return (
|
||||
<Layout>
|
||||
<SEO title="Conky – Lua API" description="Conky Lua API documentation" />
|
||||
<main className="w-full pt-4">
|
||||
<div>
|
||||
<h1 className="text-2xl px-2 lg:px-4" data-cy="page-heading">
|
||||
Lua API
|
||||
</h1>
|
||||
</div>
|
||||
<Docs docs={props.lua} braces={false} assign={false} />
|
||||
</main>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
const lua = filterDesc(getLua())
|
||||
|
||||
return { props: { lua } }
|
||||
}
|
||||
31
web/pages/variables.tsx
Normal file
31
web/pages/variables.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import Layout from '../components/Layout'
|
||||
import SEO from '../components/SEO'
|
||||
import { getVariables, Documentation, filterDesc } from '../utils/doc-utils'
|
||||
import Docs from '../components/Docs'
|
||||
|
||||
export interface VariablesProps {
|
||||
variables: Documentation
|
||||
}
|
||||
|
||||
export default function Variables(props: VariablesProps) {
|
||||
return (
|
||||
<Layout>
|
||||
<SEO
|
||||
title="Conky – Variables"
|
||||
description="Conky object variables documentation"
|
||||
/>
|
||||
<main className="w-full pt-4">
|
||||
<h1 className="text-2xl px-2 lg:px-4" data-cy="page-heading">
|
||||
Variables
|
||||
</h1>
|
||||
<Docs docs={props.variables} braces={true} assign={false} />
|
||||
</main>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
const variables = filterDesc(getVariables())
|
||||
|
||||
return { props: { variables } }
|
||||
}
|
||||
8
web/postcss.config.js
Normal file
8
web/postcss.config.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// If you want to use other PostCSS plugins, see the following:
|
||||
// https://tailwindcss.com/docs/using-with-preprocessors
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
7
web/scripts/write-search-index.ts
Normal file
7
web/scripts/write-search-index.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { writeSearchIndex } from '../utils/search-serde'
|
||||
|
||||
async function main() {
|
||||
await writeSearchIndex()
|
||||
}
|
||||
|
||||
main()
|
||||
10
web/styles/globals.css
Normal file
10
web/styles/globals.css
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind variants;
|
||||
|
||||
code[class*='language-'],
|
||||
pre[class*='language-'] {
|
||||
font-family: 'Fira Code Variable', 'ui-monospace', 'SFMono-Regular', 'Menlo',
|
||||
'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', 'monospace';
|
||||
}
|
||||
9
web/tailwind.config.js
Normal file
9
web/tailwind.config.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
module.exports = {
|
||||
mode: 'jit',
|
||||
content: [
|
||||
'./pages/**/*.{js,ts,jsx,tsx}',
|
||||
'./components/**/*.{js,ts,jsx,tsx}',
|
||||
],
|
||||
darkMode: 'class', // or 'media' or 'class'
|
||||
presets: [require('./utils/tailwind-preset')],
|
||||
}
|
||||
20
web/tsconfig.json
Normal file
20
web/tsconfig.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": ["next-env.d.ts", "global.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
73
web/utils/doc-utils.ts
Normal file
73
web/utils/doc-utils.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import yaml from 'js-yaml'
|
||||
import { unified } from 'unified'
|
||||
import remarkParse from 'remark-parse'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import remarkRehype from 'remark-rehype'
|
||||
import rehypeStringify from 'rehype-stringify'
|
||||
|
||||
const DOC_PATH = path.join(process.cwd(), '..', 'doc')
|
||||
|
||||
export interface Documentation {
|
||||
desc: string
|
||||
desc_md: string
|
||||
values: DocItem[]
|
||||
}
|
||||
export interface DocItem {
|
||||
name: string
|
||||
desc: string
|
||||
desc_md: string
|
||||
default: string | undefined
|
||||
args: string[]
|
||||
}
|
||||
|
||||
function getDocumentation(source: string): Documentation {
|
||||
const configSettingsFile = fs.readFileSync(
|
||||
path.join(DOC_PATH, source),
|
||||
'utf-8'
|
||||
)
|
||||
const parsed = yaml.load(configSettingsFile.toString()) as Documentation
|
||||
const docs = {
|
||||
...parsed,
|
||||
desc_md: processMarkdown(parsed.desc),
|
||||
values: parsed.values.map((c) => ({
|
||||
...c,
|
||||
desc_md: processMarkdown(c.desc),
|
||||
})),
|
||||
}
|
||||
|
||||
return docs
|
||||
}
|
||||
|
||||
export function filterDesc(docs: Documentation): Documentation {
|
||||
return {
|
||||
...docs,
|
||||
desc: '',
|
||||
values: docs.values.map((v) => ({
|
||||
...v,
|
||||
desc: '',
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
export function getConfigSettings(): Documentation {
|
||||
return getDocumentation('config_settings.yaml')
|
||||
}
|
||||
|
||||
export function getVariables(): Documentation {
|
||||
return getDocumentation('variables.yaml')
|
||||
}
|
||||
export function getLua(): Documentation {
|
||||
return getDocumentation('lua.yaml')
|
||||
}
|
||||
|
||||
function processMarkdown(input: string): string {
|
||||
return unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkGfm)
|
||||
.use(remarkRehype, {allowDangerousHtml: true})
|
||||
.use(rehypeStringify, {allowDangerousHtml: true})
|
||||
.processSync(input)
|
||||
.toString()
|
||||
}
|
||||
113
web/utils/mdx-utils.ts
Normal file
113
web/utils/mdx-utils.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import matter from 'gray-matter'
|
||||
import { unified } from 'unified'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import remarkParse from 'remark-parse'
|
||||
import remarkRehype from 'remark-rehype'
|
||||
import rehypeStringify from 'rehype-stringify'
|
||||
|
||||
// DOCUMENTS_PATH is useful when you want to get the path to a specific file
|
||||
export const DOCUMENTS_PATH = path.join(process.cwd(), 'documents')
|
||||
|
||||
// documentFilePaths is the list of all mdx files inside the DOCUMENTS_PATH directory
|
||||
export const documentFilePaths = fs
|
||||
.readdirSync(DOCUMENTS_PATH)
|
||||
// Only include md(x) files
|
||||
.filter((path) => /\.mdx?$/.test(path))
|
||||
|
||||
export interface DocumentData {
|
||||
title?: string
|
||||
description?: string
|
||||
indexWeight?: number
|
||||
}
|
||||
|
||||
export interface Document {
|
||||
content: string
|
||||
data: DocumentData
|
||||
filePath: string
|
||||
}
|
||||
|
||||
export const getDocuments = (): Document[] => {
|
||||
const documents = documentFilePaths.map((filePath) => {
|
||||
const source = fs.readFileSync(path.join(DOCUMENTS_PATH, filePath), 'utf-8')
|
||||
const { content, data } = matter(source)
|
||||
|
||||
return {
|
||||
content,
|
||||
data,
|
||||
filePath,
|
||||
}
|
||||
})
|
||||
|
||||
documents.sort((a, b) => {
|
||||
if (a.data.indexWeight > b.data.indexWeight) {
|
||||
return 1
|
||||
}
|
||||
if (a.data.indexWeight < b.data.indexWeight) {
|
||||
return -1
|
||||
}
|
||||
return a.data.title.localeCompare(b.data.title)
|
||||
})
|
||||
|
||||
return documents
|
||||
}
|
||||
|
||||
export const getDocumentBySlug = async (slug: string) => {
|
||||
const documentFilePath = path.join(DOCUMENTS_PATH, `${slug}.mdx`)
|
||||
const source = fs.readFileSync(documentFilePath, 'utf-8')
|
||||
|
||||
const { content, data } = matter(source)
|
||||
|
||||
const result = await unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkGfm)
|
||||
.use(remarkRehype, {allowDangerousHtml: true})
|
||||
// .use(rehypePrism)
|
||||
.use(rehypeStringify, {allowDangerousHtml: true})
|
||||
.process(content)
|
||||
|
||||
return { source: result.value, data, documentFilePath }
|
||||
}
|
||||
|
||||
export const getNextDocumentBySlug = (slug: string) => {
|
||||
const documents = getDocuments()
|
||||
const currentFileName = `${slug}.mdx`
|
||||
const currentDocument = documents.find(
|
||||
(document) => document.filePath === currentFileName
|
||||
)
|
||||
if (!currentDocument) return null
|
||||
const currentDocumentIndex = documents.indexOf(currentDocument)
|
||||
|
||||
const document = documents[currentDocumentIndex - 1]
|
||||
// no prev document found
|
||||
if (!document) return null
|
||||
|
||||
const nextDocumentSlug = document?.filePath.replace(/\.mdx?$/, '')
|
||||
|
||||
return {
|
||||
title: document.data.title,
|
||||
slug: nextDocumentSlug,
|
||||
}
|
||||
}
|
||||
|
||||
export const getPreviousDocumentBySlug = (slug: string) => {
|
||||
const documents = getDocuments()
|
||||
const currentFileName = `${slug}.mdx`
|
||||
const currentDocument = documents.find(
|
||||
(document) => document.filePath === currentFileName
|
||||
)
|
||||
if (!currentDocument) return null
|
||||
const currentDocumentIndex = documents.indexOf(currentDocument)
|
||||
|
||||
const document = documents[currentDocumentIndex + 1]
|
||||
// no prev document found
|
||||
if (!document) return null
|
||||
|
||||
const previousDocumentSlug = document?.filePath.replace(/\.mdx?$/, '')
|
||||
|
||||
return {
|
||||
title: document.data.title,
|
||||
slug: previousDocumentSlug,
|
||||
}
|
||||
}
|
||||
9
web/utils/search-serde.ts
Normal file
9
web/utils/search-serde.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import * as fs from 'fs/promises'
|
||||
import { createSearchIndex } from './search'
|
||||
|
||||
export async function writeSearchIndex() {
|
||||
await fs.mkdir('public').catch(() => {})
|
||||
await fs.mkdir('public/static').catch(() => {})
|
||||
const index = createSearchIndex()
|
||||
await fs.writeFile('public/static/fuse-index.json', JSON.stringify(index))
|
||||
}
|
||||
40
web/utils/search.ts
Normal file
40
web/utils/search.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import Fuse, { FuseIndexRecords } from 'fuse.js'
|
||||
import { getConfigSettings, getLua, getVariables } from './doc-utils'
|
||||
|
||||
export interface SearchItem {
|
||||
kind: string
|
||||
name: string
|
||||
desc: string
|
||||
}
|
||||
|
||||
export interface SearchIndex {
|
||||
index: {
|
||||
keys: readonly string[]
|
||||
records: FuseIndexRecords
|
||||
}
|
||||
list: SearchItem[]
|
||||
}
|
||||
|
||||
export function createSearchIndex(): SearchIndex {
|
||||
const cs: SearchItem[] = getConfigSettings().values.map((v) => ({
|
||||
kind: 'config',
|
||||
name: v.name,
|
||||
desc: v.desc.substring(0, 121),
|
||||
}))
|
||||
const vars: SearchItem[] = getVariables().values.map((v) => ({
|
||||
kind: 'var',
|
||||
name: v.name,
|
||||
desc: v.desc.substring(0, 121),
|
||||
}))
|
||||
const lua: SearchItem[] = getLua().values.map((v) => ({
|
||||
kind: 'lua',
|
||||
name: v.name,
|
||||
desc: v.desc.substring(0, 121),
|
||||
}))
|
||||
const list: SearchItem[] = [...cs, ...vars, ...lua]
|
||||
|
||||
return {
|
||||
list,
|
||||
index: Fuse.createIndex<SearchItem>(['name', 'desc'], list).toJSON(),
|
||||
}
|
||||
}
|
||||
79
web/utils/tailwind-preset.js
Normal file
79
web/utils/tailwind-preset.js
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import plugin = require('tailwindcss/plugin')
|
||||
import pluginTypography = require('@tailwindcss/typography')
|
||||
|
||||
const hoveredSiblingPlugin = plugin(function ({ addVariant, e }) {
|
||||
addVariant('hovered-sibling', ({ container }) => {
|
||||
container.walkRules((rule) => {
|
||||
rule.selector = `:hover + .hovered-sibling\\:${rule.selector.slice(1)}`
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
theme: {
|
||||
fontFamily: {
|
||||
sans: [
|
||||
'Inter Variable',
|
||||
'ui-sans-serif',
|
||||
'system-ui',
|
||||
'-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',
|
||||
],
|
||||
serif: [
|
||||
'Newsreader Variable',
|
||||
'ui-serif',
|
||||
'Georgia',
|
||||
'Cambria',
|
||||
'Times New Roman',
|
||||
'Times',
|
||||
'serif',
|
||||
],
|
||||
mono: [
|
||||
'Fira Code Variable',
|
||||
'ui-monospace',
|
||||
'SFMono-Regular',
|
||||
'Menlo',
|
||||
'Monaco',
|
||||
'Consolas',
|
||||
'Liberation Mono',
|
||||
'Courier New',
|
||||
'monospace',
|
||||
],
|
||||
},
|
||||
extend: {
|
||||
typography: (theme) => ({
|
||||
DEFAULT: {
|
||||
css: {
|
||||
code: {
|
||||
'&::before': {
|
||||
content: '"" !important',
|
||||
},
|
||||
'&::after': {
|
||||
content: '"" !important',
|
||||
},
|
||||
},
|
||||
fontFamily: theme('fontFamily.sans').join(', '),
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
extend: {
|
||||
borderRadius: ['first', 'last'],
|
||||
borderWidth: ['last', 'hovered-sibling'],
|
||||
typography: ['dark'],
|
||||
},
|
||||
},
|
||||
plugins: [hoveredSiblingPlugin, pluginTypography],
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue