From 97550b534327dd0d1417d64fd5b59bd4f5f0b590 Mon Sep 17 00:00:00 2001 From: Alex Ni <12097569+nialexsan@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:00:36 -0500 Subject: [PATCH 1/7] typesense search --- .github/workflows/scrape.yml | 33 ++++++++ docsearch.config.json | 46 +++++++++++ docusaurus.config.js | 27 +++++++ package-lock.json | 149 +++++++++++++++++++++++++++++++++++ package.json | 1 + 5 files changed, 256 insertions(+) create mode 100644 .github/workflows/scrape.yml create mode 100644 docsearch.config.json diff --git a/.github/workflows/scrape.yml b/.github/workflows/scrape.yml new file mode 100644 index 0000000..a5fbb9c --- /dev/null +++ b/.github/workflows/scrape.yml @@ -0,0 +1,33 @@ +name: DocSearch Scraper + +on: + workflow_dispatch: + +env: + TYPESENSE_NODE: ${{vars.TYPESENSE_NODE}} + TYPESENSE_SEARCH_ONLY_API_KEY: ${{secrets.TYPESENSE_SEARCH_ONLY_API_KEY}} + +jobs: + crawl: + name: Crawl Pages + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Run DocSearch Scraper + uses: celsiusnarhwal/typesense-scraper@v2 + with: + # The secret containing your Typesense API key. Required. + api-key: ${{ secrets.TYPESENSE_ADMIN_API_KEY }} + + # The hostname or IP address of your Typesense server. Required. + host: ${{vars.TYPESENSE_NODE}} + + # The port on which your Typesense server is listening. Optional. Default: 8108. + port: 443 + + # The protocol to use when connecting to your Typesense server. Optional. Default: http. + protocol: https + + # The path to your DocSearch config file. Optional. Default: docsearch.config.json. + config: docsearch.config.json diff --git a/docsearch.config.json b/docsearch.config.json new file mode 100644 index 0000000..d5b427e --- /dev/null +++ b/docsearch.config.json @@ -0,0 +1,46 @@ +{ + "index_name": "cadence_lang", + "start_urls": [ + "https://cadence-lang.org/" + ], + "sitemap_urls": [ + "https://cadence-lang.org/sitemap.xml" + ], + "sitemap_alternate_links": true, + "stop_urls": [ + "/tests" + ], + "selectors": { + "lvl0": { + "selector": "(//ul[contains(@class,'menu__list')]//a[contains(@class, 'menu__link menu__link--sublist menu__link--active')]/text() | //nav[contains(@class, 'navbar')]//a[contains(@class, 'navbar__link--active')]/text())[last()]", + "type": "xpath", + "global": true, + "default_value": "Documentation" + }, + "lvl1": "article h1, header h1", + "lvl2": "article h2", + "lvl3": "article h3", + "lvl4": "article h4", + "lvl5": "article h5, article td:first-child", + "lvl6": "article h6", + "text": "article p, article li, article td:last-child" + }, + "strip_chars": " .,;:#", + "custom_settings": { + "separatorsToIndex": "_", + "attributesForFaceting": [ + "language", + "version", + "type", + "docusaurus_tag" + ], + "attributesToRetrieve": [ + "hierarchy", + "content", + "anchor", + "url", + "url_without_anchor", + "type" + ] + } +} \ No newline at end of file diff --git a/docusaurus.config.js b/docusaurus.config.js index 37def1b..8ff4101 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -7,6 +7,9 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula'); const theme = require('shiki/themes/nord.json'); const { remarkCodeHike } = require('@code-hike/mdx'); +const hasTypesense = + process.env.TYPESENSE_NODE && process.env.TYPESENSE_SEARCH_ONLY_API_KEY; + /** @type {import('@docusaurus/types').Config} */ const config = { title: 'Cadence', @@ -82,6 +85,8 @@ const config = { ], ], + themes: [hasTypesense && 'docusaurus-theme-search-typesense'].filter(Boolean), + themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ @@ -169,6 +174,28 @@ const config = { theme: lightCodeTheme, darkTheme: darkCodeTheme, }, + typesense: hasTypesense && { + // Replace this with the name of your index/collection. + // It should match the "index_name" entry in the scraper's "config.json" file. + typesenseCollectionName: 'cadence_lang', + + typesenseServerConfig: { + nodes: [ + { + host: process.env.TYPESENSE_NODE, + port: 443, + protocol: 'https', + }, + ], + apiKey: process.env.TYPESENSE_SEARCH_ONLY_API_KEY, + }, + + // Optional: Typesense search parameters: https://typesense.org/docs/0.24.0/api/search.html#search-parameters + typesenseSearchParameters: {}, + + // Optional + contextualSearch: true, + }, }), }; diff --git a/package-lock.json b/package-lock.json index 2089df4..a43475f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@docusaurus/preset-classic": "3.0.0", "@mdx-js/react": "^3.0.0", "clsx": "^1.2.1", + "docusaurus-theme-search-typesense": "^0.14.0", "lottie-react": "^2.4.0", "next": "^12.0.7", "prism-react-renderer": "^1.3.5", @@ -5897,6 +5898,49 @@ "node": ">=6" } }, + "node_modules/docusaurus-theme-search-typesense": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/docusaurus-theme-search-typesense/-/docusaurus-theme-search-typesense-0.14.0.tgz", + "integrity": "sha512-ShXZQQaa7h1FvmWvau1EjYqHOHXmHleAd2A3cMW8vHZh4CtiwOux5YbAYr84uvSeR+AshWVpnGZ23swKBep+bw==", + "dependencies": { + "@docusaurus/logger": "3.0.0", + "@docusaurus/plugin-content-docs": "3.0.0", + "@docusaurus/theme-translations": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "algoliasearch-helper": "^3.10.0", + "clsx": "^1.2.1", + "eta": "^2.0.0", + "fs-extra": "^10.1.0", + "lodash": "^4.17.21", + "tslib": "^2.4.0", + "typesense-docsearch-react": "^3.4.1", + "typesense-instantsearch-adapter": "^2.7.1", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@docusaurus/core": "3.0.0", + "@docusaurus/theme-common": "3.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/docusaurus-theme-search-typesense/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -8507,6 +8551,18 @@ "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==" }, + "node_modules/loglevel": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz", + "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -14569,6 +14625,99 @@ "node": ">=14.17" } }, + "node_modules/typesense": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/typesense/-/typesense-1.7.2.tgz", + "integrity": "sha512-hgQESOiyNJq+w2mpRJa/a1UMhWtJ/+sb0p7NoeCDSkikm9sasisJdnc7uhQchM6vTWKw2sMLWUBNbAhItR6zUQ==", + "dependencies": { + "axios": "^0.26.0", + "loglevel": "^1.8.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@babel/runtime": "^7.17.2" + } + }, + "node_modules/typesense-docsearch-css": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/typesense-docsearch-css/-/typesense-docsearch-css-0.4.1.tgz", + "integrity": "sha512-mN8K18pfIpCrhzsMAJBzoS7l/YDcC4P3f9vsScenUceXmC8n3FCPldmF10dKDJmK3Lr7aAScQt70jCA5126y2w==" + }, + "node_modules/typesense-docsearch-react": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/typesense-docsearch-react/-/typesense-docsearch-react-3.4.1.tgz", + "integrity": "sha512-d0PQym/B/p5oP+hfdFEOH6goiKa1JLR63bikZSDGq1+jT2FtuwNrdMGVBZZMNFUsXVsJRA8ULHJpsREmfSJmVw==", + "dependencies": { + "@algolia/autocomplete-core": "1.8.2", + "@algolia/autocomplete-preset-algolia": "1.8.2", + "typesense": "^1.7.2", + "typesense-docsearch-css": "^0.4.1", + "typesense-instantsearch-adapter": "^2.7.1" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/typesense-docsearch-react/node_modules/@algolia/autocomplete-core": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.8.2.tgz", + "integrity": "sha512-mTeshsyFhAqw/ebqNsQpMtbnjr+qVOSKXArEj4K0d7sqc8It1XD0gkASwecm9mF/jlOQ4Z9RNg1HbdA8JPdRwQ==", + "dependencies": { + "@algolia/autocomplete-shared": "1.8.2" + } + }, + "node_modules/typesense-docsearch-react/node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.8.2.tgz", + "integrity": "sha512-J0oTx4me6ZM9kIKPuL3lyU3aB8DEvpVvR6xWmHVROx5rOYJGQcZsdG4ozxwcOyiiu3qxMkIbzntnV1S1VWD8yA==", + "dependencies": { + "@algolia/autocomplete-shared": "1.8.2" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/typesense-docsearch-react/node_modules/@algolia/autocomplete-shared": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.8.2.tgz", + "integrity": "sha512-b6Z/X4MczChMcfhk6kfRmBzPgjoPzuS9KGR4AFsiLulLNRAAqhP+xZTKtMnZGhLuc61I20d5WqlId02AZvcO6g==" + }, + "node_modules/typesense-instantsearch-adapter": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/typesense-instantsearch-adapter/-/typesense-instantsearch-adapter-2.7.1.tgz", + "integrity": "sha512-GSEwkNzXoVcL4iSV/LDiZvjx/knctqfGLLKUNRe5twgzFprnoU07UUh2mQ5Z0/aP1moY/UpBF1bMKhTU6ECoAQ==", + "hasInstallScript": true, + "dependencies": { + "typesense": "^1.7.0" + }, + "peerDependencies": { + "@babel/runtime": "^7.17.2" + } + }, + "node_modules/typesense/node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, "node_modules/ua-parser-js": { "version": "1.0.37", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz", diff --git a/package.json b/package.json index 15e714f..76b364e 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@docusaurus/preset-classic": "3.0.0", "@mdx-js/react": "^3.0.0", "clsx": "^1.2.1", + "docusaurus-theme-search-typesense": "^0.14.0", "lottie-react": "^2.4.0", "prism-react-renderer": "^1.3.5", "react": "^18.2.0", From 3437f942bf7aeef3bd17b8b437beec2f975f4982 Mon Sep 17 00:00:00 2001 From: Alex Ni <12097569+nialexsan@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:22:57 -0500 Subject: [PATCH 2/7] fix gh action env vars --- .github/workflows/scrape.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/scrape.yml b/.github/workflows/scrape.yml index a5fbb9c..b32b6a8 100644 --- a/.github/workflows/scrape.yml +++ b/.github/workflows/scrape.yml @@ -4,8 +4,8 @@ on: workflow_dispatch: env: - TYPESENSE_NODE: ${{vars.TYPESENSE_NODE}} - TYPESENSE_SEARCH_ONLY_API_KEY: ${{secrets.TYPESENSE_SEARCH_ONLY_API_KEY}} + TYPESENSE_NODE: ${{ vars.TYPESENSE_NODE }} + TYPESENSE_ADMIN_API_KEY: ${{secrets.TYPESENSE_ADMIN_API_KEY}} jobs: crawl: @@ -18,10 +18,10 @@ jobs: uses: celsiusnarhwal/typesense-scraper@v2 with: # The secret containing your Typesense API key. Required. - api-key: ${{ secrets.TYPESENSE_ADMIN_API_KEY }} + api-key: ${{ env.TYPESENSE_ADMIN_API_KEY }} # The hostname or IP address of your Typesense server. Required. - host: ${{vars.TYPESENSE_NODE}} + host: ${{ env.TYPESENSE_NODE }} # The port on which your Typesense server is listening. Optional. Default: 8108. port: 443 From a1d8cb09bcbd62e6c138c95e89678d24deb73a83 Mon Sep 17 00:00:00 2001 From: Alex Ni <12097569+nialexsan@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:33:57 -0500 Subject: [PATCH 3/7] test build and scrape --- .github/workflows/deploy.yml | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..929b86e --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,47 @@ +name: Test build & Scrape + +on: + workflow_dispatch: + push: + branches: + - main + +env: + TYPESENSE_NODE: ${{ vars.TYPESENSE_NODE }} + TYPESENSE_ADMIN_API_KEY: ${{ secrets.TYPESENSE_ADMIN_API_KEY }} + +jobs: + build: + name: Test build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + + - name: Install dependencies + run: npm i + + - name: Build website + run: npm run build + + - name: Run DocSearch Scraper + uses: celsiusnarhwal/typesense-scraper@v2 + with: + # The secret containing your Typesense API key. Required. + api-key: ${{ env.TYPESENSE_ADMIN_API_KEY }} + + # The hostname or IP address of your Typesense server. Required. + host: ${{ env.TYPESENSE_NODE }} + + # The port on which your Typesense server is listening. Optional. Default: 8108. + port: 443 + + # The protocol to use when connecting to your Typesense server. Optional. Default: http. + protocol: https + + # The path to your DocSearch config file. Optional. Default: docsearch.config.json. + config: docsearch.config.json From 617e3fd34319d1d5ae12817b05025c09d6a75f71 Mon Sep 17 00:00:00 2001 From: Alex Ni <12097569+nialexsan@users.noreply.github.com> Date: Fri, 17 Nov 2023 10:26:37 -0500 Subject: [PATCH 4/7] fix styles --- src/css/custom.css | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/css/custom.css b/src/css/custom.css index 9f3687d..0040b75 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -191,8 +191,14 @@ code { font-size: 1.8rem; } +.navbar-sidebar__brand { + width: 100%; + margin-bottom: 1rem; +} .navbar__brand { + padding: 0.75rem; padding-left: 1.5rem; + flex-grow: 1; } .navbar__brand:hover, @@ -230,7 +236,6 @@ nav > div { flex-direction: column; justify-content: flex-end; align-items: flex-start; - gap: 1rem; } nav .logo { @@ -245,8 +250,6 @@ nav .logo { nav a { display: inline-block; - padding: .75rem; - font-weight: 300; } @@ -440,7 +443,7 @@ footer { color: #c5c5c5; } -@media screen and (min-width: 64em) { +@media screen and (min-width: 997px) { nav { position: sticky; } From 76d125a9192c4bfab1bd1cd906dd2a46065bb100 Mon Sep 17 00:00:00 2001 From: Alex Ni <12097569+nialexsan@users.noreply.github.com> Date: Fri, 17 Nov 2023 10:33:51 -0500 Subject: [PATCH 5/7] fix style --- src/css/custom.css | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/css/custom.css b/src/css/custom.css index 0040b75..f44ef7c 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -231,13 +231,6 @@ nav::before { z-index: -1; } -nav > div { - display: flex; - flex-direction: column; - justify-content: flex-end; - align-items: flex-start; -} - nav .logo { margin-right: auto; padding: .75rem; From 1d5f2aac88b495af5436030d159ecd8a83cc58aa Mon Sep 17 00:00:00 2001 From: Alex Ni <12097569+nialexsan@users.noreply.github.com> Date: Fri, 17 Nov 2023 10:54:58 -0500 Subject: [PATCH 6/7] fix styles --- .env.example | 6 ++++++ .gitignore | 2 +- docusaurus.config.js | 2 +- package-lock.json | 12 ++++++++++++ package.json | 1 + src/css/custom.css | 11 +++++++++++ 6 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..16ef185 --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ + +TYPESENSE_NODE="" +TYPESENSE_SEARCH_ONLY_API_KEY="" +TYPESENSE_ADMIN_API_KEY="" + +MIXPANEL_PROJECT_TOKEN="" diff --git a/.gitignore b/.gitignore index 69b1d40..174da2d 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,4 @@ npm-debug.log* yarn-debug.log* yarn-error.log* - +.env diff --git a/docusaurus.config.js b/docusaurus.config.js index 8ff4101..bf3dd16 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -1,6 +1,6 @@ // @ts-check // Note: type annotations allow type checking and IDEs autocompletion - +require('dotenv').config(); const lightCodeTheme = require('prism-react-renderer/themes/github'); const darkCodeTheme = require('prism-react-renderer/themes/dracula'); diff --git a/package-lock.json b/package-lock.json index a43475f..ae9654d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@mdx-js/react": "^3.0.0", "clsx": "^1.2.1", "docusaurus-theme-search-typesense": "^0.14.0", + "dotenv": "^16.3.1", "lottie-react": "^2.4.0", "next": "^12.0.7", "prism-react-renderer": "^1.3.5", @@ -6031,6 +6032,17 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", diff --git a/package.json b/package.json index 76b364e..f9b5b65 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@mdx-js/react": "^3.0.0", "clsx": "^1.2.1", "docusaurus-theme-search-typesense": "^0.14.0", + "dotenv": "^16.3.1", "lottie-react": "^2.4.0", "prism-react-renderer": "^1.3.5", "react": "^18.2.0", diff --git a/src/css/custom.css b/src/css/custom.css index f44ef7c..3024aeb 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -475,3 +475,14 @@ footer { flex: 1 1 auto; } } + +@media screen and (min-width: 997px) and (max-width: 1200px) { + .DocSearch-Button-Placeholder, .DocSearch-Button-Keys { + display: none !important; + } + .navbar__item { + font-size: 14px; + padding-left: 8px; + padding-right: 8px + } +} \ No newline at end of file From 30f499f1864fa10ab2706a88bcf39f6e6025ad1e Mon Sep 17 00:00:00 2001 From: Alex Ni <12097569+nialexsan@users.noreply.github.com> Date: Fri, 17 Nov 2023 15:51:45 -0500 Subject: [PATCH 7/7] tweak style --- src/css/custom.css | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/css/custom.css b/src/css/custom.css index 3024aeb..1fb9557 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -476,13 +476,18 @@ footer { } } +.navbar__item { + font-size: 14px; + padding-left: 8px; + padding-right: 8px +} + +.navbar__items--right>:last-child { + padding-right: 12px; +} + @media screen and (min-width: 997px) and (max-width: 1200px) { .DocSearch-Button-Placeholder, .DocSearch-Button-Keys { display: none !important; } - .navbar__item { - font-size: 14px; - padding-left: 8px; - padding-right: 8px - } } \ No newline at end of file