diff --git a/.circleci/config.yml b/.circleci/config.yml index ab44b7dcb0..125240f0b2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,6 +15,17 @@ aliases: - node_modules key: *cache-key + - &restore-node-modules-cache-website + name: Restore node_modules cache for /website + keys: + - &cache-key-website v1-dependencies-website-{{ checksum "website/package.json" }} + + - &save-node-modules-cache-website + name: Save node_modules cache for /website + paths: + - website/node_modules + key: *cache-key-website + - &default-filters tags: ignore: @@ -47,6 +58,7 @@ commands: steps: - checkout - restore_cache: *restore-node-modules-cache + - restore_cache: *restore-node-modules-cache-website run-graphics-tests: description: "Run graphics tests with specific devicePixelRatio" @@ -82,6 +94,13 @@ jobs: - run: npm install - save_cache: *save-node-modules-cache + install-deps-website: + executor: node12-executor + steps: + - checkout-with-deps + - run: cd website && npm install + - save_cache: *save-node-modules-cache-website + build: executor: node12-executor steps: @@ -222,9 +241,6 @@ jobs: executor: node14-executor steps: - checkout-with-deps - # since deploying website and building/tests are running in parallel it is possible that there is no cached deps yet - # so let's install them to be sure that everything is fine - - run: npm install - run: npm run tsc - run: npm run bundle-dts - run: @@ -274,6 +290,8 @@ workflows: jobs: - install-deps: filters: *default-filters + - install-deps-website: + filters: *default-filters - no-crlf: filters: *default-filters - trailing-lf: @@ -291,6 +309,7 @@ workflows: filters: *default-filters requires: - install-deps + - install-deps-website - markdown: filters: *default-filters requires: @@ -339,8 +358,15 @@ workflows: website: jobs: + - install-deps: + filters: *default-filters + - install-deps-website: + filters: *default-filters - build-docusaurus-website: filters: *default-filters + requires: + - install-deps + - install-deps-website - deploy-docusaurus-website: filters: branches: diff --git a/.eslintrc.js b/.eslintrc.js index 4e1f9aabf9..a5b57f47de 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -56,6 +56,7 @@ module.exports = { }, extends: [ 'eslint:recommended', + 'plugin:react/recommended', ], parserOptions: { ecmaVersion: 2019, @@ -64,7 +65,7 @@ module.exports = { overrides: [ { // rules specific for js files only - files: ['**/*.js', '**/*.md/*.javascript'], + files: ['**/*.js', '**/*.md/*.javascript', '**/*.jsx'], rules: { // enforces no braces where they can be omitted // http://eslint.org/docs/rules/arrow-body-style @@ -387,6 +388,12 @@ module.exports = { ], }, }, + { + files: ['website/src/**/*.tsx'], + rules: { + 'import/no-default-export': 'off', + }, + }, { files: ['dist/typings.d.ts'], parser: '@typescript-eslint/parser', diff --git a/.gitignore b/.gitignore index 53f9515cf5..a91d1f7234 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,6 @@ debug.html /website/.docusaurus /website/.cache-loader /website/.previous-typings-cache/*.d.ts -/website/static/img/lightweight-charts-logo.svg !/src/typings/**/*.d.ts diff --git a/package.json b/package.json index 518fb62cea..b27eeca2aa 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "eslint-plugin-prefer-arrow": "~1.2.1", "eslint-plugin-tsdoc": "~0.2.14", "eslint-plugin-unicorn": "~39.0.0", + "eslint-plugin-react": "~7.28.0", "express": "~4.17.1", "glob": "~7.2.0", "markdown-it": "~12.3.0", diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 5316e1caff..ca70cd1eda 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -21,12 +21,6 @@ const cacheDir = path.resolve(__dirname, './.previous-typings-cache/'); const typedocWatch = process.env.TYPEDOC_WATCH === 'true'; -// copy logo file to static folder so we can refer to it in the config -fs.copyFileSync( - path.resolve(__dirname, '../.github/logo.svg'), - path.resolve(__dirname, 'static/img/lightweight-charts-logo.svg') -); - function downloadTypingsToFile(typingsFilePath, version) { return new Promise((resolve, reject) => { let file; @@ -139,15 +133,7 @@ const config = { navbar: { title: 'Lightweight Charts', logo: { - alt: 'Lightweight Charts Logo', - // please note that there is no such file in static/img folder in git - // but this file will be copied by this config (see above fs.copyFileSync call) - // this is just to avoid duplicating the same files in the repo - // and at the same time to avoid loading files from other domains (like github) - // (loading from other domains might take some time and the page might blink especially while loading images) - src: 'img/lightweight-charts-logo.svg', - width: 48, - height: 32, + src: 'this value is not used because we swizzled the Logo component - see src/theme/Logo', }, items: [ { @@ -181,7 +167,6 @@ const config = { ], }, footer: { - style: 'dark', links: [ { title: 'Docs', diff --git a/website/package.json b/website/package.json index fab324f8f5..d760672744 100644 --- a/website/package.json +++ b/website/package.json @@ -13,11 +13,13 @@ }, "dependencies": { "@docusaurus/core": "2.0.0-beta.13", + "@docusaurus/module-type-aliases": "2.0.0-beta.13", "@docusaurus/preset-classic": "2.0.0-beta.13", "@docusaurus/theme-search-algolia": "2.0.0-beta.13", "@tsconfig/docusaurus": "~1.0.4", "cross-env": "~7.0.3", "docusaurus-plugin-typedoc": "0.16.7", + "lightweight-charts": "~3.7.0", "prism-react-renderer": "~1.2.1", "react": "~17.0.1", "react-dom": "~17.0.1", diff --git a/website/src/css/custom.css b/website/src/css/custom.css index d9e00928c7..804a1eef8d 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -6,23 +6,83 @@ /* You can override the default Infima variables here. */ :root { - --ifm-color-primary: #2962FF; - --ifm-color-primary-dark: #1E53E5; - --ifm-color-primary-darker: #1848CC; - --ifm-color-primary-darkest: #143EB3; - --ifm-color-primary-light: #3179F5; - --ifm-color-primary-lighter: #5B9CF6; - --ifm-color-primary-lightest: #90BFF9; - --ifm-code-font-size: 95%; + --color-white: #ffffff; + --color-black: #000000; + --color-cold-gray-100: #F0F3FA; + --color-cold-gray-150: #E0E3EB; + --color-cold-gray-200: #D1D4DC; + --color-cold-gray-300: #B2B5BE; + --color-cold-gray-500: #787B86; + --color-cold-gray-750: #363A45; + --color-cold-gray-800: #2A2E39; + --color-cold-gray-850: #1E222D; + --color-cold-gray-950: #0C0E15; + --color-tv-blue-200: #90BFF9; + --color-tv-blue-300: #5B9CF6; + --color-tv-blue-400: #3179F5; + --color-tv-blue-500: #2962FF; + --color-tv-blue-600: #1E53E5; + --color-tv-blue-700: #1848CC; + --color-tv-blue-800: #143EB3; + --color-tv-blue-900: #0C3299; + + --ifm-color-primary: var(--color-tv-blue-500); + --ifm-color-primary-dark: var(--color-tv-blue-600); + --ifm-color-primary-darker: var(--color-tv-blue-700); + --ifm-color-primary-darkest: var(--color-tv-blue-800); + --ifm-color-primary-light: var(--color-tv-blue-400); + --ifm-color-primary-lighter: var(--color-tv-blue-300); + --ifm-color-primary-lightest: var(--color-tv-blue-200); + --ifm-code-font-size: 95%; + --ifm-footer-background-color: var(--color-white); + + --small-card-border-color: var(--color-cold-gray-150); + --card-background-color: var(--color-cold-gray-100); + --card-paragraph-color: var(--color-cold-gray-500); + --icon-color: var(--color-black); + --hero-button-text-color: var(--color-black); + --hero-button-hackground-color-hover: var(--color-cold-gray-100); + --hero-text-background-color: #ffffff; + --icon-color: var(--color-black); + --large-card-paragraph-text-color: var(--color-cold-gray-500); +} + +html[data-theme=dark] { + --small-card-border-color: var(--color-cold-gray-850); + --card-background-color: var(--color-cold-gray-950); + --card-paragraph-color: var(--color-cold-gray-300); + --icon-color: var(--color-cold-gray-200); + --hero-button-text-color: var(--color-cold-gray-200); + --hero-button-hackground-color-hover: var(--color-cold-gray-800); + --hero-text-background-color: var(--color-cold-gray-950); + --icon-color: var(--color-white); + --large-card-paragraph-text-color: var(--color-cold-gray-300); + --ifm-navbar-background-color: var(--color-black); + --ifm-footer-background-color: var(--color-black); + --ifm-background-color: var(--color-black); } .docusaurus-highlight-code-line { - background-color: rgba(0, 0, 0, 0.1); - display: block; - margin: 0 calc(-1 * var(--ifm-pre-padding)); - padding: 0 var(--ifm-pre-padding); + background-color: var(--color-black); + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); } html[data-theme='dark'] .docusaurus-highlight-code-line { - background-color: rgba(0, 0, 0, 0.3); + background-color: rgba(0, 0, 0, 0.3); +} + +.navbar__title { + font-size: 1.5rem; +} + +.navbar__brand svg { + --color: var(--icon-color); +} + +.main-wrapper { + display: flex; + justify-content: center; + gap: 2rem; } diff --git a/website/src/img/cog.svg b/website/src/img/cog.svg new file mode 100644 index 0000000000..690731e59c --- /dev/null +++ b/website/src/img/cog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/img/input-sliders.svg b/website/src/img/input-sliders.svg new file mode 100644 index 0000000000..2bcc69812d --- /dev/null +++ b/website/src/img/input-sliders.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/img/logo.svg b/website/src/img/logo.svg new file mode 100644 index 0000000000..2affc3c3d5 --- /dev/null +++ b/website/src/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/img/navbar-logo.svg b/website/src/img/navbar-logo.svg new file mode 100644 index 0000000000..424e8e884a --- /dev/null +++ b/website/src/img/navbar-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/img/paperplane.svg b/website/src/img/paperplane.svg new file mode 100644 index 0000000000..00d8dae68a --- /dev/null +++ b/website/src/img/paperplane.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/img/screens.svg b/website/src/img/screens.svg new file mode 100644 index 0000000000..79878b46c6 --- /dev/null +++ b/website/src/img/screens.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/img/shapes.svg b/website/src/img/shapes.svg new file mode 100644 index 0000000000..99f5b5fd46 --- /dev/null +++ b/website/src/img/shapes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/img/speedometer.svg b/website/src/img/speedometer.svg new file mode 100644 index 0000000000..b1023ca3b5 --- /dev/null +++ b/website/src/img/speedometer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/img/tradingview-heart.svg b/website/src/img/tradingview-heart.svg new file mode 100644 index 0000000000..d22ac7dcd0 --- /dev/null +++ b/website/src/img/tradingview-heart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/pages/hero-chart-data.json b/website/src/pages/hero-chart-data.json new file mode 100644 index 0000000000..2e0920e606 --- /dev/null +++ b/website/src/pages/hero-chart-data.json @@ -0,0 +1,198 @@ +{ + "orangeData": [ + { + "value": 33, + "time": 1628005368 + }, + { + "value": 33.49774076716826, + "time": 1628610168 + }, + { + "value": 33.00544183567645, + "time": 1629214968 + }, + { + "value": 33.7026637942526, + "time": 1629819768 + }, + { + "value": 33.21936886405405, + "time": 1630424568 + }, + { + "value": 33.900609590144896, + "time": 1631029368 + }, + { + "value": 33.17765657755362, + "time": 1631634168 + }, + { + "value": 33.42924174402081, + "time": 1632238968 + }, + { + "value": 33.11836183231501, + "time": 1632843768 + }, + { + "value": 33.370546260351574, + "time": 1633448568 + }, + { + "value": 32.37624709371832, + "time": 1634053368 + }, + { + "value": 32.51457619610796, + "time": 1634658168 + }, + { + "value": 32.289844763651196, + "time": 1635262968 + }, + { + "value": 32.30345180071158, + "time": 1635867768 + }, + { + "value": 31.338699866068282, + "time": 1636472568 + }, + { + "value": 31.599431171640674, + "time": 1637077368 + }, + { + "value": 31.19599059792039, + "time": 1637682168 + }, + { + "value": 31.425624659001333, + "time": 1638286968 + }, + { + "value": 30.687366192207392, + "time": 1638891768 + }, + { + "value": 31.37955209658077, + "time": 1639496568 + }, + { + "value": 30.44272814637675, + "time": 1640101368 + }, + { + "value": 30.443425326447485, + "time": 1640706168 + }, + { + "value": 30.402280371726427, + "time": 1641310968 + }, + { + "value": 31.323860910479432, + "time": 1641915768 + } + ], + "blueData": [ + { + "value": 31, + "time": 1628005368 + }, + { + "value": 31.78679751621187, + "time": 1628610168 + }, + { + "value": 31.73307428969506, + "time": 1629214968 + }, + { + "value": 32.645659569228435, + "time": 1629819768 + }, + { + "value": 32.18589215966293, + "time": 1630424568 + }, + { + "value": 32.36649658122607, + "time": 1631029368 + }, + { + "value": 32.13494929971301, + "time": 1631634168 + }, + { + "value": 32.24176261787218, + "time": 1632238968 + }, + { + "value": 32.23416002963385, + "time": 1632843768 + }, + { + "value": 33.155464487194166, + "time": 1633448568 + }, + { + "value": 32.30858974959849, + "time": 1634053368 + }, + { + "value": 33.240351713622175, + "time": 1634658168 + }, + { + "value": 32.476820033756304, + "time": 1635262968 + }, + { + "value": 33.38322664774607, + "time": 1635867768 + }, + { + "value": 33.112040840762795, + "time": 1636472568 + }, + { + "value": 33.21270434841732, + "time": 1637077368 + }, + { + "value": 32.34952853888793, + "time": 1637682168 + }, + { + "value": 33.309373031504336, + "time": 1638286968 + }, + { + "value": 32.68788509068168, + "time": 1638891768 + }, + { + "value": 32.991148534675084, + "time": 1639496568 + }, + { + "value": 32.019560141931144, + "time": 1640101368 + }, + { + "value": 32.6775781486036, + "time": 1640706168 + }, + { + "value": 31.739487272423506, + "time": 1641310968 + }, + { + "value": 31.957098637385883, + "time": 1641915768 + } + ] +} diff --git a/website/src/pages/index.md b/website/src/pages/index.md deleted file mode 100644 index ab8443600c..0000000000 --- a/website/src/pages/index.md +++ /dev/null @@ -1,6 +0,0 @@ -# Lightweight Charts - -**🚧🚧🚧 THIS PAGE IS UNDER CONSTRUCTION 🚧🚧🚧.** - -- [Docs](/docs) -- [API Reference](/docs/api) diff --git a/website/src/pages/index.module.css b/website/src/pages/index.module.css new file mode 100644 index 0000000000..2c158903e5 --- /dev/null +++ b/website/src/pages/index.module.css @@ -0,0 +1,297 @@ +.HeroContainer { + display: flex; + flex-direction: column; + align-items: center; +} + +.HeroChartContainer { + display: none; +} + +.HeroTextContainer { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding-top: 2rem; +} + +.HeroTextContainer svg { + color: var(--icon-color); +} + +.HeroButtonsContainer { + display: flex; + flex-wrap: wrap; + gap: 1rem; + min-width: 90%; +} + +.HeroButton { + flex: 1 0 100%; + text-align: center; + border-radius: 56px; + padding: 1rem; + font-weight: 600; + border: 1px solid var(--small-card-border-color); + white-space: nowrap; + color: var(--hero-button-text-color); +} + +.HeroButton:hover { + background: var(--hero-button-hackground-color-hover); + color: var(--hero-button-text-color); + text-decoration: none; +} + +.HeroButton:active { + background: rgba(224, 227, 235, 1); +} + +.HeroButtonPrimary { + color: #FFFFFF; + background: #2962FF; +} + +.HeroButtonPrimary:hover { + color: #FFFFFF; + background: rgba(30, 83, 229, 1); + text-decoration: none; +} + +.HeroButtonPrimary:active { + color: #FFFFFF; + background: rgba(24, 72, 204, 1); +} + +.HeroTextContainer h1 { + padding-top: 1rem; + font-size: 2.5rem; +} + +.HeroTextContainer p { + font-size: 1.5rem; +} + +.LargeCardContainer { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 1rem; +} + +.LargeCard { + max-width: 95%; + background: var(--card-background-color); + padding: 2rem 2rem; + border-radius: 1rem; + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.LargeCard h2 { + margin: 0; +} + +.LargeCard p { + color: var(--large-card-paragraph-text-color); +} + +.LargeCard svg { + color: var(--icon-color); +} + +.SmallCardContainer { + display: flex; + justify-content: center; + flex-wrap: wrap; +} + +.SmallCard { + flex: 1 0 auto; + max-width: 95%; + padding: 2rem 1rem; + border: 1px solid var(--small-card-border-color); + border-bottom: none; +} + +.SmallCard1 { + border-top-left-radius: 1rem; + border-top-right-radius: 1rem; +} + +.SmallCard4 { + border-bottom: 1px solid var(--small-card-border-color); + border-bottom-left-radius: 1rem; + border-bottom-right-radius: 1rem; +} + +.SmallCard p { + color: var(--card-paragraph-color); +} + +.LargeTextContainer { + display: flex; + flex-wrap: wrap; + padding-top: 2rem; + padding-left: 1rem; + padding-right: 1rem; + font-weight: 400; +} + +.LargeTextContainer h1 { + text-align: center; + font-size: 2.5rem; +} + +.LargeTextContainer p { + font-size: 1.5rem; + text-align: center; +} + +.RootContainer { + max-width: 98%; + display: flex; + flex-direction: column; + gap: 2rem; + align-items: center; +} + +@media (min-width: 767.5px) { + .HeroButtonsContainer { + min-width: unset; + flex-wrap: unset; + } + + .HeroButton { + flex: 1 1 50%; + padding-left: 2rem; + padding-right: 2rem; + } + + .LargeCard { + flex: 0 1 47%; + } + + .LargeCard3 { + flex: 1 0 100%; + } + + .SmallCard { + flex: 0 1 47%; + } + + .SmallCard1 { + border-top-right-radius: unset; + } + + .SmallCard2 { + border-top-right-radius: 1rem; + border-left: unset; + } + + .SmallCard3 { + border-bottom-left-radius: 1rem; + border-bottom: 1px solid var(--small-card-border-color); + } + + .SmallCard4 { + border-bottom-left-radius: unset; + border-left: unset; + } +} + +@media (min-width: 1279.5px) { + .HeroContainer { + position: relative; + align-self: stretch; + } + + .HeroChartContainer { + display: unset; + /* width: 100%; */ + height: 40vh; + width: 100vw; + } + + .HeroTextContainer { + position: absolute; + z-index: 2; + max-width: 65%; + top: 10%; + left: 10%; + border-radius: 2rem; + align-items: flex-start; + text-align: left; + padding: 3rem; + background: var(--hero-text-background-color); + } + + .LargeTextContainer { + max-width: 75%; + justify-content: center; + } + + .LargeCardContainer { + flex-wrap: nowrap; + } + + .LargeCard, LargeCard3 { + flex: 0 1 30%; + } + + .SmallCardContainer { + flex-wrap: nowrap; + } + + .SmallCard { + flex: 0 1 23%; + } + + .SmallCard1 { + border-top-right-radius: unset; + border-bottom-left-radius: 1rem; + border-bottom: 1px solid var(--small-card-border-color); + } + + .SmallCard2 { + border-top-right-radius: unset; + border-left: unset; + border-bottom: 1px solid var(--small-card-border-color); + } + + .SmallCard3 { + border-bottom-left-radius: unset; + border-left: unset; + border-bottom: 1px solid var(--small-card-border-color); + } + + .SmallCard4 { + border-top-right-radius: 1rem; + border-bottom-left-radius: unset; + border-left: unset; + } +} + +@media (min-width: 1919.5px) { + .HeroTextContainer { + max-width: 43%; + } + + .HeroChartContainer { + height: 50vh; + } + + .LargeTextContainer { + max-width: 77%; + } + + .LargeCardContainer { + max-width: 77%; + } + + .SmallCardContainer { + max-width: 77%; + } +} \ No newline at end of file diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx new file mode 100644 index 0000000000..cf1a641860 --- /dev/null +++ b/website/src/pages/index.tsx @@ -0,0 +1,190 @@ +import useThemeContext from '@theme/hooks/useThemeContext'; +import Layout from '@theme/Layout'; +import { createChart, DeepPartial, IChartApi, LayoutOptions, LineData } from 'lightweight-charts'; +import React from 'react'; + +import Cog from '../img/cog.svg'; +import InputSliders from '../img/input-sliders.svg'; +import Logo from '../img/logo.svg'; +import Paperplane from '../img/paperplane.svg'; +import Screens from '../img/screens.svg'; +import Shapes from '../img/shapes.svg'; +import Speedometer from '../img/speedometer.svg'; +import TradingviewHeart from '../img/tradingview-heart.svg'; +import data from './hero-chart-data.json'; +import styles from './index.module.css'; + +function getLayoutOptionsForTheme(isDarkTheme: boolean): DeepPartial { + return isDarkTheme + ? { background: { color: '#000000' }, textColor: 'rgba(248, 249, 253, 1)' } + : { background: { color: 'rgba(248, 249, 253, 1)' }, textColor: '#000000' }; +} + +function useThemeAwareLayoutOptions(): DeepPartial { + const { isDarkTheme } = useThemeContext(); + + const [layoutOptions, setLayoutOptions] = React.useState>(getLayoutOptionsForTheme(isDarkTheme)); + + React.useEffect( + () => { + setLayoutOptions(getLayoutOptionsForTheme(isDarkTheme)); + }, + [isDarkTheme] + ); + + return layoutOptions; +} + +function HeroChart(): JSX.Element { + const ref = React.useRef(null); + + const layout = useThemeAwareLayoutOptions(); + + const [chart, setChart] = React.useState(null); + + React.useLayoutEffect( + () => { + const container = ref.current; + + if (!container) { + return; + } + + const c = createChart(container, { + layout, + grid: { + horzLines: { + visible: false, + }, + vertLines: { + visible: false, + }, + }, + timeScale: { + fixLeftEdge: true, + fixRightEdge: true, + lockVisibleTimeRangeOnResize: true, + }, + handleScroll: false, + handleScale: false, + }); + + const orangeSeries = c.addAreaSeries({ + lineColor: '#FFE902', + topColor: 'rgba(251, 140, 0, 0.6)', + bottomColor: 'rgba(251, 140, 0, 0.2)', + }); + const blueSeries = c.addAreaSeries({ + lineColor: 'rgba(15, 28, 249, 1)', + topColor: 'rgba(15, 28, 249, 1)', + bottomColor: 'rgba(15, 28, 249, 0.2)', + }); + + orangeSeries.setData(data.orangeData as LineData[]); + blueSeries.setData(data.blueData as LineData[]); + + c.timeScale().setVisibleLogicalRange({ from: 1, to: data.orangeData.length - 2 }); + + const resizeListener = () => { + const { width, height } = container.getBoundingClientRect(); + c.resize(width, height); + }; + + setChart(c); + + window.addEventListener('resize', resizeListener); + + return () => { + window.removeEventListener('resize', resizeListener); + c.remove(); + setChart(null); + }; + }, + [] + ); + + React.useEffect( + () => { + if (!chart) { + return; + } + + chart.applyOptions({ layout }); + }, + [layout] + ); + + return ( +
+ ); +} + +function Index(): JSX.Element { + return
+
+ +
+ +

Lightweight Charts

+

Free, open-source and feature-rich. At just 40 kilobytes, the dream of lightweight interactive charts is now a reality.

+ +
+
+
+

Fully customizable & free charts that don't contain hidden ads

+

Millions of websites still use static pictures for showing financial charts. The old way is not interactive and doesn't scale with various devices. Pictures always had a huge advantage of their small size and fast loading — but no more!

+
+
+
+ +

High Performance

+

Our charting solutions were engineered from the start to work with huge data arrays. Charts stay responsive and nimble even with thousands of bars even with updates multiple times per second with new ticks.

+
+
+ +

Interactive, responsive and mobile-friendly

+

Intelligently adapts to any device. Charts are carefully engineered for best interactivity, both for powerful desktops with a mouse, and touch-optimized for tablets and phones.

+
+
+ +

Finance is at the heart

+

Charting is our core. TradingView charts are used by tens of thousands of websites, apps and financial portals, as well as millions of traders around the world. You can be sure that we've included everything you need, starting from popular chart types to advanced price scaling.

+
+
+
+
+ +

Ultra lightweight - just 40 Kb

+

HTML5 Canvas technology no larger than a standard GIF file.

+
+
+ +

Integrating & connecting any data is quick and easy

+

Built for developers, by developers. Charts are rich in features and easy to integrate — so you can integrate with a breeze.

+
+
+ +

Open-source

+

Fully customizable & free charts that don't contain hidden ads. Contributions are welcome!

+
+
+ +

Flexible styling

+

Change the standard look & feel to match your style with perfection. There are many premade examples that you can copy & paste.

+
+
+
; +} + +function LayoutWrapper(): JSX.Element { + return ( + + + + ); +} + +export default LayoutWrapper; diff --git a/website/src/theme/Logo/index.tsx b/website/src/theme/Logo/index.tsx new file mode 100644 index 0000000000..b7eef8dd7a --- /dev/null +++ b/website/src/theme/Logo/index.tsx @@ -0,0 +1,30 @@ +import Link from '@docusaurus/Link'; +import { useThemeConfig } from '@docusaurus/theme-common'; +import useBaseUrl from '@docusaurus/useBaseUrl'; +import React, { ComponentPropsWithoutRef } from 'react'; + +import LogoSvg from '../../img/navbar-logo.svg'; + +export interface LogoProps extends ComponentPropsWithoutRef<'a'> { + readonly imageClassName?: string; + readonly titleClassName?: string; +} + +function Logo(props: LogoProps): JSX.Element { + const { titleClassName, imageClassName, ...propsRest } = props; + const { + navbar: { + logo = { + src: '', + }, + }, + } = useThemeConfig(); + const logoLink = useBaseUrl(logo.href || '/'); + return ( + + + + ); +} + +export default Logo; diff --git a/website/svgr.config.js b/website/svgr.config.js new file mode 100644 index 0000000000..7c1bc8b8c7 --- /dev/null +++ b/website/svgr.config.js @@ -0,0 +1,3 @@ +module.exports = { + svgo: false, +};