Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ckb explorer page #69

Merged
merged 2 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/explorer/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Since the ".env" file is gitignored, you can use the ".env.example" file to
# build a new ".env" file when you clone the repo. Keep this file up-to-date
# when you add new variables to `.env`.

# This file will be committed to version control, so make sure not to have any
# secrets in it. If you are cloning this repo, create a copy of this file named
# ".env" and populate it with your secrets.

# When adding additional environment variables, the schema in "/src/env.mjs"
# should be updated accordingly.

# Example:
# SERVERVAR="foo"
# NEXT_PUBLIC_CLIENTVAR="bar"
NEXT_PUBLIC_REPO=nervosnetwork/ckb-explorer

# For accessing api.github.com
# https://docs.github.com/en/rest/overview/authenticating-to-the-rest-api?apiVersion=2022-11-28
GITHUB_TOKEN=

UPTIME_KEY=
7 changes: 7 additions & 0 deletions packages/explorer/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import("eslint").Linter.Config} */
const config = {
root: true,
extends: ['@magickbase-website/eslint-config/next.js'],
}

module.exports = config
9 changes: 9 additions & 0 deletions packages/explorer/.lintstagedrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const path = require('path')

const buildEslintCommand = filenames =>
`next lint --fix --file ${filenames.map(f => path.relative(process.cwd(), f)).join(' --file ')}`

module.exports = {
'*.{js,cjs,mjs,jsx,ts,tsx}': ['prettier --write', buildEslintCommand],
'*.{css,scss}': ['prettier --write', 'stylelint --fix'],
}
52 changes: 52 additions & 0 deletions packages/explorer/.stylelintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"overrides": [
{
"files": ["**/*.scss"],
"customSyntax": "postcss-scss"
}
],
"extends": [
"stylelint-config-standard-scss",
"stylelint-config-rational-order",
"stylelint-config-css-modules",
"stylelint-config-prettier-scss"
],
"rules": {
"selector-class-pattern": [
"^[a-z][a-zA-Z0-9]*$",
{
"message": "Expected class selector to be lowerCamelCase"
}
],
"custom-property-pattern": [
"^[a-z][a-zA-Z0-9]*$",
{
"message": "Expected custom property name to be lowerCamelCase"
}
],
"keyframes-name-pattern": [
"^[a-z][a-zA-Z0-9]*$",
{
"message": "Expected class selector to be lowerCamelCase"
}
],
"scss/dollar-variable-pattern": [
"^[a-z][a-zA-Z0-9]*$",
{
"message": "Expected variable to be lowerCamelCase"
}
],
"scss/percent-placeholder-pattern": [
"^[a-z][a-zA-Z0-9]*$",
{
"message": "Expected placeholder to be lowerCamelCase"
}
],
"scss/at-mixin-pattern": [
"^[a-z][a-zA-Z0-9]*$",
{
"message": "Expected mixin name to be lowerCamelCase"
}
]
}
}
120 changes: 120 additions & 0 deletions packages/explorer/i18next-parser.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { UserConfig } from 'i18next-parser'

const config: UserConfig = {
// Key separator used in your translation keys
contextSeparator: '_',

// Save the \_old files
createOldCatalogs: false,

// Default namespace used in your i18next config
defaultNamespace: 'translation',

defaultValue(locale, namespace, key) {
return key ?? ''
},

// Indentation of the catalog files
indentation: 2,

// Keep keys from the catalog that are no longer in code
// You may either specify a boolean to keep or discard all removed keys.
// You may also specify an array of patterns: the keys from the catalog that are no long in the code but match one of the patterns will be kept.
// The patterns are applied to the full key including the namespace, the parent keys and the separators.
keepRemoved: false,

// Key separator used in your translation keys
// If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
keySeparator: false,

// see below for more details
lexers: {
hbs: ['HandlebarsLexer'],
handlebars: ['HandlebarsLexer'],

htm: ['HTMLLexer'],
html: ['HTMLLexer'],

mjs: ['JavascriptLexer'],
js: ['JavascriptLexer'],
ts: [
{
lexer: 'JavascriptLexer',
functions: ['t', 'addI18nKey'],
namespaceFunctions: ['useTranslation', 'withTranslation', 'createI18nKeyAdder'],
},
],
jsx: ['JsxLexer'],
tsx: ['JsxLexer'],

default: ['JavascriptLexer'],
},

// Control the line ending. See options at https://github.com/ryanve/eol
lineEnding: 'lf',

// An array of the locales in your applications
locales: ['en', 'zh'],

// Namespace separator used in your translation keys
// If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
namespaceSeparator: false,

// Supports $LOCALE and $NAMESPACE injection
// Supports JSON (.json) and YAML (.yml) file formats
// Where to write the locale files relative to process.cwd()
output: 'public/locales/$LOCALE/$NAMESPACE.json',

// Plural separator used in your translation keys
// If you want to use plain english keys, separators such as `_` might conflict. You might want to set `pluralSeparator` to a different string that does not occur in your keys.
// If you don't want to generate keys for plurals (for example, in case you are using ICU format), set `pluralSeparator: false`.
pluralSeparator: '_',

// An array of globs that describe where to look for source files
// relative to the location of the configuration file
input: ['src/**/*.{ts,tsx}', '../shared/src/**/*.{ts,tsx}'],

// Whether or not to sort the catalog. Can also be a [compareFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#parameters)
sort: true,

// Display info about the parsing including some stats
verbose: false,

// Exit with an exit code of 1 on warnings
failOnWarnings: false,

// Exit with an exit code of 1 when translations are updated (for CI purpose)
failOnUpdate: false,

// If you wish to customize the value output the value as an object, you can set your own format.
// ${defaultValue} is the default value you set in your translation function.
// Any other custom property will be automatically extracted.
//
// Example:
// {
// message: "${defaultValue}",
// description: "${maxLength}", // t('my-key', {maxLength: 150})
// }
customValueTemplate: null,

// The locale to compare with default values to determine whether a default value has been changed.
// If this is set and a default value differs from a translation in the specified locale, all entries
// for that key across locales are reset to the default value, and existing translations are moved to
// the `_old` file.
resetDefaultValueLocale: null,

// If you wish to customize options in internally used i18next instance, you can define an object with any
// configuration property supported by i18next (https://www.i18next.com/overview/configuration-options).
// { compatibilityJSON: 'v3' } can be used to generate v3 compatible plurals.
i18nextOptions: null,

// If you wish to customize options for yaml output, you can define an object here.
// Configuration options are here (https://github.com/nodeca/js-yaml#dump-object---options-).
// Example:
// {
// lineWidth: -1,
// }
yamlOptions: null,
}

export default config
21 changes: 21 additions & 0 deletions packages/explorer/next-i18next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* next-i18next not support mjs config
*/
/* eslint-disable @typescript-eslint/no-var-requires */

const path = require('path')

/**
* @type {import('next-i18next').UserConfig}
*/
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'zh'],
localeDetection: true,
},
fallbackNS: 'common',
localePath: typeof window === 'undefined' ? path.resolve('./public/locales') : '/locales',

reloadOnPrerender: process.env.NODE_ENV === 'development',
}
107 changes: 107 additions & 0 deletions packages/explorer/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
const i18nConfig = (await import('./next-i18next.config.js')).default

/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
* This is especially useful for Docker builds.
*/
!process.env.SKIP_ENV_VALIDATION && (await import('./src/env.mjs'))

/** @type {import("next").NextConfig} */
const config = {
reactStrictMode: true,

pageExtensions: ['tsx', 'ts', 'jsx', 'js'].map(suffix => `page.${suffix}`),

/**
* If you have the "experimental: { appDir: true }" setting enabled, then you
* must comment the below `i18n` config out.
*
* @see https://github.com/vercel/next.js/issues/41980
*/
i18n: i18nConfig.i18n,

images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'avatars.githubusercontent.com',
},
],
},

transpilePackages: ['@magickbase-website/shared'],

sassOptions: {
logger: {
warn: function (message) {
console.warn(message)
},
debug: function (message) {
console.log(message)
},
},
},

webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: [
{
loader: '@svgr/webpack',
options: {
svgoConfig: {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false,
},
},
},
],
},
},
},
],
})

// https://dhanrajsp.me/snippets/customize-css-loader-options-in-nextjs
const oneOf = config.module.rules.find(rule => typeof rule.oneOf === 'object')
if (oneOf) {
const moduleSassRule = oneOf.oneOf.find(rule => regexEqual(rule.test, /\.module\.(scss|sass)$/))
if (moduleSassRule) {
// Get the config object for css-loader plugin
const cssLoader = moduleSassRule.use.find(({ loader }) => loader.includes('css-loader'))
if (cssLoader) {
cssLoader.options = {
...cssLoader.options,
modules: {
...cssLoader.options.modules,
mode: 'local',
},
}
}
}
}

return config
},
}

/**
* Stolen from https://stackoverflow.com/questions/10776600/testing-for-equality-of-regular-expressions
*/
function regexEqual(x, y) {
return (
x instanceof RegExp &&
y instanceof RegExp &&
x.source === y.source &&
x.global === y.global &&
x.ignoreCase === y.ignoreCase &&
x.multiline === y.multiline
)
}

export default config
Loading