浏览代码

Merge branch 'refactor/nx-goober' of code.modal.sh:TheoryOfNekomata/viewfinder

master
父节点
当前提交
6b2fbf3a93
共有 100 个文件被更改,包括 5377 次插入6520 次删除
  1. +104
    -2
      .gitignore
  2. +0
    -6
      .npmignore
  3. +4
    -18
      LICENSE
  4. +7
    -47
      README.md
  5. +0
    -1
      example/.browserslistrc
  6. +0
    -3
      example/.gitignore
  7. +0
    -39
      example/components/Brand/index.tsx
  8. +0
    -11
      example/index.html
  9. +0
    -44
      example/index.tsx
  10. +0
    -14
      example/layouts/basic-narrow/index.html
  11. +0
    -19
      example/layouts/basic-narrow/index.tsx
  12. +0
    -14
      example/layouts/basic/index.html
  13. +0
    -14
      example/layouts/left-sidebar-2/index.html
  14. +0
    -14
      example/layouts/left-sidebar-with-menu/index.html
  15. +0
    -14
      example/layouts/left-sidebar/index.html
  16. +0
    -14
      example/layouts/right-sidebar-static/index.html
  17. +0
    -26
      example/package.json
  18. +0
    -19
      example/tsconfig.json
  19. +0
    -5527
      example/yarn.lock
  20. +0
    -85
      package.json
  21. +67
    -0
      packages/base/package.json
  22. +3
    -0
      packages/base/pridepack.json
  23. +12
    -0
      packages/base/src/common.ts
  24. +3
    -0
      packages/base/src/index.ts
  25. +34
    -0
      packages/base/src/layouts/Basic.ts
  26. +90
    -0
      packages/base/src/layouts/LeftSidebar.ts
  27. +370
    -0
      packages/base/src/layouts/LeftSidebarWithMenu.ts
  28. +83
    -0
      packages/base/src/layouts/RightSidebarStatic.ts
  29. +4
    -0
      packages/base/src/layouts/index.ts
  30. +125
    -0
      packages/base/src/widgets/TopBar.ts
  31. +1
    -0
      packages/base/src/widgets/index.ts
  32. +8
    -0
      packages/base/test/index.test.ts
  33. +21
    -0
      packages/base/tsconfig.json
  34. +3378
    -0
      packages/base/yarn.lock
  35. +3
    -0
      packages/kitchen-sink/react-next/.eslintrc.json
  36. +36
    -0
      packages/kitchen-sink/react-next/.gitignore
  37. +34
    -0
      packages/kitchen-sink/react-next/README.md
  38. +7
    -0
      packages/kitchen-sink/react-next/next.config.js
  39. +26
    -0
      packages/kitchen-sink/react-next/package.json
  40. 二进制
      packages/kitchen-sink/react-next/public/favicon.ico
  41. +0
    -0
      packages/kitchen-sink/react-next/public/static/japanese-calligraphy/20101122_Calligraphy_Hirano_Demo.jpg
  42. +0
    -0
      packages/kitchen-sink/react-next/public/static/japanese-calligraphy/freddie-marriage-gL-7_NtZpYI-unsplash.jpg
  43. +0
    -0
      packages/kitchen-sink/react-next/public/static/japanese-calligraphy/japanese_calligraphy_at_meiji_shrine_tokyo.jpg
  44. +0
    -0
      packages/kitchen-sink/react-next/public/static/japanese-calligraphy/marco-zuppone-zHwWnUDMizo-unsplash.jpg
  45. +0
    -0
      packages/kitchen-sink/react-next/public/static/japanese-calligraphy/niketh-vellanki-vJqSAasmCEY-unsplash.jpg
  46. +0
    -0
      packages/kitchen-sink/react-next/public/static/japanese-calligraphy/what-is-japanese-calligraphy-used-for-1-1.jpg
  47. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/bechstein-moor-grand-00.jpg
  48. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/bechstein-moor-grand-01.jpg
  49. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/boesendorfer-moor-grand-00.jpg
  50. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/boesendorfer-moor-grand-01.jpg
  51. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/boesendorfer-moor-grand-02.jpg
  52. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/chris-maene-cm228-parlor-grand-00.jpg
  53. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/chris-maene-cm250-chamber-concert-grand-00.jpg
  54. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/chris-maene-cm284-concert-grand-00.jpg
  55. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/grotrian-duo-double-grand.jpg
  56. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/grotrian-steinweg-double-grand-00.jpg
  57. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/korg-kronos-88-00.jpg
  58. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/korg-kronos-88-01.jpg
  59. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/kurzweil-forte-00.webp
  60. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/nehlsen-omega-double-grand-00.jpg
  61. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/pleyel-double-grand-00.jpg
  62. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/pleyel-double-grand-01.jpg
  63. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/pleyel-double-grand-02.jpg
  64. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/pleyel-moor-grand-00.jpg
  65. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/pleyel-moor-grand-01.jpg
  66. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/pleyel-moor-grand-02.jpg
  67. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/pleyel-moor-upright-00.jpg
  68. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/roland-fantom-8-00.jpg
  69. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/roland-fantom-8-01.jpg
  70. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/roland-fantom-8-02.jpg
  71. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/steinway-moor-grand-00.jpg
  72. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/stuart-and-sons-beleura-concert-grand-00.jpg
  73. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/stuart-and-sons-beleura-concert-grand-01.jpg
  74. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/stuart-and-sons-beleura-studio-grand-00.jpg
  75. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/yamaha-cp88-00.jpg
  76. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/yamaha-cp88-01.jpg
  77. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/yamaha-cp88-02.jpg
  78. +0
    -0
      packages/kitchen-sink/react-next/public/static/piano/yamaha-montage-8-00.webp
  79. +0
    -0
      packages/kitchen-sink/react-next/public/static/ramen/Butter_Corn_Ramen.jpg
  80. +0
    -0
      packages/kitchen-sink/react-next/public/static/ramen/Tokyoramen.jpg
  81. +0
    -0
      packages/kitchen-sink/react-next/public/static/ramen/karei.png
  82. +0
    -0
      packages/kitchen-sink/react-next/public/static/ramen/miso.png
  83. +0
    -0
      packages/kitchen-sink/react-next/public/static/ramen/sapporo.jpg
  84. +0
    -0
      packages/kitchen-sink/react-next/public/static/ramen/shio.png
  85. +0
    -0
      packages/kitchen-sink/react-next/public/static/ramen/shoyu.jpg
  86. +4
    -0
      packages/kitchen-sink/react-next/public/vercel.svg
  87. +25
    -0
      packages/kitchen-sink/react-next/src/components/Brand/Brand.module.css
  88. +19
    -0
      packages/kitchen-sink/react-next/src/components/Brand/index.tsx
  89. +37
    -0
      packages/kitchen-sink/react-next/src/components/DummyLinks.tsx
  90. +18
    -0
      packages/kitchen-sink/react-next/src/components/Image/index.tsx
  91. +10
    -0
      packages/kitchen-sink/react-next/src/pages/_app.tsx
  92. +89
    -0
      packages/kitchen-sink/react-next/src/pages/_document.tsx
  93. +13
    -0
      packages/kitchen-sink/react-next/src/pages/api/hello.ts
  94. +43
    -0
      packages/kitchen-sink/react-next/src/pages/index.tsx
  95. +56
    -83
      packages/kitchen-sink/react-next/src/pages/layouts/basic.tsx
  96. +218
    -232
      packages/kitchen-sink/react-next/src/pages/layouts/left-sidebar-with-menu.tsx
  97. +116
    -147
      packages/kitchen-sink/react-next/src/pages/layouts/left-sidebar.tsx
  98. +199
    -0
      packages/kitchen-sink/react-next/src/pages/layouts/left-sidebar/alternate.tsx
  99. +90
    -127
      packages/kitchen-sink/react-next/src/pages/layouts/right-sidebar-static.tsx
  100. +20
    -0
      packages/kitchen-sink/react-next/tsconfig.json

+ 104
- 2
.gitignore 查看文件

@@ -1,6 +1,108 @@
# Logs
logs
*.log
.DS_Store
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.production
.env.development

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

.npmrc
.idea/

+ 0
- 6
.npmignore 查看文件

@@ -1,6 +0,0 @@
example/
node_modules/
src/
.editorconfig
tsconfig.json
yarn.lock

+ 4
- 18
LICENSE 查看文件

@@ -1,21 +1,7 @@
MIT License
MIT License Copyright (c) 2022 TheoryOfNekomata <allan.crisostomo@outlook.com>

Copyright (c) 2021 TheoryOfNekomata
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 7
- 47
README.md 查看文件

@@ -6,53 +6,7 @@ This library is made to avoid custom repetitive layout code.

## Usage

Just import:

```tsx
import * as React from 'react'
import { Basic, LeftSidebar, LeftSidebarWithMenu, RightSidebarStatic } from '@tesseract-design/viewfinder'

const Page: React.FC = ({
avatar,
fullName,
}) => (
<Basic.Layout
brand={
<a href="/">
<img
src="logo.svg"
alt="ACME Inc."
/>
</a>
}
topBarCenter={
<form>
<input
type="search"
name="q"
/>
</form>
}
userLink={
<a href="/profile">
<img
src={avatar}
alt={fullName}
/>
</a>
}
>
<Basic.ContentContainer>
Hello world!
</Basic.ContentContainer>
</Basic.Layout>
)

export default Page
```

Other examples can be found in the `example` directory in the repository. Please check them out for hints
on styling and using the different available layouts.
See the [kitchen sink](./packages/kitchen-sink) for examples.

The available props per layout are included as a TypeScript declarations file.

@@ -72,3 +26,9 @@ Height of the top bar widget.
Default value: `4rem`

Width or height of the menu, depending on the orientation it is rendered.

### `--color-background`

Default value: `white`

Background colors of several widgets from the library.

+ 0
- 1
example/.browserslistrc 查看文件

@@ -1 +0,0 @@
defaults

+ 0
- 3
example/.gitignore 查看文件

@@ -1,3 +0,0 @@
node_modules
.cache
dist

+ 0
- 39
example/components/Brand/index.tsx 查看文件

@@ -1,39 +0,0 @@
import * as React from 'react'
import styled from 'styled-components'

const BrandBase = styled('a')({
display: 'block',
textDecoration: 'none',
fontSize: '1.5rem',
fontWeight: 'bold',
fontStretch: '75%',
textTransform: 'uppercase',
width: '2rem',
textAlign: 'center',
'@media (min-width: 720px)': {
width: '8rem',
textAlign: 'left',
},
})

const Hide = styled('span')({
display: 'none',
'@media (min-width: 720px)': {
display: 'inline',
},
})

const Brand = () => {
return (
<BrandBase
href="/index.html"
>
B
<Hide>
rand
</Hide>
</BrandBase>
)
}

export default Brand

+ 0
- 11
example/index.html 查看文件

@@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Viewfinder Examples</title>
</head>
<body>
<script src="./index.tsx"></script>
</body>
</html>

+ 0
- 44
example/index.tsx 查看文件

@@ -1,44 +0,0 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';

const Page = () => {
return (
<>
<h1>
Viewfinder Examples
</h1>
<nav>
<h2>
Layouts
</h2>
<div>
<a href="layouts/basic/index.html">Basic</a>
</div>
<div>
<a href="layouts/basic-narrow/index.html">Basic Narrow</a>
</div>
<div>
<a href="layouts/left-sidebar/index.html">Left Sidebar</a>
</div>
<div>
<a href="layouts/left-sidebar-2/index.html">Left Sidebar (alternate)</a>
</div>
<div>
<a href="layouts/left-sidebar-with-menu/index.html">Left Sidebar With Menu</a>
</div>
<div>
<a href="layouts/right-sidebar-static/index.html">Right Sidebar Static</a>
</div>
</nav>
<p>
Look at how the layouts are coded in the <a href="https://code.modal.sh/TheoryOfNekomata/viewfinder" rel="noreferrer noopener" target="_blank">Git repository</a>.
</p>
</>
);
};

const root = document.createElement('div')

ReactDOM.render(<Page />, root);

document.body.appendChild(root);

+ 0
- 14
example/layouts/basic-narrow/index.html 查看文件

@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Basic Narrow Layout | Viewfinder</title>
<style>
body { margin: 0 }
</style>
</head>
<body>
<script src="./index.tsx"></script>
</body>
</html>

+ 0
- 19
example/layouts/basic-narrow/index.tsx 查看文件

@@ -1,19 +0,0 @@
import * as React from 'react'
import * as ReactDOM from 'react-dom';
import { BasicNarrow } from '../../..';

const Page = () => {
return (
<BasicNarrow.Layout>
<BasicNarrow.ContentContainer>
Hello
</BasicNarrow.ContentContainer>
</BasicNarrow.Layout>
)
}

const root = document.createElement('div')

ReactDOM.render(<Page />, root);

document.body.appendChild(root);

+ 0
- 14
example/layouts/basic/index.html 查看文件

@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Basic Layout | Viewfinder</title>
<style>
body { margin: 0 }
</style>
</head>
<body>
<script src="./index.tsx"></script>
</body>
</html>

+ 0
- 14
example/layouts/left-sidebar-2/index.html 查看文件

@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Left Sidebar Layout (alternate) | Viewfinder</title>
<style>
body { margin: 0 }
</style>
</head>
<body>
<script src="./index.tsx"></script>
</body>
</html>

+ 0
- 14
example/layouts/left-sidebar-with-menu/index.html 查看文件

@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Left Sidebar With Menu Layout | Viewfinder</title>
<style>
body { margin: 0 }
</style>
</head>
<body>
<script src="./index.tsx"></script>
</body>
</html>

+ 0
- 14
example/layouts/left-sidebar/index.html 查看文件

@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Left Sidebar Layout | Viewfinder</title>
<style>
body { margin: 0 }
</style>
</head>
<body>
<script src="./index.tsx"></script>
</body>
</html>

+ 0
- 14
example/layouts/right-sidebar-static/index.html 查看文件

@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Right Sidebar Static Layout | Viewfinder</title>
<style>
body { margin: 0 }
</style>
</head>
<body>
<script src="./index.tsx"></script>
</body>
</html>

+ 0
- 26
example/package.json 查看文件

@@ -1,26 +0,0 @@
{
"name": "example",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "parcel index.html layouts/**/*.html static/**/*",
"build": "parcel build index.html layouts/**/*.html",
"postbuild": "parcel build static/**/*"
},
"alias": {
"react": "../node_modules/react",
"react-dom": "../node_modules/react-dom/profiling",
"styled-components": "../node_modules/styled-components",
"scheduler/tracing": "../node_modules/scheduler/tracing-profiling"
},
"devDependencies": {
"@types/react": "^16.9.11",
"@types/react-dom": "^16.8.4",
"parcel": "1.12.3",
"typescript": "^3.4.5"
},
"dependencies": {
"react-markdown": "^6.0.2"
}
}

+ 0
- 19
example/tsconfig.json 查看文件

@@ -1,19 +0,0 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": false,
"target": "es5",
"module": "commonjs",
"jsx": "react",
"moduleResolution": "node",
"noImplicitAny": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"removeComments": true,
"strictNullChecks": true,
"preserveConstEnums": true,
"sourceMap": true,
"esModuleInterop": true,
"lib": ["es2015", "es2016", "dom"],
"types": ["node"]
}
}

+ 0
- 5527
example/yarn.lock
文件差异内容过多而无法显示
查看文件


+ 0
- 85
package.json 查看文件

@@ -1,85 +0,0 @@
{
"version": "0.2.6",
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"files": [
"dist"
],
"publishing": {
"github": {
"repository": "https://github.com/TheoryOfNekomata/viewfinder.git",
"publishConfig": {
"registry": "https://npm.pkg.github.com"
}
},
"master": {
"repository": "https://code.modal.sh/TheoryOfNekomata/viewfinder.git",
"publishConfig": {
"registry": "https://js.pack.modal.sh"
}
},
"npm": {
"publishConfig": {
"registry": "https://registry.npmjs.com"
}
}
},
"engines": {
"node": ">=10"
},
"scripts": {
"start": "tsdx watch",
"build": "tsdx build",
"test": "tsdx test --passWithNoTests",
"lint": "tsdx lint",
"prepare": "tsdx build",
"size": "size-limit",
"analyze": "size-limit --why"
},
"peerDependencies": {
"react": ">=16",
"styled-components": "^5.2.3"
},
"husky": {
"hooks": {
"pre-commit": "tsdx lint"
}
},
"name": "@theoryofnekomata/viewfinder",
"description": "Layout scaffolding for Web apps.",
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>",
"module": "dist/viewfinder.esm.js",
"size-limit": [
{
"path": "dist/viewfinder.cjs.production.min.js",
"limit": "10 KB"
},
{
"path": "dist/viewfinder.esm.js",
"limit": "10 KB"
}
],
"devDependencies": {
"@size-limit/preset-small-lib": "^4.10.2",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3",
"@types/styled-components": "^5.1.9",
"husky": "^6.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"size-limit": "^4.10.2",
"tsdx": "^0.14.1",
"tslib": "^2.2.0",
"typescript": "^4.2.4",
"styled-components": "^5.2.3"
},
"keywords": [
"scaffolding",
"template",
"react",
"layout",
"design",
"design-system"
]
}

+ 67
- 0
packages/base/package.json 查看文件

@@ -0,0 +1,67 @@
{
"name": "@tesseract-design/viewfinder-base",
"version": "0.0.0",
"files": [
"dist",
"src"
],
"engines": {
"node": ">=10"
},
"license": "MIT",
"keywords": [
"pridepack"
],
"dependencies": {
"@tesseract-design/goofy-goober": "https://code.modal.sh/tesseract-design/goofy-goober.git"
},
"devDependencies": {
"@types/node": "^18.0.0",
"eslint": "^8.20.0",
"eslint-config-lxsmnsyc": "^0.4.7",
"pridepack": "2.2.1",
"tslib": "^2.4.0",
"typescript": "^4.7.4",
"vitest": "^0.19.1"
},
"scripts": {
"prepublishOnly": "pridepack clean && pridepack build",
"build": "pridepack build",
"type-check": "pridepack check",
"lint": "pridepack lint",
"clean": "pridepack clean",
"watch": "pridepack watch",
"start": "pridepack start",
"dev": "pridepack dev",
"test": "vitest"
},
"private": false,
"description": "Base styles for Viewfinder.",
"repository": {
"url": "",
"type": "git"
},
"homepage": "",
"bugs": {
"url": ""
},
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>",
"publishConfig": {
"access": "public"
},
"types": "./dist/types/index.d.ts",
"exports": {
".": {
"development": {
"require": "./dist/cjs/development/index.js",
"import": "./dist/esm/development/index.js"
},
"require": "./dist/cjs/production/index.js",
"import": "./dist/esm/production/index.js",
"types": "./dist/types/index.d.ts"
}
},
"typesVersions": {
"*": {}
}
}

+ 3
- 0
packages/base/pridepack.json 查看文件

@@ -0,0 +1,3 @@
{
"target": "es2017"
}

+ 12
- 0
packages/base/src/common.ts 查看文件

@@ -0,0 +1,12 @@
export enum Span {
NARROW = 'narrow',
NORMAL = 'normal',
WIDE = 'wide',
}

export type LayoutArgs = {
span: Span;
mainSidebarOpen: boolean;
}

export { setup, extractCss } from '@tesseract-design/goofy-goober';

+ 3
- 0
packages/base/src/index.ts 查看文件

@@ -0,0 +1,3 @@
export * as layouts from './layouts';
export * as widgets from './widgets';
export * from './common';

+ 34
- 0
packages/base/src/layouts/Basic.ts 查看文件

@@ -0,0 +1,34 @@
import { css } from '@tesseract-design/goofy-goober';
import {LayoutArgs, Span} from '../common';

export const ContentBase = () => css.cx(
css`
box-sizing: border-box;
`
);

export const ContentContainer = ({
span,
}: LayoutArgs) => css.cx(
css`
padding: 0 1rem;
box-sizing: border-box;
margin: 0 auto;
width: 100%;
`,
css.if(span === Span.NARROW)(
css`
max-width: var(--base-width);
`
),
css.if(span === Span.NORMAL)(
css`
max-width: calc(var(--base-width) * 2);
`
),
css.if(span === Span.WIDE)(
css`
max-width: calc(var(--base-width) * 3);
`
),
);

+ 90
- 0
packages/base/src/layouts/LeftSidebar.ts 查看文件

@@ -0,0 +1,90 @@
import { css } from '@tesseract-design/goofy-goober';
import {LayoutArgs} from '../common';

export const ContentBase = () => css.cx(
css`
box-sizing: border-box;
`,
css.media('(min-width: 1080px)')(
css`
padding-left: calc(50% - (var(--base-width) * 0.5));
`
),
);

export const SidebarOverflow = () => css.cx(
css`
width: 100%;
height: 100%;
overflow: auto;
// overflow: overlay;
position: relative;
z-index: 1;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
`
)

export const SidebarBase = ({
mainSidebarOpen,
}: LayoutArgs) => css.cx(
css`
box-sizing: border-box;
position: fixed;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background-color: var(--color-background, white);
& > * {
display: block;
width: 100%;
height: 100%;
}
`,
css.media('(min-width: 1080px)')(
css`
width: calc(50% - (var(--base-width) * 0.5));
left: 0;
`
),
css.if(mainSidebarOpen)(
css`
left: 0;
`
),
);

export const SidebarMainContainer = () => css.cx(
css`
width: 100%;
margin: 0 auto;
padding: 0 1rem;
box-sizing: border-box;
max-width: calc(var(--base-width) * 2);
`,
css.media('(min-width: 1080px)')(
css`
width: var(--base-width);
margin-right: 0;
`
),
);

export const ContentContainer = () => css.cx(
css`
padding: 0 1rem;
box-sizing: border-box;
width: 100%;
max-width: calc(var(--base-width) * 2);
margin-right: auto;
margin-left: auto;
`,
css.media('(min-width: 1080px)')(
css`
margin-left: 0;
`
),
);

+ 370
- 0
packages/base/src/layouts/LeftSidebarWithMenu.ts 查看文件

@@ -0,0 +1,370 @@
import { css } from '@tesseract-design/goofy-goober';
import {LayoutArgs} from '../common';

export const ContentBase = () => css.cx(
css`
box-sizing: border-box;
padding-bottom: var(--size-menu, 4rem);
`,
css.media('(min-width: 1080px)')(
css`
padding-left: calc(50% - var(--base-width) * 0.5);
padding-bottom: 0;
`,
),
)

export const SidebarBase = () => css.cx(
css`
box-sizing: border-box;
overflow: hidden;
display: contents;
left: calc(var(--base-width) * -1);
`,
css.media('(min-width: 1080px)')(
css`
position: fixed;
top: 0;
left: 0;
width: calc(50% - var(--base-width) * 0.5);
height: 100%;
display: block;
`,
),
)

export const SidebarMain = ({
mainSidebarOpen,
}: LayoutArgs) => css.cx(
css`
box-sizing: border-box;
position: fixed;
top: 0;
width: 100%;
height: 100%;
padding-top: inherit;
padding-bottom: var(--size-menu, 4rem);
z-index: 2;
background-color: var(--color-background, white);
> * {
display: block;
width: 100%;
height: 100%;
background-color: var(--color-background, white);
}
`,
css.dynamic({
right: mainSidebarOpen ? 0 : '100%',
}),
css.media('(min-width: 1080px)')(
css`
position: absolute;
right: 0;
width: calc(var(--base-width) - var(--size-menu, 4rem));
margin-left: 0;
padding-bottom: 0;
`,
),
)

export const SidebarMainOverflow = () => css.cx(
css`
width: 100%;
height: 100%;
overflow: auto; /* overflow: overlay */
scrollbar-width: none;
position: relative;
z-index: 1;
::-webkit-scrollbar {
display: none;
}
`
)

export const SidebarMenu = () => css.cx(
css`
box-sizing: border-box;
overflow: auto; /* overflow: overlay */
scrollbar-width: none;
::-webkit-scrollbar {
display: none;
}
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: var(--size-menu, 4rem);
z-index: 1;
background-color: var(--color-background, white);
> * {
display: block;
width: 100%;
height: 100%;
background-color: var(--color-background, white);
}
`,
css.media('(min-width: 1080px)')(
css`
top: 0;
margin-left: auto;
position: absolute;
height: 100%;
padding-top: inherit;
overflow: auto;
z-index: auto;
`,
),
);

export const SidebarMenuSize = () => css.cx(
css`
display: flex;
width: 100%;
height: 100%;
max-width: calc(var(--base-width) * 2);
margin: 0 auto;
position: relative;
z-index: 1;
`,
css.media('(min-width: 1080px)')(
css`
max-width: none;
margin-right: 0;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
`,
),
);

export const SidebarMenuGroup = () => css.cx(
css`
display: contents;
`,
css.media('(min-width: 1080px)')(
css`
width: 100%;
display: block;
`,
),
);

export const MoreItems = ({
mainSidebarOpen,
}: LayoutArgs) => css.cx(
css`
position: fixed;
top: 0;
width: 100%;
height: 100%;
padding-top: var(--height-topbar, 4rem);
padding-bottom: var(--size-menu, 4rem);
z-index: -1;
box-sizing: border-box;
`,
css.dynamic({
left: mainSidebarOpen ? 0 : '-100%',
}),
css.media('(min-width: 1080px)')(
css`
display: contents;
`,
),
);

export const MoreItemsScroll = () => css.cx(
css`
width: 100%;
height: 100%;
overflow: auto;
background-color: var(--color-background, white);
`,
css.media('(min-width: 1080px)')(
css`
display: contents;
`,
),
);

export const MorePrimarySidebarMenuGroup = () => css.cx(
css.media('(min-width: 1080px)')(
css`
flex: auto;
`,
),
);

export const MoreSecondarySidebarMenuGroup = () => css.cx(
css.media('(min-width: 1080px)')(
css`
order: 4;
`,
),
);

export const SidebarMenuItem = () => css.cx(
css`
width: 0;
flex: auto;
height: var(--size-menu, 4rem);
> * {
height: 100%;
display: flex;
align-items: center;
text-decoration: none;
width: 100%;
}
`,
css.media('(min-width: 1080px)')(
css`
width: auto !important;
flex: 0 1 auto;
> * {
height: auto;
}
`
),
);

export const MoreSidebarMenuItem = () => css.cx(
css`
height: var(--size-menu, 4rem);
display: block;
> * {
height: 100%;
display: flex;
align-items: center;
text-decoration: none;
width: 100%;
}
`,
css.media('(min-width: 1080px)')(
css`
width: auto !important;
flex: 0 1 auto;
`,
),
);

export const MoreToggleSidebarMenuItem = () => css.cx(
css`
width: 0;
flex: auto;
height: var(--size-menu, 4rem);
> * {
height: 100%;
display: flex;
align-items: center;
text-decoration: none;
width: 100%;
}
`,
css.media('(min-width: 1080px)')(
css`
display: none;
`,
),
);

export const SidebarMenuItemIcon = () => css.cx(
css`
display: block;
`,
css.media('(min-width: 1080px)')(
css`
width: var(--size-menu, 4rem);
height: var(--size-menu, 4rem);
display: grid;
place-content: center;
`,
),
);

export const MoreSidebarMenuItemIcon = () => css.cx(
css`
margin-right: 1rem;
display: block;
`,
css.media('(min-width: 1080px)')(
css`
width: var(--size-menu, 4rem);
height: var(--size-menu, 4rem);
display: grid;
place-content: center;
margin-right: 0;
`,
),
);

export const SidebarMenuContainer = () => css.cx(
css`
box-sizing: border-box;
display: grid;
place-content: center;
width: 100%;
text-align: center;
`,
css.media('(min-width: 1080px)')(
css`
display: flex;
justify-content: flex-start;
align-items: center;
margin-left: auto;
padding-right: 1rem;
text-align: left;
box-sizing: border-box;
width: var(--base-width);
`,
),
)

export const MoreSidebarMenuContainer = () => css.cx(
css`
display: flex;
justify-content: flex-start;
align-items: center;
width: calc(var(--base-width) * 2);
margin: 0 auto;
padding: 0 1rem;
text-align: left;
box-sizing: border-box;
`,
css.media('(min-width: 1080px)')(
css`
margin-right: 0;
width: var(--base-width);
padding-left: 0;
`,
),
);

export const ContentContainer = () => css.cx(
css`
padding: 0 1rem;
box-sizing: border-box;
width: 100%;
max-width: calc(var(--base-width) * 2);
margin-right: auto;
margin-left: auto;
`,
css.media('(min-width: 1080px)')(
css`
margin-left: 0;
`,
),
);

export const SidebarMainContainer = () => css.cx(
css`
padding: 0 1rem;
box-sizing: border-box;
width: 100%;
max-width: calc(var(--base-width) * 2);
margin: 0 auto;
`,
css.media('(min-width: 1080px)')(
css`
max-width: none;
`,
),
);

+ 83
- 0
packages/base/src/layouts/RightSidebarStatic.ts 查看文件

@@ -0,0 +1,83 @@
import { css } from '@tesseract-design/goofy-goober';

export const ContentBase = () => css.cx(
css`
box-sizing: border-box;
`,
css.media('(min-width: 1080px)')(
css`
padding-right: calc(50% - (var(--base-width) * 0.5));
`
),
);

export const SidebarBase = () => css.cx(
css`
box-sizing: border-box;
background-color: var(--color-background, white);
`,
// prevent collapse of margin
css`
&::after {
content: '';
display: block;
padding-bottom: 1px;
margin-top: -1px;
box-sizing: border-box;
}
& > * {
display: block;
width: 100%;
height: 100%;
}
`,
css.media('(min-width: 1080px)')(
css`
position: absolute;
top: 0;
right: 0;
width: calc(50% - var(--base-width) * 0.5);
height: 100%;
`,
),
)

export const SidebarMainContent = () => css.cx(
css`
position: relative;
z-index: 1;
`
)

export const SidebarMainContainer = () => css.cx(
css`
padding: 0 1rem;
box-sizing: border-box;
width: 100%;
max-width: calc(var(--base-width) * 2);
margin: 0 auto;
`,
css.media('(min-width: 1080px)')(
css`
margin-left: 0;
width: var(--base-width);
`,
),
)

export const ContentContainer = () => css.cx(
css`
padding: 0 1rem;
box-sizing: border-box;
width: 100%;
max-width: calc(var(--base-width) * 2);
margin: 0 auto;
`,
css.media('(min-width: 1080px)')(
css`
margin-right: 0;
`,
),
)

// TODO port from original viewfinder package

+ 4
- 0
packages/base/src/layouts/index.ts 查看文件

@@ -0,0 +1,4 @@
export * as Basic from './Basic';
export * as LeftSidebar from './LeftSidebar';
export * as LeftSidebarWithMenu from './LeftSidebarWithMenu';
export * as RightSidebarStatic from './RightSidebarStatic';

+ 125
- 0
packages/base/src/widgets/TopBar.ts 查看文件

@@ -0,0 +1,125 @@
import { css } from '@tesseract-design/goofy-goober';
import {LayoutArgs, Span} from '../common';

export const Base = () => css.cx(
css`
position: fixed;
top: 0;
left: 0;
width: 100%;
height: var(--height-topbar, 4rem);
z-index: 3;
& > * {
display: block;
width: 100%;
height: 100%;
background-color: var(--color-background, white);
}
& ~ * {
padding-top: var(--height-topbar, 4rem);
}
~ main ~ * {
padding-top: 0;
}
`,
css.media('(min-width: 1080px)')(
css`
~ main ~ * {
padding-top: var(--height-topbar, 4rem);
}
`
)
);

export const Container = ({
span,
}: LayoutArgs) => css.cx(
css`
padding: 0 1rem;
box-sizing: border-box;
margin: 0 auto;
width: 100%;
height: 100%;
display: flex;
align-items: center;
position: relative;
z-index: 1;
`,
css.if(span === Span.NARROW)(
css`
max-width: var(--base-width);
`
),
css.if(span === Span.NORMAL)(
css`
max-width: calc(var(--base-width) * 2);
`
),
css.if(span === Span.WIDE)(
css.media('(min-width: 1080px)')(
css`
max-width: calc(var(--base-width) * 3);
`
)
),
);

export const CenterContainer = () => css.cx(
css`
flex: auto;
padding: 0 1rem;
box-sizing: border-box;
`,
css.nest(':first-child')(
css`
padding-left: 0;
`
)
)

export const ActionContainer = () => css.cx(
css`
display: flex;
align-items: center;
justify-content: flex-end;
height: 100%;
white-space: nowrap;
`,
css.media('(min-width: 720px)')(
css`
min-width: 8rem;
`
)
);

export const LinkContainer = () => css.cx(
css`
width: var(--height-topbar, 4rem);
height: 100%;
& > * {
width: 100%;
height: 100%;
display: inline-grid;
place-content: center;
}
`
);

export const MenuLinkContainer = () => css.cx(
css`
width: var(--height-topbar, 4rem);
height: 100%;
& > * {
width: 100%;
height: 100%;
display: inline-grid;
place-content: center;
}
`,
css.media('(min-width: 1080px)')(
css`
position: absolute;
left: -999999px;
`
)
);

+ 1
- 0
packages/base/src/widgets/index.ts 查看文件

@@ -0,0 +1 @@
export * as TopBar from './TopBar';

+ 8
- 0
packages/base/test/index.test.ts 查看文件

@@ -0,0 +1,8 @@
import { describe, it, expect } from 'vitest';
import add from '../src';

describe('blah', () => {
it('works', () => {
expect(add(1, 1)).toEqual(2);
});
});

+ 21
- 0
packages/base/tsconfig.json 查看文件

@@ -0,0 +1,21 @@
{
"exclude": ["node_modules"],
"include": ["src", "types"],
"compilerOptions": {
"module": "ESNext",
"lib": ["ESNext"],
"importHelpers": true,
"declaration": true,
"sourceMap": true,
"rootDir": "./src",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"jsx": "react",
"esModuleInterop": true,
"target": "ES2017"
}
}

+ 3378
- 0
packages/base/yarn.lock
文件差异内容过多而无法显示
查看文件


+ 3
- 0
packages/kitchen-sink/react-next/.eslintrc.json 查看文件

@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

+ 36
- 0
packages/kitchen-sink/react-next/.gitignore 查看文件

@@ -0,0 +1,36 @@
# 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

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

+ 34
- 0
packages/kitchen-sink/react-next/README.md 查看文件

@@ -0,0 +1,34 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.

[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.

The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

+ 7
- 0
packages/kitchen-sink/react-next/next.config.js 查看文件

@@ -0,0 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
}

module.exports = nextConfig

+ 26
- 0
packages/kitchen-sink/react-next/package.json 查看文件

@@ -0,0 +1,26 @@
{
"name": "@tesseract-design/viewfinder-kitchen-sink-react",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"goober": "^2.1.12",
"next": "12.2.4",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-markdown": "^8.0.6"
},
"devDependencies": {
"@types/node": "18.6.4",
"@types/react": "18.0.15",
"@types/react-dom": "18.0.6",
"eslint": "8.21.0",
"eslint-config-next": "12.2.4",
"typescript": "4.7.4"
}
}

二进制
packages/kitchen-sink/react-next/public/favicon.ico 查看文件

之前 之后

example/static/japanese-calligraphy/20101122_Calligraphy_Hirano_Demo.jpg → packages/kitchen-sink/react-next/public/static/japanese-calligraphy/20101122_Calligraphy_Hirano_Demo.jpg 查看文件


example/static/japanese-calligraphy/freddie-marriage-gL-7_NtZpYI-unsplash.jpg → packages/kitchen-sink/react-next/public/static/japanese-calligraphy/freddie-marriage-gL-7_NtZpYI-unsplash.jpg 查看文件


example/static/japanese-calligraphy/japanese_calligraphy_at_meiji_shrine_tokyo.jpg → packages/kitchen-sink/react-next/public/static/japanese-calligraphy/japanese_calligraphy_at_meiji_shrine_tokyo.jpg 查看文件


example/static/japanese-calligraphy/marco-zuppone-zHwWnUDMizo-unsplash.jpg → packages/kitchen-sink/react-next/public/static/japanese-calligraphy/marco-zuppone-zHwWnUDMizo-unsplash.jpg 查看文件


example/static/japanese-calligraphy/niketh-vellanki-vJqSAasmCEY-unsplash.jpg → packages/kitchen-sink/react-next/public/static/japanese-calligraphy/niketh-vellanki-vJqSAasmCEY-unsplash.jpg 查看文件


example/static/japanese-calligraphy/what-is-japanese-calligraphy-used-for-1-1.jpg → packages/kitchen-sink/react-next/public/static/japanese-calligraphy/what-is-japanese-calligraphy-used-for-1-1.jpg 查看文件


example/static/piano/bechstein-moor-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/bechstein-moor-grand-00.jpg 查看文件


example/static/piano/bechstein-moor-grand-01.jpg → packages/kitchen-sink/react-next/public/static/piano/bechstein-moor-grand-01.jpg 查看文件


example/static/piano/boesendorfer-moor-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/boesendorfer-moor-grand-00.jpg 查看文件


example/static/piano/boesendorfer-moor-grand-01.jpg → packages/kitchen-sink/react-next/public/static/piano/boesendorfer-moor-grand-01.jpg 查看文件


example/static/piano/boesendorfer-moor-grand-02.jpg → packages/kitchen-sink/react-next/public/static/piano/boesendorfer-moor-grand-02.jpg 查看文件


example/static/piano/chris-maene-cm228-parlor-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/chris-maene-cm228-parlor-grand-00.jpg 查看文件


example/static/piano/chris-maene-cm250-chamber-concert-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/chris-maene-cm250-chamber-concert-grand-00.jpg 查看文件


example/static/piano/chris-maene-cm284-concert-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/chris-maene-cm284-concert-grand-00.jpg 查看文件


example/static/piano/grotrian-duo-double-grand.jpg → packages/kitchen-sink/react-next/public/static/piano/grotrian-duo-double-grand.jpg 查看文件


example/static/piano/grotrian-steinweg-double-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/grotrian-steinweg-double-grand-00.jpg 查看文件


example/static/piano/korg-kronos-88-00.jpg → packages/kitchen-sink/react-next/public/static/piano/korg-kronos-88-00.jpg 查看文件


example/static/piano/korg-kronos-88-01.jpg → packages/kitchen-sink/react-next/public/static/piano/korg-kronos-88-01.jpg 查看文件


example/static/piano/kurzweil-forte-00.webp → packages/kitchen-sink/react-next/public/static/piano/kurzweil-forte-00.webp 查看文件


example/static/piano/nehlsen-omega-double-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/nehlsen-omega-double-grand-00.jpg 查看文件


example/static/piano/pleyel-double-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/pleyel-double-grand-00.jpg 查看文件


example/static/piano/pleyel-double-grand-01.jpg → packages/kitchen-sink/react-next/public/static/piano/pleyel-double-grand-01.jpg 查看文件


example/static/piano/pleyel-double-grand-02.jpg → packages/kitchen-sink/react-next/public/static/piano/pleyel-double-grand-02.jpg 查看文件


example/static/piano/pleyel-moor-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/pleyel-moor-grand-00.jpg 查看文件


example/static/piano/pleyel-moor-grand-01.jpg → packages/kitchen-sink/react-next/public/static/piano/pleyel-moor-grand-01.jpg 查看文件


example/static/piano/pleyel-moor-grand-02.jpg → packages/kitchen-sink/react-next/public/static/piano/pleyel-moor-grand-02.jpg 查看文件


example/static/piano/pleyel-moor-upright-00.jpg → packages/kitchen-sink/react-next/public/static/piano/pleyel-moor-upright-00.jpg 查看文件


example/static/piano/roland-fantom-8-00.jpg → packages/kitchen-sink/react-next/public/static/piano/roland-fantom-8-00.jpg 查看文件


example/static/piano/roland-fantom-8-01.jpg → packages/kitchen-sink/react-next/public/static/piano/roland-fantom-8-01.jpg 查看文件


example/static/piano/roland-fantom-8-02.jpg → packages/kitchen-sink/react-next/public/static/piano/roland-fantom-8-02.jpg 查看文件


example/static/piano/steinway-moor-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/steinway-moor-grand-00.jpg 查看文件


example/static/piano/stuart-and-sons-beleura-concert-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/stuart-and-sons-beleura-concert-grand-00.jpg 查看文件


example/static/piano/stuart-and-sons-beleura-concert-grand-01.jpg → packages/kitchen-sink/react-next/public/static/piano/stuart-and-sons-beleura-concert-grand-01.jpg 查看文件


example/static/piano/stuart-and-sons-beleura-studio-grand-00.jpg → packages/kitchen-sink/react-next/public/static/piano/stuart-and-sons-beleura-studio-grand-00.jpg 查看文件


example/static/piano/yamaha-cp88-00.jpg → packages/kitchen-sink/react-next/public/static/piano/yamaha-cp88-00.jpg 查看文件


example/static/piano/yamaha-cp88-01.jpg → packages/kitchen-sink/react-next/public/static/piano/yamaha-cp88-01.jpg 查看文件


example/static/piano/yamaha-cp88-02.jpg → packages/kitchen-sink/react-next/public/static/piano/yamaha-cp88-02.jpg 查看文件


example/static/piano/yamaha-montage-8-00.webp → packages/kitchen-sink/react-next/public/static/piano/yamaha-montage-8-00.webp 查看文件


example/static/ramen/Butter_Corn_Ramen.jpg → packages/kitchen-sink/react-next/public/static/ramen/Butter_Corn_Ramen.jpg 查看文件


example/static/ramen/Tokyoramen.jpg → packages/kitchen-sink/react-next/public/static/ramen/Tokyoramen.jpg 查看文件


example/static/ramen/karei.png → packages/kitchen-sink/react-next/public/static/ramen/karei.png 查看文件


example/static/ramen/miso.png → packages/kitchen-sink/react-next/public/static/ramen/miso.png 查看文件


example/static/ramen/sapporo.jpg → packages/kitchen-sink/react-next/public/static/ramen/sapporo.jpg 查看文件


example/static/ramen/shio.png → packages/kitchen-sink/react-next/public/static/ramen/shio.png 查看文件


example/static/ramen/shoyu.jpg → packages/kitchen-sink/react-next/public/static/ramen/shoyu.jpg 查看文件


+ 4
- 0
packages/kitchen-sink/react-next/public/vercel.svg 查看文件

@@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

+ 25
- 0
packages/kitchen-sink/react-next/src/components/Brand/Brand.module.css 查看文件

@@ -0,0 +1,25 @@
.brand-base {
display: block;
text-decoration: none;
font-size: 1.5rem;
font-weight: bold;
font-stretch: 75%;
text-transform: uppercase;
width: 2rem;
text-align: center;
}

.hide {
display: none;
}

@media (min-width: 720px) {
.brand-base {
width: 8rem;
text-align: left;
}

.hide {
display: inline;
}
}

+ 19
- 0
packages/kitchen-sink/react-next/src/components/Brand/index.tsx 查看文件

@@ -0,0 +1,19 @@
import Link from 'next/link'
import styles from './Brand.module.css'

export const Brand = () => (
<Link
href="/"
passHref
>
<a
href="/"
className={styles['brand-base']}
>
B
<span className={styles.hide}>
rand
</span>
</a>
</Link>
)

+ 37
- 0
packages/kitchen-sink/react-next/src/components/DummyLinks.tsx 查看文件

@@ -0,0 +1,37 @@
import Link from 'next/link'

export const DummyLinks = () => (
<div
style={{
display: 'flex',
gap: '1rem',
alignItems: 'center',
marginLeft: '1rem',
}}
>
<Link
href="/"
passHref
>
<a>
About
</a>
</Link>
<Link
href="/"
passHref
>
<a>
Learn More
</a>
</Link>
<Link
href="/"
passHref
>
<a>
Contact
</a>
</Link>
</div>
)

+ 18
- 0
packages/kitchen-sink/react-next/src/components/Image/index.tsx 查看文件

@@ -0,0 +1,18 @@
import {FC} from 'react';

export interface ImageProps {
src?: string;
alt?: string;
style?: React.CSSProperties;
}

export const Image: FC<ImageProps> = ({ src, alt, style, }) => (
<img
src={src}
alt={alt}
style={{
...style,
width: '100%',
}}
/>
)

+ 10
- 0
packages/kitchen-sink/react-next/src/pages/_app.tsx 查看文件

@@ -0,0 +1,10 @@
import type { AppProps } from 'next/app'
import { setup } from '@tesseract-design/viewfinder-react';
import * as gooberPrefixer from 'goober/prefixer';
import * as React from 'react';

setup(React.createElement, gooberPrefixer.prefix);

const MyApp: React.FC<AppProps> = ({ Component, pageProps }) => <Component {...pageProps} />

export default MyApp

+ 89
- 0
packages/kitchen-sink/react-next/src/pages/_document.tsx 查看文件

@@ -0,0 +1,89 @@
import NextDocument, {Html, Head as NextHead, Main, NextScript, DocumentContext} from 'next/document';
import { extractCss } from '@tesseract-design/viewfinder-react';

export default class Document extends NextDocument {
static async getInitialProps(ctx: DocumentContext) {
const page = await ctx.renderPage()

const style = extractCss();

const initialProps = await NextDocument.getInitialProps(ctx)

return {
...initialProps,
...page,
style,
}
}

render() {
const { style: rawStyle } = this.props as Record<string, unknown>
const style = rawStyle as string

return (
<Html>
<NextHead>
{
style.length > 0
&& (
<style
id="_goober_ssr"
dangerouslySetInnerHTML={{ __html: style }}
/>
)
}
<style>
{`
:root {
--base-width: 360px;
--color-background: white;
}

html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
line-height: 1.75;
}

a {
color: inherit;
text-decoration: none;
}

* {
box-sizing: border-box;
}

@media (prefers-color-scheme: dark) {
:root {
--color-background: black;
}

html {
color-scheme: dark;
}
body {
color: white;
background-color: var(--color-background);
}
}

#__next {
display: contents;
background-color: inherit;
}

`}
</style>
</NextHead>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}

+ 13
- 0
packages/kitchen-sink/react-next/src/pages/api/hello.ts 查看文件

@@ -0,0 +1,13 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'

type Data = {
name: string
}

export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: 'John Doe' })
}

+ 43
- 0
packages/kitchen-sink/react-next/src/pages/index.tsx 查看文件

@@ -0,0 +1,43 @@
import type { NextPage } from 'next'
import { Layouts } from '@tesseract-design/viewfinder-react'
import Link from 'next/link'

const Home: NextPage = () => {
return (
<Layouts.Basic.Root>
<Layouts.Basic.ContentContainer>
<h1>
Viewfinder Examples
</h1>
<nav>
<h2>
Layouts
</h2>
<div>
<Link href="layouts/basic">Basic</Link>
</div>
<div>
<Link href="layouts/basic?span=narrow">Basic Narrow</Link>
</div>
<div>
<Link href="layouts/left-sidebar">Left Sidebar</Link>
</div>
<div>
<Link href="layouts/left-sidebar/alternate">Left Sidebar (alternate)</Link>
</div>
<div>
<Link href="layouts/left-sidebar-with-menu">Left Sidebar With Menu</Link>
</div>
<div>
<Link href="layouts/right-sidebar-static">Right Sidebar Static</Link>
</div>
</nav>
<p>
Look at how the layouts are coded in the <a href="https://code.modal.sh/TheoryOfNekomata/viewfinder" rel="noreferrer noopener" target="_blank">Git repository</a>.
</p>
</Layouts.Basic.ContentContainer>
</Layouts.Basic.Root>
)
}

export default Home

example/layouts/basic/index.tsx → packages/kitchen-sink/react-next/src/pages/layouts/basic.tsx 查看文件

@@ -1,80 +1,49 @@
import * as React from 'react'
import * as ReactDOM from 'react-dom';
import ReactMarkdown from 'react-markdown'
import styled from 'styled-components';
import Brand from '../../components/Brand';
import { Basic } from '../../..';
import type {GetServerSideProps, NextPage} from 'next';
import ReactMarkdown from 'react-markdown';
import { Layouts, Widgets } from '@tesseract-design/viewfinder-react';
import {Span} from '@tesseract-design/viewfinder-base';
import {Brand} from '../../components/Brand';
import {Image} from '../../components/Image';
import Link from 'next/link';

const TopBar = styled('div')({
backgroundColor: 'black',
color: 'white',
boxShadow: '0 0 0.25rem rgba(0,0,0,0.25)',
'a': {
color: 'inherit',
textDecoration: 'none',
}
})
type BaseLayoutPageProps = {
span: Span;
}

const Page = () => {
return (
<Basic.Layout
brand={
<Brand />
}
topBarComponent={TopBar}
topBarCenter={
<form
style={{
display: 'flex',
alignItems: 'center',
}}
>
<input
type="search"
name="q"
placeholder="Type your search keywords&hellip;"
style={{
height: '3rem',
width: '100%',
display: 'block',
boxSizing: 'border-box',
}}
/>
<button
type="submit"
style={{
height: '3rem',
marginLeft: '0.5rem',
}}
>
Search
</button>
</form>
}
userLink={
<a
href="?user"
>
User
</a>
}
>
<Basic.ContentContainer>
<ReactMarkdown
components={{
img: ({ src, alt, style, }) => (
<img
src={src}
alt={alt}
style={{
...style,
width: '100%',
}}
/>
)
}}
>
{`# Piano
const BasicLayoutPage: NextPage<BaseLayoutPageProps> = ({
span,
}) => {
return (
<Layouts.Basic.Root
topBarWidget={
<Widgets.TopBar
brand={
<Brand />
}
span={span as Span}
userLink={
<Link
href={{
query: {
open: 'sidebar',
},
}}
>
User
</Link>
}
/>
}
>
<Layouts.Basic.ContentContainer
span={span as Span}
>
<ReactMarkdown
components={{
img: Image,
}}
>
{`# Piano

![Bechstein Moor](/static/piano/bechstein-moor-grand-00.jpg)

@@ -95,14 +64,18 @@ Most modern pianos have a row of 88 black and white keys, 52 white keys for the
![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-02.jpg)

During the 1800s, influenced by the musical trends of the Romantic music era, innovations such as the cast iron frame (which allowed much greater string tensions) and aliquot stringing gave grand pianos a more powerful sound, with a longer sustain and richer tone. In the nineteenth century, a family's piano played the same role that a radio or phonograph played in the twentieth century; when a nineteenth-century family wanted to hear a newly published musical piece or symphony, they could hear it by having a family member play a simplified version on the piano. During the nineteenth century, music publishers produced many types of musical works (symphonies, opera overtures, waltzes, etc.) in arrangements for piano, so that music lovers could play and hear the popular pieces of the day in their home. The piano is widely employed in classical, jazz, traditional and popular music for solo and ensemble performances, accompaniment, and for composing, songwriting and rehearsals. Although the piano is very heavy and thus not portable and is expensive (in comparison with other widely used accompaniment instruments, such as the acoustic guitar), its musical versatility (i.e., its wide pitch range, ability to play chords, louder or softer notes and two or more independent musical lines at the same time), the large number of musicians - both amateurs and professionals - trained in playing it, and its wide availability in performance venues, schools and rehearsal spaces have made it one of the Western world's most familiar musical instruments.`}
</ReactMarkdown>
</Basic.ContentContainer>
</Basic.Layout>
)
</ReactMarkdown>
</Layouts.Basic.ContentContainer>
</Layouts.Basic.Root>
)
}

const root = document.createElement('div')

ReactDOM.render(<Page />, root);
export default BasicLayoutPage

document.body.appendChild(root);
export const getServerSideProps: GetServerSideProps = async (ctx) => {
return {
props: {
span: ctx.query.span ?? Span.NORMAL,
}
}
}

example/layouts/left-sidebar-with-menu/index.tsx → packages/kitchen-sink/react-next/src/pages/layouts/left-sidebar-with-menu.tsx 查看文件

@@ -1,250 +1,236 @@
import * as React from 'react'
import * as ReactDOM from 'react-dom';
import type { NextPage } from 'next'
import { Layouts, Widgets } from '@tesseract-design/viewfinder-react';
import {Span} from '@tesseract-design/viewfinder-base';
import Link from 'next/link';
import {Brand} from '../../components/Brand';
import {GetServerSideProps} from 'next';
import {FC, ReactNode} from 'react';
import {Image} from '../../components/Image';
import ReactMarkdown from 'react-markdown';
import Brand from '../../components/Brand';
import { LeftSidebarWithMenu } from '../../..';
import styled from 'styled-components';

const SidebarMenuComponent = styled('div')({
'::after': {
content: "''",
position: 'absolute',
top: 0,
right: 0,
height: '100%',
width: '0.0625rem',
backgroundColor: 'currentcolor',
opacity: 0.25,
pointerEvents: 'none',
}
})

const SidebarMainComponent = styled('div')({
'::before': {
content: "''",
position: 'absolute',
top: 0,
left: 0,
height: '100%',
width: '0.0625rem',
backgroundColor: 'currentcolor',
opacity: 0.25,
pointerEvents: 'none',
},
'::after': {
content: "''",
position: 'absolute',
top: 0,
right: 0,
height: '100%',
width: '0.0625rem',
backgroundColor: 'currentcolor',
opacity: 0.25,
pointerEvents: 'none',
}
})

const Page = () => {
const [sidebarMainOpen, setSidebarMainOpen] = React.useState(location.hash === '#sidebar')
const [moreItemsOpen, setMoreItemsOpen] = React.useState(location.hash === '#more')

React.useEffect(() => {
const handleHashChange = () => {
setSidebarMainOpen(location.hash === '#sidebar')
setMoreItemsOpen(location.hash === '#more')
}

window.addEventListener('hashchange', handleHashChange)
return () => {
window.removeEventListener('hashchange', handleHashChange)
}
}, [])

return (
<LeftSidebarWithMenu.Layout
moreItemsOpen={moreItemsOpen}
sidebarMainComponent={SidebarMainComponent}
sidebarMenuComponent={SidebarMenuComponent}
sidebarMenuItems={[
{
id: 'foo',
icon: 'F',
label: 'Foo',
url: '#foo',
},
{
id: 'bar',
icon: 'B',
label: 'Bar',
url: '#bar',
},
{
id: 'baz',
icon: 'Z',
label: 'Baz',
url: '#baz',
},
{
id: 'quux',
icon: 'Q',
label: 'Quux',
url: '#quux',
},
{
id: 'quuux',
icon: 'U',
label: 'Quuux',
url: '#quuux',
secondary: true,
},
{
id: 'quuuux',
icon: 'X',
label: 'Quuuux',
url: '#quuuux',
secondary: true,
},
]}
moreLinkMenuItem={{
url: '#more',
icon: 'M',
label: 'More',
}}
linkComponent={({
url,
icon,
label,
}) => (
<a
href={url}
>
<LeftSidebarWithMenu.SidebarMenuContainer>
<LeftSidebarWithMenu.SidebarMenuItemIcon>
{icon}
</LeftSidebarWithMenu.SidebarMenuItemIcon>
{label}
</LeftSidebarWithMenu.SidebarMenuContainer>
</a>
)}
moreLinkComponent={({
url,
icon,
label,
}) => (
<a
href={url}
>
<LeftSidebarWithMenu.MoreSidebarMenuContainer>
<LeftSidebarWithMenu.MoreSidebarMenuItemIcon>
{icon}
</LeftSidebarWithMenu.MoreSidebarMenuItemIcon>
{label}
</LeftSidebarWithMenu.MoreSidebarMenuContainer>
</a>
)}
brand={
<Brand />
}
sidebarMainOpen={sidebarMainOpen}
menuLink={
<a
href="#sidebar"
>
Menu
</a>
}
userLink={
<a
href="#user"
>
User
</a>
}
sidebarMain={
<>
<a
href="#foo"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<LeftSidebarWithMenu.SidebarMainContainer>
Foo
</LeftSidebarWithMenu.SidebarMainContainer>
</a>
<a
href="#bar"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<LeftSidebarWithMenu.SidebarMainContainer>
Bar
</LeftSidebarWithMenu.SidebarMainContainer>
</a>
<a
href="#baz"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<LeftSidebarWithMenu.SidebarMainContainer>
Baz
</LeftSidebarWithMenu.SidebarMainContainer>
</a>
</>
}
>
<LeftSidebarWithMenu.ContentContainer>
<ReactMarkdown
components={{
img: ({ src, alt, style, }) => (
<img
src={src}
alt={alt}
style={{
...style,
width: '100%',
}}
/>
)
}}
>
{`# Piano

![Bechstein Moor](/static/piano/chris-maene-cm228-parlor-grand-00.jpg)

type LeftSidebarWithMenuLayoutPageProps = {
open: string | null;
}

type LinkComponentProps = {
url: string;
label: string;
icon: ReactNode;
}

const LinkComponent: FC<LinkComponentProps> = ({
url,
label,
icon,
}) => (
<Link
href={url}
passHref
>
<a>
<Layouts.LeftSidebarWithMenu.SidebarMenuContainer>
<Layouts.LeftSidebarWithMenu.SidebarMenuItemIcon>
{icon}
</Layouts.LeftSidebarWithMenu.SidebarMenuItemIcon>
{label}
</Layouts.LeftSidebarWithMenu.SidebarMenuContainer>
</a>
</Link>
)

const MoreLinkComponent: FC<LinkComponentProps> = ({
url,
label,
icon,
}) => (
<Link
href={url}
passHref
>
<a>
<Layouts.LeftSidebarWithMenu.MoreSidebarMenuContainer>
<Layouts.LeftSidebarWithMenu.MoreSidebarMenuItemIcon>
{icon}
</Layouts.LeftSidebarWithMenu.MoreSidebarMenuItemIcon>
{label}
</Layouts.LeftSidebarWithMenu.MoreSidebarMenuContainer>
</a>
</Link>
)

const LeftSidebarWithMenuLayoutPage: NextPage<LeftSidebarWithMenuLayoutPageProps> = ({
open,
}) => {
const sidebarOpen = open === 'sidebar';
const moreItemsOpen = open === 'more';

return (
<Layouts.LeftSidebarWithMenu.Root
sidebarBaseWidget={
<Widgets.LeftSidebarWithMenuBase
span={Span.WIDE}
open={sidebarOpen}
moreItemsOpen={moreItemsOpen}
items={[
{
id: 'foo',
icon: 'F',
label: 'Foo',
url: '#foo',
},
{
id: 'bar',
icon: 'B',
label: 'Bar',
url: '#bar',
},
{
id: 'baz',
icon: 'Z',
label: 'Baz',
url: '#baz',
},
{
id: 'quux',
icon: 'Q',
label: 'Quux',
url: '#quux',
},
{
id: 'quuux',
icon: 'U',
label: 'Quuux',
url: '#quuux',
secondary: true,
},
{
id: 'quuuux',
icon: 'X',
label: 'Quuuux',
url: '#quuuux',
secondary: true,
},
]}
linkComponent={LinkComponent}
moreLinkItem={{
url: {
query: {
open: 'more',
},
},
icon: 'M',
label: 'More',
}}
moreLinkComponent={MoreLinkComponent}
>
<a
href="#foo"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<Layouts.LeftSidebarWithMenu.SidebarContentContainer>
Foo
</Layouts.LeftSidebarWithMenu.SidebarContentContainer>
</a>
<a
href="#bar"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<Layouts.LeftSidebarWithMenu.SidebarContentContainer>
Bar
</Layouts.LeftSidebarWithMenu.SidebarContentContainer>
</a>
<a
href="#baz"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<Layouts.LeftSidebarWithMenu.SidebarContentContainer>
Baz
</Layouts.LeftSidebarWithMenu.SidebarContentContainer>
</a>
</Widgets.LeftSidebarWithMenuBase>
}
topBarWidget={
<Widgets.TopBar
brand={
<Brand />
}
menuLink={
<Link
href={{
query: {
open: 'sidebar',
},
}}
>
Menu
</Link>
}
userLink={
<Link
href={{
query: {
open: 'sidebar',
},
}}
>
User
</Link>
}
span={Span.WIDE}
/>
}
>
<Layouts.LeftSidebarWithMenu.MainContentContainer>
<ReactMarkdown
components={{
img: Image,
}}
>
{`# Piano

![Bechstein Moor](/static/piano/bechstein-moor-grand-00.jpg)

The piano is an acoustic, stringed musical instrument invented in Italy by Bartolomeo Cristofori around the year 1700 (the exact year is uncertain), in which the strings are struck by wooden hammers that are coated with a softer material (modern hammers are covered with dense wool felt; some early pianos used leather). It is played using a keyboard, which is a row of keys (small levers) that the performer presses down or strikes with the fingers and thumbs of both hands to cause the hammers to strike the strings.

![Bechstein Moor](/static/piano/chris-maene-cm250-chamber-concert-grand-00.jpg)
![Bechstein Moor](/static/piano/bechstein-moor-grand-01.jpg)

The word piano is a shortened form of pianoforte, the Italian term for the early 1700s versions of the instrument, which in turn derives from gravicembalo col piano e forte (key cymbal with quieter and louder) and fortepiano. The Italian musical terms piano and forte indicate "soft" and "loud" respectively, in this context referring to the variations in volume (i.e., loudness) produced in response to a pianist's touch or pressure on the keys: the greater the velocity of a key press, the greater the force of the hammer hitting the strings, and the louder the sound of the note produced and the stronger the attack. The name was created as a contrast to harpsichord, a musical instrument that does not allow variation in volume; compared to the harpsichord, the first fortepianos in the 1700s had a quieter sound and smaller dynamic range.

![Bösendorfer Moor](/static/piano/chris-maene-cm284-concert-grand-00.jpg)
![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-00.jpg)

A piano usually has a protective wooden case surrounding the soundboard and metal strings, which are strung under great tension on a heavy metal frame. Pressing one or more keys on the piano's keyboard causes a wooden or plastic hammer (typically padded with firm felt) to strike the strings. The hammer rebounds from the strings, and the strings continue to vibrate at their resonant frequency. These vibrations are transmitted through a bridge to a soundboard that amplifies by more efficiently coupling the acoustic energy to the air. When the key is released, a damper stops the strings' vibration, ending the sound. Notes can be sustained, even when the keys are released by the fingers and thumbs, by the use of pedals at the base of the instrument. The sustain pedal enables pianists to play musical passages that would otherwise be impossible, such as sounding a 10-note chord in the lower register and then, while this chord is being continued with the sustain pedal, shifting both hands to the treble range to play a melody and arpeggios over the top of this sustained chord. Unlike the pipe organ and harpsichord, two major keyboard instruments widely used before the piano, the piano allows gradations of volume and tone according to how forcefully or softly a performer presses or strikes the keys.

![Bösendorfer Moor](/static/piano/grotrian-duo-double-grand.jpg)
![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-01.jpg)

Most modern pianos have a row of 88 black and white keys, 52 white keys for the notes of the C major scale (C, D, E, F, G, A and B) and 36 shorter black keys, which are raised above the white keys, and set further back on the keyboard. This means that the piano can play 88 different pitches (or "notes"), going from the deepest bass range to the highest treble. The black keys are for the "accidentals" (F♯/G♭, G♯/A♭, A♯/B♭, C♯/D♭, and D♯/E♭), which are needed to play in all twelve keys. More rarely, some pianos have additional keys (which require additional strings), an example of which is the Bösendorfer Concert Grand 290 Imperial, which has 97 keys. Most notes have three strings, except for the bass, which graduates from one to two. The strings are sounded when keys are pressed or struck, and silenced by dampers when the hands are lifted from the keyboard. Although an acoustic piano has strings, it is usually classified as a percussion instrument rather than as a stringed instrument, because the strings are struck rather than plucked (as with a harpsichord or spinet); in the Hornbostel–Sachs system of instrument classification, pianos are considered chordophones. There are two main types of piano: the grand piano and the upright piano. The grand piano has a better sound and gives the player a more precise control of the keys, and is therefore the preferred choice for every situation in which the available floor-space and the budget will allow, as well as often being considered a requirement in venues where skilled pianists will frequently give public performances. The upright piano, which necessarily involves some compromise in both tone and key action compared to a grand piano of equivalent quality, is nevertheless much more widely used, because it occupies less space (allowing it to fit comfortably in a room where a grand piano would be too large) and is significantly less expensive.

![Bösendorfer Moor](/static/piano/grotrian-steinweg-double-grand-00.jpg)
![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-02.jpg)

During the 1800s, influenced by the musical trends of the Romantic music era, innovations such as the cast iron frame (which allowed much greater string tensions) and aliquot stringing gave grand pianos a more powerful sound, with a longer sustain and richer tone. In the nineteenth century, a family's piano played the same role that a radio or phonograph played in the twentieth century; when a nineteenth-century family wanted to hear a newly published musical piece or symphony, they could hear it by having a family member play a simplified version on the piano. During the nineteenth century, music publishers produced many types of musical works (symphonies, opera overtures, waltzes, etc.) in arrangements for piano, so that music lovers could play and hear the popular pieces of the day in their home. The piano is widely employed in classical, jazz, traditional and popular music for solo and ensemble performances, accompaniment, and for composing, songwriting and rehearsals. Although the piano is very heavy and thus not portable and is expensive (in comparison with other widely used accompaniment instruments, such as the acoustic guitar), its musical versatility (i.e., its wide pitch range, ability to play chords, louder or softer notes and two or more independent musical lines at the same time), the large number of musicians - both amateurs and professionals - trained in playing it, and its wide availability in performance venues, schools and rehearsal spaces have made it one of the Western world's most familiar musical instruments.`}
</ReactMarkdown>
</LeftSidebarWithMenu.ContentContainer>
</LeftSidebarWithMenu.Layout>
)
</ReactMarkdown>
</Layouts.LeftSidebarWithMenu.MainContentContainer>
</Layouts.LeftSidebarWithMenu.Root>
)
}

const root = document.createElement('div')

ReactDOM.render(<Page />, root);
export default LeftSidebarWithMenuLayoutPage

document.body.appendChild(root);
export const getServerSideProps: GetServerSideProps = async (ctx) => {
return {
props: {
open: ctx.query.open ?? null,
}
}
}

example/layouts/left-sidebar-2/index.tsx → packages/kitchen-sink/react-next/src/pages/layouts/left-sidebar.tsx 查看文件

@@ -1,167 +1,136 @@
import * as React from 'react'
import * as ReactDOM from 'react-dom';
import type { NextPage } from 'next'
import { Layouts, Widgets } from '@tesseract-design/viewfinder-react';
import {Span} from '@tesseract-design/viewfinder-base';
import Link from 'next/link';
import {Brand} from '../../components/Brand';
import {Image} from '../../components/Image';
import ReactMarkdown from 'react-markdown';
import Brand from '../../components/Brand';
import { LeftSidebarWithMenu } from '../../..';
import {GetServerSideProps} from 'next';

const Page = () => {
const [sidebarMainOpen, setSidebarMainOpen] = React.useState(location.hash === '#sidebar')
const [moreItemsOpen, setMoreItemsOpen] = React.useState(location.hash === '#more')

React.useEffect(() => {
const handleHashChange = () => {
setSidebarMainOpen(location.hash === '#sidebar')
setMoreItemsOpen(location.hash === '#more')
}

window.addEventListener('hashchange', handleHashChange)
return () => {
window.removeEventListener('hashchange', handleHashChange)
}
}, [])

return (
<LeftSidebarWithMenu.Layout
moreItemsOpen={moreItemsOpen}
sidebarMenuItems={[
{
id: 'foo',
icon: 'F',
label: 'Foo',
url: '#foo',
},
{
id: 'bar',
icon: 'B',
label: 'Bar',
url: '#bar',
},
{
id: 'baz',
icon: 'Z',
label: 'Baz',
url: '#baz',
},
{
id: 'quux',
icon: 'Q',
label: 'Quux',
url: '#quux',
},
{
id: 'quuux',
icon: 'U',
label: 'Quuux',
url: '#quuux',
secondary: true,
},
{
id: 'quuuux',
icon: 'X',
label: 'Quuuux',
url: '#quuuux',
secondary: true,
},
]}
moreLinkMenuItem={{
url: '#more',
icon: 'M',
label: 'More',
}}
linkComponent={({
url,
icon,
label,
}) => (
<a
href={url}
>
<LeftSidebarWithMenu.SidebarMenuContainer>
<LeftSidebarWithMenu.SidebarMenuItemIcon>
{icon}
</LeftSidebarWithMenu.SidebarMenuItemIcon>
{label}
</LeftSidebarWithMenu.SidebarMenuContainer>
</a>
)}
moreLinkComponent={({
url,
icon,
label,
}) => (
<a
href={url}
>
<LeftSidebarWithMenu.MoreSidebarMenuContainer>
<LeftSidebarWithMenu.MoreSidebarMenuItemIcon>
{icon}
</LeftSidebarWithMenu.MoreSidebarMenuItemIcon>
{label}
</LeftSidebarWithMenu.MoreSidebarMenuContainer>
</a>
)}
brand={
<Brand />
}
menuLink={
<a
href="#sidebar"
>
Menu
</a>
}
userLink={
<a
href="#user"
>
User
</a>
}
>
<LeftSidebarWithMenu.ContentContainer>
<ReactMarkdown
components={{
img: ({ src, alt, style, }) => (
<img
src={src}
alt={alt}
style={{
...style,
width: '100%',
}}
/>
)
}}
>
{`# Piano
type LeftSidebarLayoutPageProps = {
open: string | null;
}

![Bechstein Moor](/static/piano/chris-maene-cm228-parlor-grand-00.jpg)
const LeftSidebarLayoutPage: NextPage<LeftSidebarLayoutPageProps> = ({
open,
}) => {
const sidebarOpen = open === 'sidebar';

return (
<Layouts.LeftSidebar.Root
sidebarBaseWidget={
<Widgets.LeftSidebarBase
span={Span.WIDE}
open={sidebarOpen}
>
<a
href="#foo"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<Layouts.LeftSidebar.SidebarContentContainer>
Foo
</Layouts.LeftSidebar.SidebarContentContainer>
</a>
<a
href="#bar"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<Layouts.LeftSidebar.SidebarContentContainer>
Bar
</Layouts.LeftSidebar.SidebarContentContainer>
</a>
<a
href="#baz"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<Layouts.LeftSidebar.SidebarContentContainer>
Baz
</Layouts.LeftSidebar.SidebarContentContainer>
</a>
</Widgets.LeftSidebarBase>
}
topBarWidget={
<Widgets.TopBar
brand={
<Brand />
}
menuLink={
<Link
href={{
query: {
open: 'sidebar',
},
}}
>
Menu
</Link>
}
userLink={
<Link
href={{
query: {
open: 'sidebar',
},
}}
>
User
</Link>
}
span={Span.WIDE}
/>
}
>
<Layouts.LeftSidebar.MainContentContainer>
<ReactMarkdown
components={{
img: Image,
}}
>
{`# Piano

![Bechstein Moor](/static/piano/bechstein-moor-grand-00.jpg)

The piano is an acoustic, stringed musical instrument invented in Italy by Bartolomeo Cristofori around the year 1700 (the exact year is uncertain), in which the strings are struck by wooden hammers that are coated with a softer material (modern hammers are covered with dense wool felt; some early pianos used leather). It is played using a keyboard, which is a row of keys (small levers) that the performer presses down or strikes with the fingers and thumbs of both hands to cause the hammers to strike the strings.

![Bechstein Moor](/static/piano/chris-maene-cm250-chamber-concert-grand-00.jpg)
![Bechstein Moor](/static/piano/bechstein-moor-grand-01.jpg)

The word piano is a shortened form of pianoforte, the Italian term for the early 1700s versions of the instrument, which in turn derives from gravicembalo col piano e forte (key cymbal with quieter and louder) and fortepiano. The Italian musical terms piano and forte indicate "soft" and "loud" respectively, in this context referring to the variations in volume (i.e., loudness) produced in response to a pianist's touch or pressure on the keys: the greater the velocity of a key press, the greater the force of the hammer hitting the strings, and the louder the sound of the note produced and the stronger the attack. The name was created as a contrast to harpsichord, a musical instrument that does not allow variation in volume; compared to the harpsichord, the first fortepianos in the 1700s had a quieter sound and smaller dynamic range.

![Bösendorfer Moor](/static/piano/chris-maene-cm284-concert-grand-00.jpg)
![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-00.jpg)

A piano usually has a protective wooden case surrounding the soundboard and metal strings, which are strung under great tension on a heavy metal frame. Pressing one or more keys on the piano's keyboard causes a wooden or plastic hammer (typically padded with firm felt) to strike the strings. The hammer rebounds from the strings, and the strings continue to vibrate at their resonant frequency. These vibrations are transmitted through a bridge to a soundboard that amplifies by more efficiently coupling the acoustic energy to the air. When the key is released, a damper stops the strings' vibration, ending the sound. Notes can be sustained, even when the keys are released by the fingers and thumbs, by the use of pedals at the base of the instrument. The sustain pedal enables pianists to play musical passages that would otherwise be impossible, such as sounding a 10-note chord in the lower register and then, while this chord is being continued with the sustain pedal, shifting both hands to the treble range to play a melody and arpeggios over the top of this sustained chord. Unlike the pipe organ and harpsichord, two major keyboard instruments widely used before the piano, the piano allows gradations of volume and tone according to how forcefully or softly a performer presses or strikes the keys.

![Bösendorfer Moor](/static/piano/grotrian-duo-double-grand.jpg)
![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-01.jpg)

Most modern pianos have a row of 88 black and white keys, 52 white keys for the notes of the C major scale (C, D, E, F, G, A and B) and 36 shorter black keys, which are raised above the white keys, and set further back on the keyboard. This means that the piano can play 88 different pitches (or "notes"), going from the deepest bass range to the highest treble. The black keys are for the "accidentals" (F♯/G♭, G♯/A♭, A♯/B♭, C♯/D♭, and D♯/E♭), which are needed to play in all twelve keys. More rarely, some pianos have additional keys (which require additional strings), an example of which is the Bösendorfer Concert Grand 290 Imperial, which has 97 keys. Most notes have three strings, except for the bass, which graduates from one to two. The strings are sounded when keys are pressed or struck, and silenced by dampers when the hands are lifted from the keyboard. Although an acoustic piano has strings, it is usually classified as a percussion instrument rather than as a stringed instrument, because the strings are struck rather than plucked (as with a harpsichord or spinet); in the Hornbostel–Sachs system of instrument classification, pianos are considered chordophones. There are two main types of piano: the grand piano and the upright piano. The grand piano has a better sound and gives the player a more precise control of the keys, and is therefore the preferred choice for every situation in which the available floor-space and the budget will allow, as well as often being considered a requirement in venues where skilled pianists will frequently give public performances. The upright piano, which necessarily involves some compromise in both tone and key action compared to a grand piano of equivalent quality, is nevertheless much more widely used, because it occupies less space (allowing it to fit comfortably in a room where a grand piano would be too large) and is significantly less expensive.

![Bösendorfer Moor](/static/piano/grotrian-steinweg-double-grand-00.jpg)
![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-02.jpg)

During the 1800s, influenced by the musical trends of the Romantic music era, innovations such as the cast iron frame (which allowed much greater string tensions) and aliquot stringing gave grand pianos a more powerful sound, with a longer sustain and richer tone. In the nineteenth century, a family's piano played the same role that a radio or phonograph played in the twentieth century; when a nineteenth-century family wanted to hear a newly published musical piece or symphony, they could hear it by having a family member play a simplified version on the piano. During the nineteenth century, music publishers produced many types of musical works (symphonies, opera overtures, waltzes, etc.) in arrangements for piano, so that music lovers could play and hear the popular pieces of the day in their home. The piano is widely employed in classical, jazz, traditional and popular music for solo and ensemble performances, accompaniment, and for composing, songwriting and rehearsals. Although the piano is very heavy and thus not portable and is expensive (in comparison with other widely used accompaniment instruments, such as the acoustic guitar), its musical versatility (i.e., its wide pitch range, ability to play chords, louder or softer notes and two or more independent musical lines at the same time), the large number of musicians - both amateurs and professionals - trained in playing it, and its wide availability in performance venues, schools and rehearsal spaces have made it one of the Western world's most familiar musical instruments.`}
</ReactMarkdown>
</LeftSidebarWithMenu.ContentContainer>
</LeftSidebarWithMenu.Layout>
)
</ReactMarkdown>
</Layouts.LeftSidebar.MainContentContainer>
</Layouts.LeftSidebar.Root>
)
}

const root = document.createElement('div')

ReactDOM.render(<Page />, root);
export default LeftSidebarLayoutPage

document.body.appendChild(root);
export const getServerSideProps: GetServerSideProps = async (ctx) => {
return {
props: {
open: ctx.query.open ?? null,
}
}
}

+ 199
- 0
packages/kitchen-sink/react-next/src/pages/layouts/left-sidebar/alternate.tsx 查看文件

@@ -0,0 +1,199 @@
import type { NextPage } from 'next'
import { Layouts, Widgets } from '@tesseract-design/viewfinder-react';
import {Span} from '@tesseract-design/viewfinder-base';
import Link from 'next/link';
import {Brand} from '../../../components/Brand';
import {GetServerSideProps} from 'next';
import {FC, ReactNode} from 'react';
import {Image} from '../../../components/Image';
import ReactMarkdown from 'react-markdown';

type LeftSidebarWithMenuLayoutPageProps = {
open: string | null;
}

type LinkComponentProps = {
url: string;
label: string;
icon: ReactNode;
}

const LinkComponent: FC<LinkComponentProps> = ({
url,
label,
icon,
}) => (
<Link
href={url}
passHref
>
<a>
<Layouts.LeftSidebarWithMenu.SidebarMenuContainer>
<Layouts.LeftSidebarWithMenu.SidebarMenuItemIcon>
{icon}
</Layouts.LeftSidebarWithMenu.SidebarMenuItemIcon>
{label}
</Layouts.LeftSidebarWithMenu.SidebarMenuContainer>
</a>
</Link>
)

const MoreLinkComponent: FC<LinkComponentProps> = ({
url,
label,
icon,
}) => (
<Link
href={url}
passHref
>
<a>
<Layouts.LeftSidebarWithMenu.MoreSidebarMenuContainer>
<Layouts.LeftSidebarWithMenu.MoreSidebarMenuItemIcon>
{icon}
</Layouts.LeftSidebarWithMenu.MoreSidebarMenuItemIcon>
{label}
</Layouts.LeftSidebarWithMenu.MoreSidebarMenuContainer>
</a>
</Link>
)

const LeftSidebarWithMenuLayoutPage: NextPage<LeftSidebarWithMenuLayoutPageProps> = ({
open,
}) => {
const sidebarOpen = open === 'sidebar';
const moreItemsOpen = open === 'more';

return (
<Layouts.LeftSidebarWithMenu.Root
sidebarBaseWidget={
<Widgets.LeftSidebarWithMenuBase
span={Span.WIDE}
open={sidebarOpen}
moreItemsOpen={moreItemsOpen}
items={[
{
id: 'foo',
icon: 'F',
label: 'Foo',
url: '#foo',
},
{
id: 'bar',
icon: 'B',
label: 'Bar',
url: '#bar',
},
{
id: 'baz',
icon: 'Z',
label: 'Baz',
url: '#baz',
},
{
id: 'quux',
icon: 'Q',
label: 'Quux',
url: '#quux',
},
{
id: 'quuux',
icon: 'U',
label: 'Quuux',
url: '#quuux',
secondary: true,
},
{
id: 'quuuux',
icon: 'X',
label: 'Quuuux',
url: '#quuuux',
secondary: true,
},
]}
linkComponent={LinkComponent}
moreLinkItem={{
url: {
query: {
open: 'more',
},
},
icon: 'M',
label: 'More',
}}
moreLinkComponent={MoreLinkComponent}
/>
}
topBarWidget={
<Widgets.TopBar
brand={
<Brand />
}
menuLink={
<Link
href={{
query: {
open: 'sidebar',
},
}}
>
Menu
</Link>
}
userLink={
<Link
href={{
query: {
open: 'sidebar',
},
}}
>
User
</Link>
}
span={Span.WIDE}
/>
}
>
<Layouts.LeftSidebarWithMenu.MainContentContainer>
<ReactMarkdown
components={{
img: Image,
}}
>
{`# Piano

![Bechstein Moor](/static/piano/bechstein-moor-grand-00.jpg)

The piano is an acoustic, stringed musical instrument invented in Italy by Bartolomeo Cristofori around the year 1700 (the exact year is uncertain), in which the strings are struck by wooden hammers that are coated with a softer material (modern hammers are covered with dense wool felt; some early pianos used leather). It is played using a keyboard, which is a row of keys (small levers) that the performer presses down or strikes with the fingers and thumbs of both hands to cause the hammers to strike the strings.

![Bechstein Moor](/static/piano/bechstein-moor-grand-01.jpg)

The word piano is a shortened form of pianoforte, the Italian term for the early 1700s versions of the instrument, which in turn derives from gravicembalo col piano e forte (key cymbal with quieter and louder) and fortepiano. The Italian musical terms piano and forte indicate "soft" and "loud" respectively, in this context referring to the variations in volume (i.e., loudness) produced in response to a pianist's touch or pressure on the keys: the greater the velocity of a key press, the greater the force of the hammer hitting the strings, and the louder the sound of the note produced and the stronger the attack. The name was created as a contrast to harpsichord, a musical instrument that does not allow variation in volume; compared to the harpsichord, the first fortepianos in the 1700s had a quieter sound and smaller dynamic range.

![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-00.jpg)

A piano usually has a protective wooden case surrounding the soundboard and metal strings, which are strung under great tension on a heavy metal frame. Pressing one or more keys on the piano's keyboard causes a wooden or plastic hammer (typically padded with firm felt) to strike the strings. The hammer rebounds from the strings, and the strings continue to vibrate at their resonant frequency. These vibrations are transmitted through a bridge to a soundboard that amplifies by more efficiently coupling the acoustic energy to the air. When the key is released, a damper stops the strings' vibration, ending the sound. Notes can be sustained, even when the keys are released by the fingers and thumbs, by the use of pedals at the base of the instrument. The sustain pedal enables pianists to play musical passages that would otherwise be impossible, such as sounding a 10-note chord in the lower register and then, while this chord is being continued with the sustain pedal, shifting both hands to the treble range to play a melody and arpeggios over the top of this sustained chord. Unlike the pipe organ and harpsichord, two major keyboard instruments widely used before the piano, the piano allows gradations of volume and tone according to how forcefully or softly a performer presses or strikes the keys.

![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-01.jpg)

Most modern pianos have a row of 88 black and white keys, 52 white keys for the notes of the C major scale (C, D, E, F, G, A and B) and 36 shorter black keys, which are raised above the white keys, and set further back on the keyboard. This means that the piano can play 88 different pitches (or "notes"), going from the deepest bass range to the highest treble. The black keys are for the "accidentals" (F♯/G♭, G♯/A♭, A♯/B♭, C♯/D♭, and D♯/E♭), which are needed to play in all twelve keys. More rarely, some pianos have additional keys (which require additional strings), an example of which is the Bösendorfer Concert Grand 290 Imperial, which has 97 keys. Most notes have three strings, except for the bass, which graduates from one to two. The strings are sounded when keys are pressed or struck, and silenced by dampers when the hands are lifted from the keyboard. Although an acoustic piano has strings, it is usually classified as a percussion instrument rather than as a stringed instrument, because the strings are struck rather than plucked (as with a harpsichord or spinet); in the Hornbostel–Sachs system of instrument classification, pianos are considered chordophones. There are two main types of piano: the grand piano and the upright piano. The grand piano has a better sound and gives the player a more precise control of the keys, and is therefore the preferred choice for every situation in which the available floor-space and the budget will allow, as well as often being considered a requirement in venues where skilled pianists will frequently give public performances. The upright piano, which necessarily involves some compromise in both tone and key action compared to a grand piano of equivalent quality, is nevertheless much more widely used, because it occupies less space (allowing it to fit comfortably in a room where a grand piano would be too large) and is significantly less expensive.

![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-02.jpg)

During the 1800s, influenced by the musical trends of the Romantic music era, innovations such as the cast iron frame (which allowed much greater string tensions) and aliquot stringing gave grand pianos a more powerful sound, with a longer sustain and richer tone. In the nineteenth century, a family's piano played the same role that a radio or phonograph played in the twentieth century; when a nineteenth-century family wanted to hear a newly published musical piece or symphony, they could hear it by having a family member play a simplified version on the piano. During the nineteenth century, music publishers produced many types of musical works (symphonies, opera overtures, waltzes, etc.) in arrangements for piano, so that music lovers could play and hear the popular pieces of the day in their home. The piano is widely employed in classical, jazz, traditional and popular music for solo and ensemble performances, accompaniment, and for composing, songwriting and rehearsals. Although the piano is very heavy and thus not portable and is expensive (in comparison with other widely used accompaniment instruments, such as the acoustic guitar), its musical versatility (i.e., its wide pitch range, ability to play chords, louder or softer notes and two or more independent musical lines at the same time), the large number of musicians - both amateurs and professionals - trained in playing it, and its wide availability in performance venues, schools and rehearsal spaces have made it one of the Western world's most familiar musical instruments.`}
</ReactMarkdown>
</Layouts.LeftSidebarWithMenu.MainContentContainer>
</Layouts.LeftSidebarWithMenu.Root>
)
}

export default LeftSidebarWithMenuLayoutPage

export const getServerSideProps: GetServerSideProps = async (ctx) => {
return {
props: {
open: ctx.query.open ?? null,
}
}
}

example/layouts/left-sidebar/index.tsx → packages/kitchen-sink/react-next/src/pages/layouts/right-sidebar-static.tsx 查看文件

@@ -1,144 +1,107 @@
import * as React from 'react'
import * as ReactDOM from 'react-dom';
import type { NextPage } from 'next'
import { Layouts, Widgets } from '@tesseract-design/viewfinder-react';
import {Span} from '@tesseract-design/viewfinder-base';
import {Brand} from '../../components/Brand';
import {Image} from '../../components/Image';
import ReactMarkdown from 'react-markdown';
import styled from 'styled-components';
import Brand from '../../components/Brand';
import { LeftSidebar } from '../../..';

const SidebarMainComponent = styled('div')({
'::after': {
content: "''",
position: 'absolute',
top: 0,
right: 0,
height: '100%',
width: '0.0625rem',
backgroundColor: 'currentcolor',
opacity: 0.5,
pointerEvents: 'none',
}
})

const Page = () => {
const [sidebarMainOpen, setSidebarMainOpen] = React.useState(location.hash === '#sidebar')

React.useEffect(() => {
const handleHashChange = () => {
setSidebarMainOpen(location.hash === '#sidebar')
}

window.addEventListener('hashchange', handleHashChange)
return () => {
window.removeEventListener('hashchange', handleHashChange)
}
}, [])

return (
<LeftSidebar.Layout
brand={
<Brand />
}
sidebarMainOpen={sidebarMainOpen}
menuLink={
<a
href="#sidebar"
>
Menu
</a>
}
userLink={
<a
href="#user"
>
User
</a>
}
sidebarMain={
<>
<a
href="#foo"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<LeftSidebar.SidebarMainContainer>
Foo
</LeftSidebar.SidebarMainContainer>
</a>
<a
href="#bar"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<LeftSidebar.SidebarMainContainer>
Bar
</LeftSidebar.SidebarMainContainer>
</a>
<a
href="#baz"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<LeftSidebar.SidebarMainContainer>
Baz
</LeftSidebar.SidebarMainContainer>
</a>
</>
}
sidebarMainComponent={SidebarMainComponent}
>
<LeftSidebar.ContentContainer>
<ReactMarkdown
components={{
img: ({ src, alt, style, }) => (
<img
src={src}
alt={alt}
style={{
...style,
width: '100%',
}}
/>
)
}}
>
{`# Piano

![Bechstein Moor](/static/piano/chris-maene-cm228-parlor-grand-00.jpg)
import Link from 'next/link';

const RightSidebarStaticLayoutPage: NextPage = () => {
return (
<Layouts.RightSidebarStatic.Root
sidebarBaseWidget={
<Widgets.RightSidebarStaticBase
span={Span.WIDE}
>
<a
href="#foo"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<Layouts.RightSidebarStatic.SidebarContentContainer>
Foo
</Layouts.RightSidebarStatic.SidebarContentContainer>
</a>
<a
href="#bar"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<Layouts.RightSidebarStatic.SidebarContentContainer>
Bar
</Layouts.RightSidebarStatic.SidebarContentContainer>
</a>
<a
href="#baz"
style={{
display: 'flex',
alignItems: 'center',
height: '3rem',
}}
>
<Layouts.RightSidebarStatic.SidebarContentContainer>
Baz
</Layouts.RightSidebarStatic.SidebarContentContainer>
</a>
</Widgets.RightSidebarStaticBase>
}
topBarWidget={
<Widgets.TopBar
brand={
<Brand />
}
userLink={
<Link
href={{
query: {
open: 'sidebar',
},
}}
>
User
</Link>
}
span={Span.WIDE}
/>
}
>
<Layouts.RightSidebarStatic.MainContentContainer>
<ReactMarkdown
components={{
img: Image,
}}
>
{`# Piano

![Bechstein Moor](/static/piano/bechstein-moor-grand-00.jpg)

The piano is an acoustic, stringed musical instrument invented in Italy by Bartolomeo Cristofori around the year 1700 (the exact year is uncertain), in which the strings are struck by wooden hammers that are coated with a softer material (modern hammers are covered with dense wool felt; some early pianos used leather). It is played using a keyboard, which is a row of keys (small levers) that the performer presses down or strikes with the fingers and thumbs of both hands to cause the hammers to strike the strings.

![Bechstein Moor](/static/piano/chris-maene-cm250-chamber-concert-grand-00.jpg)
![Bechstein Moor](/static/piano/bechstein-moor-grand-01.jpg)

The word piano is a shortened form of pianoforte, the Italian term for the early 1700s versions of the instrument, which in turn derives from gravicembalo col piano e forte (key cymbal with quieter and louder) and fortepiano. The Italian musical terms piano and forte indicate "soft" and "loud" respectively, in this context referring to the variations in volume (i.e., loudness) produced in response to a pianist's touch or pressure on the keys: the greater the velocity of a key press, the greater the force of the hammer hitting the strings, and the louder the sound of the note produced and the stronger the attack. The name was created as a contrast to harpsichord, a musical instrument that does not allow variation in volume; compared to the harpsichord, the first fortepianos in the 1700s had a quieter sound and smaller dynamic range.

![Bösendorfer Moor](/static/piano/chris-maene-cm284-concert-grand-00.jpg)
![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-00.jpg)

A piano usually has a protective wooden case surrounding the soundboard and metal strings, which are strung under great tension on a heavy metal frame. Pressing one or more keys on the piano's keyboard causes a wooden or plastic hammer (typically padded with firm felt) to strike the strings. The hammer rebounds from the strings, and the strings continue to vibrate at their resonant frequency. These vibrations are transmitted through a bridge to a soundboard that amplifies by more efficiently coupling the acoustic energy to the air. When the key is released, a damper stops the strings' vibration, ending the sound. Notes can be sustained, even when the keys are released by the fingers and thumbs, by the use of pedals at the base of the instrument. The sustain pedal enables pianists to play musical passages that would otherwise be impossible, such as sounding a 10-note chord in the lower register and then, while this chord is being continued with the sustain pedal, shifting both hands to the treble range to play a melody and arpeggios over the top of this sustained chord. Unlike the pipe organ and harpsichord, two major keyboard instruments widely used before the piano, the piano allows gradations of volume and tone according to how forcefully or softly a performer presses or strikes the keys.

![Bösendorfer Moor](/static/piano/grotrian-duo-double-grand.jpg)
![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-01.jpg)

Most modern pianos have a row of 88 black and white keys, 52 white keys for the notes of the C major scale (C, D, E, F, G, A and B) and 36 shorter black keys, which are raised above the white keys, and set further back on the keyboard. This means that the piano can play 88 different pitches (or "notes"), going from the deepest bass range to the highest treble. The black keys are for the "accidentals" (F♯/G♭, G♯/A♭, A♯/B♭, C♯/D♭, and D♯/E♭), which are needed to play in all twelve keys. More rarely, some pianos have additional keys (which require additional strings), an example of which is the Bösendorfer Concert Grand 290 Imperial, which has 97 keys. Most notes have three strings, except for the bass, which graduates from one to two. The strings are sounded when keys are pressed or struck, and silenced by dampers when the hands are lifted from the keyboard. Although an acoustic piano has strings, it is usually classified as a percussion instrument rather than as a stringed instrument, because the strings are struck rather than plucked (as with a harpsichord or spinet); in the Hornbostel–Sachs system of instrument classification, pianos are considered chordophones. There are two main types of piano: the grand piano and the upright piano. The grand piano has a better sound and gives the player a more precise control of the keys, and is therefore the preferred choice for every situation in which the available floor-space and the budget will allow, as well as often being considered a requirement in venues where skilled pianists will frequently give public performances. The upright piano, which necessarily involves some compromise in both tone and key action compared to a grand piano of equivalent quality, is nevertheless much more widely used, because it occupies less space (allowing it to fit comfortably in a room where a grand piano would be too large) and is significantly less expensive.

![Bösendorfer Moor](/static/piano/grotrian-steinweg-double-grand-00.jpg)
![Bösendorfer Moor](/static/piano/boesendorfer-moor-grand-02.jpg)

During the 1800s, influenced by the musical trends of the Romantic music era, innovations such as the cast iron frame (which allowed much greater string tensions) and aliquot stringing gave grand pianos a more powerful sound, with a longer sustain and richer tone. In the nineteenth century, a family's piano played the same role that a radio or phonograph played in the twentieth century; when a nineteenth-century family wanted to hear a newly published musical piece or symphony, they could hear it by having a family member play a simplified version on the piano. During the nineteenth century, music publishers produced many types of musical works (symphonies, opera overtures, waltzes, etc.) in arrangements for piano, so that music lovers could play and hear the popular pieces of the day in their home. The piano is widely employed in classical, jazz, traditional and popular music for solo and ensemble performances, accompaniment, and for composing, songwriting and rehearsals. Although the piano is very heavy and thus not portable and is expensive (in comparison with other widely used accompaniment instruments, such as the acoustic guitar), its musical versatility (i.e., its wide pitch range, ability to play chords, louder or softer notes and two or more independent musical lines at the same time), the large number of musicians - both amateurs and professionals - trained in playing it, and its wide availability in performance venues, schools and rehearsal spaces have made it one of the Western world's most familiar musical instruments.`}
</ReactMarkdown>
</LeftSidebar.ContentContainer>
</LeftSidebar.Layout>
)
</ReactMarkdown>
</Layouts.RightSidebarStatic.MainContentContainer>
</Layouts.RightSidebarStatic.Root>
)
}

const root = document.createElement('div')

ReactDOM.render(<Page />, root);

document.body.appendChild(root);
export default RightSidebarStaticLayoutPage

+ 20
- 0
packages/kitchen-sink/react-next/tsconfig.json 查看文件

@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

部分文件因为文件数量过多而无法显示

正在加载...
取消
保存