main #21

Merged
VPhung24 merged 3 commits from snowball/testnet-onboarding-app:main into main 2024-08-09 00:58:46 +00:00
15 changed files with 441 additions and 148 deletions

View File

@ -1,40 +1,42 @@
# testnet-onboarding-app # testnet-onboarding-app
React app for onboarding participants to laconicd chain with Nitro/Cosmos key attestation React app for onboarding participants to laconicd chain with Nitro/Cosmos key attestation
## Setup for testnet-onboarding-app ## Setup for testnet-onboarding-app
1. Clone the repository 1. Clone the repository
``` ```zsh
git clone git@git.vdb.to:cerc-io/testnet-onboarding-app.git git clone git@git.vdb.to:cerc-io/testnet-onboarding-app.git
``` ```
2. Enter the project directory 2. Enter the project directory
``` ```zsh
cd testnet-onboarding-app cd testnet-onboarding-app
``` ```
3. Install dependencies 3. Install dependencies
``` ```zsh
yarn yarn
``` ```
4. Setup .env 4. Setup .env
- Copy and update `.env` - Copy and update `.env`
``` ```zsh
cp .env.example .env cp .env.example .env
``` ```
- In the `.env` file, add the WalletConnect project ID used in your [laconic-wallet](https://git.vdb.to/cerc-io/laconic-wallet) setup. - In the `.env` file, add the WalletConnect project ID used in your [laconic-wallet](https://git.vdb.to/cerc-io/laconic-wallet) setup.
```
```zsh
WALLET_CONNECT_PROJECT_ID=39bc93c... WALLET_CONNECT_PROJECT_ID=39bc93c...
``` ```
5. Start the application 5. Start the application
``` ```zsh
yarn start yarn start
``` ```

View File

@ -1,56 +1,56 @@
const fs = require('fs'); const fs = require("fs");
const path = require('path'); const path = require("path");
const webpack = require('webpack'); const webpack = require("webpack");
const resolve = require('resolve'); const resolve = require("resolve");
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require("html-webpack-plugin");
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); const CaseSensitivePathsPlugin = require("case-sensitive-paths-webpack-plugin");
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin'); const InlineChunkHtmlPlugin = require("react-dev-utils/InlineChunkHtmlPlugin");
const TerserPlugin = require('terser-webpack-plugin'); const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const { WebpackManifestPlugin } = require('webpack-manifest-plugin'); const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); const InterpolateHtmlPlugin = require("react-dev-utils/InterpolateHtmlPlugin");
const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); const WorkboxWebpackPlugin = require("workbox-webpack-plugin");
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const ModuleScopePlugin = require("react-dev-utils/ModuleScopePlugin");
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); const getCSSModuleLocalIdent = require("react-dev-utils/getCSSModuleLocalIdent");
const ESLintPlugin = require('eslint-webpack-plugin'); const ESLintPlugin = require("eslint-webpack-plugin");
const paths = require('./paths'); const paths = require("./paths");
const modules = require('./modules'); const modules = require("./modules");
const getClientEnvironment = require('./env'); const getClientEnvironment = require("./env");
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); const ModuleNotFoundPlugin = require("react-dev-utils/ModuleNotFoundPlugin");
const ForkTsCheckerWebpackPlugin = const ForkTsCheckerWebpackPlugin =
process.env.TSC_COMPILE_ON_ERROR === 'true' process.env.TSC_COMPILE_ON_ERROR === "true"
? require('react-dev-utils/ForkTsCheckerWarningWebpackPlugin') ? require("react-dev-utils/ForkTsCheckerWarningWebpackPlugin")
: require('react-dev-utils/ForkTsCheckerWebpackPlugin'); : require("react-dev-utils/ForkTsCheckerWebpackPlugin");
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
const createEnvironmentHash = require('./webpack/persistentCache/createEnvironmentHash'); const createEnvironmentHash = require("./webpack/persistentCache/createEnvironmentHash");
// Source maps are resource heavy and can cause out of memory issue for large source files. // Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'; const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
const reactRefreshRuntimeEntry = require.resolve('react-refresh/runtime'); const reactRefreshRuntimeEntry = require.resolve("react-refresh/runtime");
const reactRefreshWebpackPluginRuntimeEntry = require.resolve( const reactRefreshWebpackPluginRuntimeEntry = require.resolve(
'@pmmmwh/react-refresh-webpack-plugin' "@pmmmwh/react-refresh-webpack-plugin"
); );
const babelRuntimeEntry = require.resolve('babel-preset-react-app'); const babelRuntimeEntry = require.resolve("babel-preset-react-app");
const babelRuntimeEntryHelpers = require.resolve( const babelRuntimeEntryHelpers = require.resolve(
'@babel/runtime/helpers/esm/assertThisInitialized', "@babel/runtime/helpers/esm/assertThisInitialized",
{ paths: [babelRuntimeEntry] } { paths: [babelRuntimeEntry] }
); );
const babelRuntimeRegenerator = require.resolve('@babel/runtime/regenerator', { const babelRuntimeRegenerator = require.resolve("@babel/runtime/regenerator", {
paths: [babelRuntimeEntry], paths: [babelRuntimeEntry],
}); });
// Some apps do not need the benefits of saving a web request, so not inlining the chunk // Some apps do not need the benefits of saving a web request, so not inlining the chunk
// makes for a smoother build process. // makes for a smoother build process.
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false'; const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== "false";
const emitErrorsAsWarnings = process.env.ESLINT_NO_DEV_ERRORS === 'true'; const emitErrorsAsWarnings = process.env.ESLINT_NO_DEV_ERRORS === "true";
const disableESLintPlugin = process.env.DISABLE_ESLINT_PLUGIN === 'true'; const disableESLintPlugin = process.env.DISABLE_ESLINT_PLUGIN === "true";
const imageInlineSizeLimit = parseInt( const imageInlineSizeLimit = parseInt(
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000' process.env.IMAGE_INLINE_SIZE_LIMIT || "10000"
); );
// Check if TypeScript is setup // Check if TypeScript is setup
@ -58,7 +58,7 @@ const useTypeScript = fs.existsSync(paths.appTsConfig);
// Check if Tailwind config exists // Check if Tailwind config exists
const useTailwind = fs.existsSync( const useTailwind = fs.existsSync(
path.join(paths.appPath, 'tailwind.config.js') path.join(paths.appPath, "tailwind.config.ts")
); );
// Get the path to the uncompiled service worker (if it exists). // Get the path to the uncompiled service worker (if it exists).
@ -71,12 +71,12 @@ const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/; const sassModuleRegex = /\.module\.(scss|sass)$/;
const hasJsxRuntime = (() => { const hasJsxRuntime = (() => {
if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') { if (process.env.DISABLE_NEW_JSX_TRANSFORM === "true") {
return false; return false;
} }
try { try {
require.resolve('react/jsx-runtime'); require.resolve("react/jsx-runtime");
return true; return true;
} catch (e) { } catch (e) {
return false; return false;
@ -86,13 +86,13 @@ const hasJsxRuntime = (() => {
// This is the production and development configuration. // This is the production and development configuration.
// It is focused on developer experience, fast rebuilds, and a minimal bundle. // It is focused on developer experience, fast rebuilds, and a minimal bundle.
module.exports = function (webpackEnv) { module.exports = function (webpackEnv) {
const isEnvDevelopment = webpackEnv === 'development'; const isEnvDevelopment = webpackEnv === "development";
const isEnvProduction = webpackEnv === 'production'; const isEnvProduction = webpackEnv === "production";
// Variable used for enabling profiling in Production // Variable used for enabling profiling in Production
// passed into alias object. Uses a flag if passed into the build command // passed into alias object. Uses a flag if passed into the build command
const isEnvProductionProfile = const isEnvProductionProfile =
isEnvProduction && process.argv.includes('--profile'); isEnvProduction && process.argv.includes("--profile");
// We will provide `paths.publicUrlOrPath` to our app // We will provide `paths.publicUrlOrPath` to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
@ -105,38 +105,38 @@ module.exports = function (webpackEnv) {
// common function to get style loaders // common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor) => { const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [ const loaders = [
isEnvDevelopment && require.resolve('style-loader'), isEnvDevelopment && require.resolve("style-loader"),
isEnvProduction && { isEnvProduction && {
loader: MiniCssExtractPlugin.loader, loader: MiniCssExtractPlugin.loader,
// css is located in `static/css`, use '../../' to locate index.html folder // css is located in `static/css`, use '../../' to locate index.html folder
// in production `paths.publicUrlOrPath` can be a relative path // in production `paths.publicUrlOrPath` can be a relative path
options: paths.publicUrlOrPath.startsWith('.') options: paths.publicUrlOrPath.startsWith(".")
? { publicPath: '../../' } ? { publicPath: "../../" }
: {}, : {},
}, },
{ {
loader: require.resolve('css-loader'), loader: require.resolve("css-loader"),
options: cssOptions, options: cssOptions,
}, },
{ {
// Options for PostCSS as we reference these options twice // Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in // Adds vendor prefixing based on your specified browser support in
// package.json // package.json
loader: require.resolve('postcss-loader'), loader: require.resolve("postcss-loader"),
options: { options: {
postcssOptions: { postcssOptions: {
// Necessary for external CSS imports to work // Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677 // https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss', ident: "postcss",
config: false, config: false,
plugins: !useTailwind plugins: !useTailwind
? [ ? [
'postcss-flexbugs-fixes', "postcss-flexbugs-fixes",
[ [
'postcss-preset-env', "postcss-preset-env",
{ {
autoprefixer: { autoprefixer: {
flexbox: 'no-2009', flexbox: "no-2009",
}, },
stage: 3, stage: 3,
}, },
@ -144,16 +144,16 @@ module.exports = function (webpackEnv) {
// Adds PostCSS Normalize as the reset css with default options, // Adds PostCSS Normalize as the reset css with default options,
// so that it honors browserslist config in package.json // so that it honors browserslist config in package.json
// which in turn let's users customize the target behavior as per their needs. // which in turn let's users customize the target behavior as per their needs.
'postcss-normalize', "postcss-normalize",
] ]
: [ : [
'tailwindcss', "tailwindcss",
'postcss-flexbugs-fixes', "postcss-flexbugs-fixes",
[ [
'postcss-preset-env', "postcss-preset-env",
{ {
autoprefixer: { autoprefixer: {
flexbox: 'no-2009', flexbox: "no-2009",
}, },
stage: 3, stage: 3,
}, },
@ -167,7 +167,7 @@ module.exports = function (webpackEnv) {
if (preProcessor) { if (preProcessor) {
loaders.push( loaders.push(
{ {
loader: require.resolve('resolve-url-loader'), loader: require.resolve("resolve-url-loader"),
options: { options: {
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment, sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
root: paths.appSrc, root: paths.appSrc,
@ -185,17 +185,17 @@ module.exports = function (webpackEnv) {
}; };
return { return {
target: ['browserslist'], target: ["browserslist"],
// Webpack noise constrained to errors and warnings // Webpack noise constrained to errors and warnings
stats: 'errors-warnings', stats: "errors-warnings",
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development', mode: isEnvProduction ? "production" : isEnvDevelopment && "development",
// Stop compilation early in production // Stop compilation early in production
bail: isEnvProduction, bail: isEnvProduction,
devtool: isEnvProduction devtool: isEnvProduction
? shouldUseSourceMap ? shouldUseSourceMap
? 'source-map' ? "source-map"
: false : false
: isEnvDevelopment && 'cheap-module-source-map', : isEnvDevelopment && "cheap-module-source-map",
// These are the "entry points" to our application. // These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle. // This means they will be the "root" imports that are included in JS bundle.
entry: paths.appIndexJs, entry: paths.appIndexJs,
@ -207,41 +207,42 @@ module.exports = function (webpackEnv) {
// There will be one main bundle, and one file per asynchronous chunk. // There will be one main bundle, and one file per asynchronous chunk.
// In development, it does not produce real files. // In development, it does not produce real files.
filename: isEnvProduction filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js' ? "static/js/[name].[contenthash:8].js"
: isEnvDevelopment && 'static/js/bundle.js', : isEnvDevelopment && "static/js/bundle.js",
// There are also additional JS chunk files if you use code splitting. // There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js' ? "static/js/[name].[contenthash:8].chunk.js"
: isEnvDevelopment && 'static/js/[name].chunk.js', : isEnvDevelopment && "static/js/[name].chunk.js",
assetModuleFilename: 'static/media/[name].[hash][ext]', assetModuleFilename: "static/media/[name].[hash][ext]",
// webpack uses `publicPath` to determine where the app is being served from. // webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path. // It requires a trailing slash, or the file assets will get an incorrect path.
// We inferred the "public path" (such as / or /my-project) from homepage. // We inferred the "public path" (such as / or /my-project) from homepage.
publicPath: paths.publicUrlOrPath, publicPath: paths.publicUrlOrPath,
// Point sourcemap entries to original disk location (format as URL on Windows) // Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: isEnvProduction devtoolModuleFilenameTemplate: isEnvProduction
? info => ? (info) =>
path path
.relative(paths.appSrc, info.absoluteResourcePath) .relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/') .replace(/\\/g, "/")
: isEnvDevelopment && : isEnvDevelopment &&
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')), ((info) =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, "/")),
}, },
cache: { cache: {
type: 'filesystem', type: "filesystem",
version: createEnvironmentHash(env.raw), version: createEnvironmentHash(env.raw),
cacheDirectory: paths.appWebpackCache, cacheDirectory: paths.appWebpackCache,
store: 'pack', store: "pack",
buildDependencies: { buildDependencies: {
defaultWebpack: ['webpack/lib/'], defaultWebpack: ["webpack/lib/"],
config: [__filename], config: [__filename],
tsconfig: [paths.appTsConfig, paths.appJsConfig].filter(f => tsconfig: [paths.appTsConfig, paths.appJsConfig].filter((f) =>
fs.existsSync(f) fs.existsSync(f)
), ),
}, },
}, },
infrastructureLogging: { infrastructureLogging: {
level: 'none', level: "none",
}, },
optimization: { optimization: {
minimize: isEnvProduction, minimize: isEnvProduction,
@ -312,16 +313,16 @@ module.exports = function (webpackEnv) {
// `web` extension prefixes have been added for better support // `web` extension prefixes have been added for better support
// for React Native Web. // for React Native Web.
extensions: paths.moduleFileExtensions extensions: paths.moduleFileExtensions
.map(ext => `.${ext}`) .map((ext) => `.${ext}`)
.filter(ext => useTypeScript || !ext.includes('ts')), .filter((ext) => useTypeScript || !ext.includes("ts")),
alias: { alias: {
// Support React Native Web // Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web', "react-native": "react-native-web",
// Allows for better profiling with ReactDevTools // Allows for better profiling with ReactDevTools
...(isEnvProductionProfile && { ...(isEnvProductionProfile && {
'react-dom$': 'react-dom/profiling', "react-dom$": "react-dom/profiling",
'scheduler/tracing': 'scheduler/tracing-profiling', "scheduler/tracing": "scheduler/tracing-profiling",
}), }),
...(modules.webpackAliases || {}), ...(modules.webpackAliases || {}),
}, },
@ -346,10 +347,10 @@ module.exports = function (webpackEnv) {
rules: [ rules: [
// Handle node_modules packages that contain sourcemaps // Handle node_modules packages that contain sourcemaps
shouldUseSourceMap && { shouldUseSourceMap && {
enforce: 'pre', enforce: "pre",
exclude: /@babel(?:\/|\\{1,2})runtime/, exclude: /@babel(?:\/|\\{1,2})runtime/,
test: /\.(js|mjs|jsx|ts|tsx|css)$/, test: /\.(js|mjs|jsx|ts|tsx|css)$/,
loader: require.resolve('source-map-loader'), loader: require.resolve("source-map-loader"),
}, },
{ {
// "oneOf" will traverse all following loaders until one will // "oneOf" will traverse all following loaders until one will
@ -360,8 +361,8 @@ module.exports = function (webpackEnv) {
// https://github.com/jshttp/mime-db // https://github.com/jshttp/mime-db
{ {
test: [/\.avif$/], test: [/\.avif$/],
type: 'asset', type: "asset",
mimetype: 'image/avif', mimetype: "image/avif",
parser: { parser: {
dataUrlCondition: { dataUrlCondition: {
maxSize: imageInlineSizeLimit, maxSize: imageInlineSizeLimit,
@ -373,7 +374,7 @@ module.exports = function (webpackEnv) {
// A missing `test` is equivalent to a match. // A missing `test` is equivalent to a match.
{ {
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
type: 'asset', type: "asset",
parser: { parser: {
dataUrlCondition: { dataUrlCondition: {
maxSize: imageInlineSizeLimit, maxSize: imageInlineSizeLimit,
@ -384,7 +385,7 @@ module.exports = function (webpackEnv) {
test: /\.svg$/, test: /\.svg$/,
use: [ use: [
{ {
loader: require.resolve('@svgr/webpack'), loader: require.resolve("@svgr/webpack"),
options: { options: {
prettier: false, prettier: false,
svgo: false, svgo: false,
@ -396,9 +397,9 @@ module.exports = function (webpackEnv) {
}, },
}, },
{ {
loader: require.resolve('file-loader'), loader: require.resolve("file-loader"),
options: { options: {
name: 'static/media/[name].[hash].[ext]', name: "static/media/[name].[hash].[ext]",
}, },
}, },
], ],
@ -411,16 +412,16 @@ module.exports = function (webpackEnv) {
{ {
test: /\.(js|mjs|jsx|ts|tsx)$/, test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc, include: paths.appSrc,
loader: require.resolve('babel-loader'), loader: require.resolve("babel-loader"),
options: { options: {
customize: require.resolve( customize: require.resolve(
'babel-preset-react-app/webpack-overrides' "babel-preset-react-app/webpack-overrides"
), ),
presets: [ presets: [
[ [
require.resolve('babel-preset-react-app'), require.resolve("babel-preset-react-app"),
{ {
runtime: hasJsxRuntime ? 'automatic' : 'classic', runtime: hasJsxRuntime ? "automatic" : "classic",
}, },
], ],
], ],
@ -428,7 +429,7 @@ module.exports = function (webpackEnv) {
plugins: [ plugins: [
isEnvDevelopment && isEnvDevelopment &&
shouldUseReactRefresh && shouldUseReactRefresh &&
require.resolve('react-refresh/babel'), require.resolve("react-refresh/babel"),
].filter(Boolean), ].filter(Boolean),
// This is a feature of `babel-loader` for webpack (not Babel itself). // This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/ // It enables caching results in ./node_modules/.cache/babel-loader/
@ -444,14 +445,14 @@ module.exports = function (webpackEnv) {
{ {
test: /\.(js|mjs)$/, test: /\.(js|mjs)$/,
exclude: /@babel(?:\/|\\{1,2})runtime/, exclude: /@babel(?:\/|\\{1,2})runtime/,
loader: require.resolve('babel-loader'), loader: require.resolve("babel-loader"),
options: { options: {
babelrc: false, babelrc: false,
configFile: false, configFile: false,
compact: false, compact: false,
presets: [ presets: [
[ [
require.resolve('babel-preset-react-app/dependencies'), require.resolve("babel-preset-react-app/dependencies"),
{ helpers: true }, { helpers: true },
], ],
], ],
@ -482,7 +483,7 @@ module.exports = function (webpackEnv) {
? shouldUseSourceMap ? shouldUseSourceMap
: isEnvDevelopment, : isEnvDevelopment,
modules: { modules: {
mode: 'icss', mode: "icss",
}, },
}), }),
// Don't consider CSS imports dead code even if the // Don't consider CSS imports dead code even if the
@ -501,7 +502,7 @@ module.exports = function (webpackEnv) {
? shouldUseSourceMap ? shouldUseSourceMap
: isEnvDevelopment, : isEnvDevelopment,
modules: { modules: {
mode: 'local', mode: "local",
getLocalIdent: getCSSModuleLocalIdent, getLocalIdent: getCSSModuleLocalIdent,
}, },
}), }),
@ -519,10 +520,10 @@ module.exports = function (webpackEnv) {
? shouldUseSourceMap ? shouldUseSourceMap
: isEnvDevelopment, : isEnvDevelopment,
modules: { modules: {
mode: 'icss', mode: "icss",
}, },
}, },
'sass-loader' "sass-loader"
), ),
// Don't consider CSS imports dead code even if the // Don't consider CSS imports dead code even if the
// containing package claims to have no side effects. // containing package claims to have no side effects.
@ -541,11 +542,11 @@ module.exports = function (webpackEnv) {
? shouldUseSourceMap ? shouldUseSourceMap
: isEnvDevelopment, : isEnvDevelopment,
modules: { modules: {
mode: 'local', mode: "local",
getLocalIdent: getCSSModuleLocalIdent, getLocalIdent: getCSSModuleLocalIdent,
}, },
}, },
'sass-loader' "sass-loader"
), ),
}, },
// "file" loader makes sure those assets get served by WebpackDevServer. // "file" loader makes sure those assets get served by WebpackDevServer.
@ -559,7 +560,7 @@ module.exports = function (webpackEnv) {
// Also exclude `html` and `json` extensions so they get processed // Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders. // by webpacks internal loaders.
exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/], exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
type: 'asset/resource', type: "asset/resource",
}, },
// ** STOP ** Are you adding a new loader? // ** STOP ** Are you adding a new loader?
// Make sure to add the new loader(s) before the "file" loader. // Make sure to add the new loader(s) before the "file" loader.
@ -633,8 +634,8 @@ module.exports = function (webpackEnv) {
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output // Options similar to the same options in webpackOptions.output
// both options are optional // both options are optional
filename: 'static/css/[name].[contenthash:8].css', filename: "static/css/[name].[contenthash:8].css",
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css', chunkFilename: "static/css/[name].[contenthash:8].chunk.css",
}), }),
// Generate an asset manifest file with the following content: // Generate an asset manifest file with the following content:
// - "files" key: Mapping of all asset filenames to their corresponding // - "files" key: Mapping of all asset filenames to their corresponding
@ -643,7 +644,7 @@ module.exports = function (webpackEnv) {
// - "entrypoints" key: Array of files which are included in `index.html`, // - "entrypoints" key: Array of files which are included in `index.html`,
// can be used to reconstruct the HTML if necessary // can be used to reconstruct the HTML if necessary
new WebpackManifestPlugin({ new WebpackManifestPlugin({
fileName: 'asset-manifest.json', fileName: "asset-manifest.json",
publicPath: paths.publicUrlOrPath, publicPath: paths.publicUrlOrPath,
generate: (seed, files, entrypoints) => { generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => { const manifestFiles = files.reduce((manifest, file) => {
@ -651,7 +652,7 @@ module.exports = function (webpackEnv) {
return manifest; return manifest;
}, seed); }, seed);
const entrypointFiles = entrypoints.main.filter( const entrypointFiles = entrypoints.main.filter(
fileName => !fileName.endsWith('.map') (fileName) => !fileName.endsWith(".map")
); );
return { return {
@ -687,7 +688,7 @@ module.exports = function (webpackEnv) {
new ForkTsCheckerWebpackPlugin({ new ForkTsCheckerWebpackPlugin({
async: isEnvDevelopment, async: isEnvDevelopment,
typescript: { typescript: {
typescriptPath: resolve.sync('typescript', { typescriptPath: resolve.sync("typescript", {
basedir: paths.appNodeModules, basedir: paths.appNodeModules,
}), }),
configOverwrite: { configOverwrite: {
@ -707,7 +708,7 @@ module.exports = function (webpackEnv) {
diagnosticOptions: { diagnosticOptions: {
syntactic: true, syntactic: true,
}, },
mode: 'write-references', mode: "write-references",
// profile: true, // profile: true,
}, },
issue: { issue: {
@ -716,41 +717,41 @@ module.exports = function (webpackEnv) {
// '../cra-template-typescript/template/src/App.tsx' // '../cra-template-typescript/template/src/App.tsx'
// otherwise. // otherwise.
include: [ include: [
{ file: '../**/src/**/*.{ts,tsx}' }, { file: "../**/src/**/*.{ts,tsx}" },
{ file: '**/src/**/*.{ts,tsx}' }, { file: "**/src/**/*.{ts,tsx}" },
], ],
exclude: [ exclude: [
{ file: '**/src/**/__tests__/**' }, { file: "**/src/**/__tests__/**" },
{ file: '**/src/**/?(*.){spec|test}.*' }, { file: "**/src/**/?(*.){spec|test}.*" },
{ file: '**/src/setupProxy.*' }, { file: "**/src/setupProxy.*" },
{ file: '**/src/setupTests.*' }, { file: "**/src/setupTests.*" },
], ],
}, },
logger: { logger: {
infrastructure: 'silent', infrastructure: "silent",
}, },
}), }),
!disableESLintPlugin && !disableESLintPlugin &&
new ESLintPlugin({ new ESLintPlugin({
// Plugin options // Plugin options
extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'], extensions: ["js", "mjs", "jsx", "ts", "tsx"],
formatter: require.resolve('react-dev-utils/eslintFormatter'), formatter: require.resolve("react-dev-utils/eslintFormatter"),
eslintPath: require.resolve('eslint'), eslintPath: require.resolve("eslint"),
failOnError: !(isEnvDevelopment && emitErrorsAsWarnings), failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),
context: paths.appSrc, context: paths.appSrc,
cache: true, cache: true,
cacheLocation: path.resolve( cacheLocation: path.resolve(
paths.appNodeModules, paths.appNodeModules,
'.cache/.eslintcache' ".cache/.eslintcache"
), ),
// ESLint class options // ESLint class options
cwd: paths.appPath, cwd: paths.appPath,
resolvePluginsRelativeTo: __dirname, resolvePluginsRelativeTo: __dirname,
baseConfig: { baseConfig: {
extends: [require.resolve('eslint-config-react-app/base')], extends: [require.resolve("eslint-config-react-app/base")],
rules: { rules: {
...(!hasJsxRuntime && { ...(!hasJsxRuntime && {
'react/react-in-jsx-scope': 'error', "react/react-in-jsx-scope": "error",
}), }),
}, },
}, },

View File

@ -33,7 +33,7 @@
"resolve": "^1.20.0", "resolve": "^1.20.0",
"semver": "^7.3.5", "semver": "^7.3.5",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",
"tailwindcss": "^3.0.2", "tailwindcss": "^3.4.9",
"typescript": "^4.9.5" "typescript": "^4.9.5"
}, },
"scripts": { "scripts": {
@ -66,8 +66,10 @@
"@types/node": "^16.18.90", "@types/node": "^16.18.90",
"@types/react": "^18.2.67", "@types/react": "^18.2.67",
"@types/react-dom": "^18.2.22", "@types/react-dom": "^18.2.22",
"@types/tailwindcss": "^3.1.0",
"@typescript-eslint/eslint-plugin": "^6.13.2", "@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2", "@typescript-eslint/parser": "^6.13.2",
"autoprefixer": "^10.4.20",
"babel-jest": "^27.4.2", "babel-jest": "^27.4.2",
"babel-loader": "^8.2.3", "babel-loader": "^8.2.3",
"babel-plugin-named-asset-import": "^0.3.8", "babel-plugin-named-asset-import": "^0.3.8",
@ -92,7 +94,7 @@
"jest-resolve": "^27.4.2", "jest-resolve": "^27.4.2",
"jest-watch-typeahead": "^1.0.0", "jest-watch-typeahead": "^1.0.0",
"mini-css-extract-plugin": "^2.4.5", "mini-css-extract-plugin": "^2.4.5",
"postcss": "^8.4.4", "postcss": "^8.4.41",
"postcss-flexbugs-fixes": "^5.0.2", "postcss-flexbugs-fixes": "^5.0.2",
"postcss-loader": "^6.2.1", "postcss-loader": "^6.2.1",
"postcss-normalize": "^10.0.1", "postcss-normalize": "^10.0.1",

6
postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

3
public/laconic_logo.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.04924 12.6164C6.84238 9.85387 8.57128 6.03867 8.57051 1.82634C8.57154 1.25458 8.53962 0.689188 8.47618 0.130795L0 0.131558L0.000257231 16.2401C-0.000514887 18.1926 0.75217 20.1458 2.25767 21.6349C3.7633 23.124 5.73941 23.8693 7.71384 23.8683L7.71333 23.8688L24 23.8692L23.9994 15.4843C23.4361 15.4228 22.8645 15.3911 22.2851 15.391C18.0274 15.3915 14.17 17.1014 11.3769 19.864C9.34443 21.8239 6.08571 21.8243 4.07833 19.8388C2.07224 17.8545 2.07133 14.6303 4.04924 12.6164ZM22.2419 1.87395C19.9011 -0.441217 16.0981 -0.442108 13.7566 1.87395C11.415 4.18987 11.4159 7.95136 13.7566 10.2664C16.0985 12.5828 19.9003 12.5825 22.2419 10.2664C24.5835 7.95047 24.5838 4.19026 22.2419 1.87395Z" fill="#FBFBFB"/>
</svg>

After

Width:  |  Height:  |  Size: 859 B

View File

@ -0,0 +1,10 @@
<svg width="117" height="21" viewBox="0 0 117 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.22282 11.0194C6.57609 8.69185 8.03272 5.47748 8.03206 1.92852C8.03293 1.44681 8.00604 0.970455 7.95259 0.499999L0.811272 0.500642L0.811488 14.0723C0.810838 15.7174 1.44499 17.3629 2.7134 18.6175C3.98191 19.8721 5.64682 20.5001 7.31031 20.4992L7.30988 20.4997L21.0317 20.5L21.0311 13.4355C20.5566 13.3838 20.075 13.357 19.5869 13.3569C15.9997 13.3574 12.7498 14.798 10.3965 17.1255C8.6841 18.7768 5.93858 18.7771 4.24733 17.1043C2.55716 15.4325 2.5564 12.7161 4.22282 11.0194ZM19.5504 1.96863C17.5783 0.0180696 14.3742 0.017319 12.4014 1.96863C10.4286 3.91984 10.4293 7.08895 12.4014 9.03941C14.3745 10.991 17.5776 10.9907 19.5504 9.03941C21.5232 7.0882 21.5236 3.92016 19.5504 1.96863Z" fill="#FBFBFB"/>
<path d="M32.6326 19.0836H40.4995V16.83H35.2622V1.91329H32.6326V19.0836Z" fill="#FBFBFB"/>
<path d="M51.1715 1.91329H46.8108L42.2528 19.0836H44.97L46.1095 14.791H51.7413L52.8808 19.0836H55.7295L51.1715 1.91329ZM46.6574 12.6448L48.9363 3.75909H49.024L51.2153 12.6448H46.6574Z" fill="#FBFBFB"/>
<path d="M64.4348 8.56823H67.5027C67.5027 3.67471 65.903 1.57134 62.1777 1.57134C58.2552 1.57134 56.5679 4.23278 56.5679 10.4785C56.5679 16.7456 58.2552 19.4285 62.1777 19.4285C65.903 19.4285 67.5027 17.3895 67.5246 12.6462H64.4567C64.4348 16.3593 63.9746 17.2822 62.1777 17.2822C60.1179 17.2822 59.6138 15.93 59.6357 10.4785C59.6357 5.04833 60.1398 3.69616 62.1777 3.71761C63.9746 3.71761 64.4348 4.68351 64.4348 8.56823Z" fill="#FBFBFB"/>
<path d="M75.4027 1.57146C79.391 1.59302 81.1002 4.27581 81.1002 10.5C81.1002 16.7243 79.391 19.4072 75.4027 19.4286C71.3926 19.4501 69.6833 16.7672 69.6833 10.5C69.6833 4.23291 71.3926 1.55002 75.4027 1.57146ZM72.7512 10.5C72.7512 15.9302 73.2772 17.2823 75.4027 17.2823C77.5064 17.2823 78.0324 15.9302 78.0324 10.5C78.0324 5.04846 77.5064 3.69629 75.4027 3.71784C73.2772 3.73929 72.7512 5.09146 72.7512 10.5Z" fill="#FBFBFB"/>
<path d="M86.8315 19.0621L84.2019 19.0836V1.91329H88.8257L93.1427 15.9071H93.1865V1.91329H95.8156V19.0836H91.4773L86.8755 4.01667H86.8315V19.0621Z" fill="#FBFBFB"/>
<path d="M102.387 1.91329H99.7577V19.0836H102.387V1.91329Z" fill="#FBFBFB"/>
<path d="M113.176 8.56823H116.244C116.244 3.67471 114.644 1.57134 110.919 1.57134C106.997 1.57134 105.309 4.23278 105.309 10.4785C105.309 16.7456 106.997 19.4285 110.919 19.4285C114.644 19.4285 116.244 17.3895 116.266 12.6462H113.198C113.176 16.3593 112.716 17.2822 110.919 17.2822C108.859 17.2822 108.355 15.93 108.377 10.4785C108.377 5.04833 108.881 3.69616 110.919 3.71761C112.716 3.71761 113.176 4.68351 113.176 8.56823Z" fill="#FBFBFB"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -15,6 +15,8 @@ import VerifyEmail from "./pages/VerifyEmail";
import Email from "./pages/Email"; import Email from "./pages/Email";
import Thanks from "./pages/Thanks"; import Thanks from "./pages/Thanks";
import "./App.css";
function App() { function App() {
return ( return (
<Router> <Router>
@ -28,14 +30,8 @@ function App() {
<Route path="/thanks" element={<Thanks />} /> <Route path="/thanks" element={<Thanks />} />
<Route element={<SignPageLayout />}> <Route element={<SignPageLayout />}>
<Route path="/sign-with-nitro-key" element={<SignWithNitroKey />} /> <Route path="/sign-with-nitro-key" element={<SignWithNitroKey />} />
<Route <Route path="/user-verification" element={<UserVerification />} />
path="/user-verification" <Route path="/sign-with-cosmos" element={<SignWithCosmos />} />
element={<UserVerification />}
/>
<Route
path="/sign-with-cosmos"
element={<SignWithCosmos />}
/>
<Route <Route
path="/onboarding-success" path="/onboarding-success"
element={<OnboardingSuccess />} element={<OnboardingSuccess />}

View File

@ -0,0 +1,30 @@
import React, { ComponentPropsWithoutRef } from "react";
export interface CustomIconProps extends ComponentPropsWithoutRef<"svg"> {
size?: number | string; // width and height will both be set as the same value
name?: string;
}
export const CustomIcon: React.FC<CustomIconProps> = ({
children,
width = 24,
height = 24,
size,
viewBox = "0 0 24 24",
name,
...rest
}: CustomIconProps) => {
return (
<svg
aria-labelledby={name}
height={size || height}
role="presentation"
viewBox={viewBox}
width={size || width}
xmlns="http://www.w3.org/2000/svg"
{...rest}
>
{children}
</svg>
);
};

View File

@ -0,0 +1,78 @@
# CustomIcon
`CustomIcon` is a flexible and reusable React component for rendering SVG icons. It allows for easy customization of size, color, and other SVG properties.
- Viewbox "0 0 24 24": From where you're exporting from, please make sure the icon is using viewBox="0 0 24 24" before downloading/exporting. Not doing so will result in incorrect icon scaling
## Create a Custom Icon
1. Duplicate a current icon e.g. `LaconicIcon` and rename it accordingly.
2. Rename the function inside the new file you duplicated too
3. Replace the markup with your SVG markup (make sure it complies with the above section's rule)
4. Depending on the svg you pasted...
A. If the `<svg>` has only 1 child, remove the `<svg>` parent entirely so you only have the path left
B. If your component has more than 1 paths, rename `<svg>` tag with the `<g>` tag. Then, remove all attributes of this `<g>` tag so that it's just `<g>`
5. Usually, icons are single colored. If that's the case, replace all fill/stroke color with `currentColor`. E.g. `<path d="..." fill="currentColor">`. Leave the other attributes without removing them.
6. If your icon has more than one color, then it's up to you to decide whether we want to use tailwind to help set the fill and stroke colors
7. Lastly, export your icon in `index.ts` by following what was done for `LaconicIcon`
8. Make sure to provide a `name` for the `<CustomIcon>` component for accessibility
9. Done!
Example:
```tsx
import { CustomIcon, CustomIconProps } from "../CustomIcon";
export const LaconicIcon = (props: CustomIconProps) => {
return (
<CustomIcon
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M4.04924 12.6164C6.84238 9.85387 8.57128 6.03867 8.57051 1.82634C8.57154 1.25458 8.53962 0.689188 8.47618 0.130795L0 0.131558L0.000257231 16.2401C-0.000514887 18.1926 0.75217 20.1458 2.25767 21.6349C3.7633 23.124 5.73941 23.8693 7.71384 23.8683L7.71333 23.8688L24 23.8692L23.9994 15.4843C23.4361 15.4228 22.8645 15.3911 22.2851 15.391C18.0274 15.3915 14.17 17.1014 11.3769 19.864C9.34443 21.8239 6.08571 21.8243 4.07833 19.8388C2.07224 17.8545 2.07133 14.6303 4.04924 12.6164ZM22.2419 1.87395C19.9011 -0.441217 16.0981 -0.442108 13.7566 1.87395C11.415 4.18987 11.4159 7.95136 13.7566 10.2664C16.0985 12.5828 19.9003 12.5825 22.2419 10.2664C24.5835 7.95047 24.5838 4.19026 22.2419 1.87395Z"
fill="currentColor"
/>
</CustomIcon>
);
};
```
## Usage
```tsx
import { LaconicIcon } from './components/CustomIcon';
...
<LaconicIcon size={32} />
```
## Props
The `CustomIcon` component accepts the following props:
- `children`: SVG content (paths, groups, etc.)
- `size`: Sets both width and height (number or string)
- `width`: SVG width (default: 24)
- `height`: SVG height (default: 24)
- `viewBox`: SVG viewBox (default: "0 0 24 24")
- `name`: Icon name for accessibility (sets aria-labelledby)
- ...other SVG props
## Accessibility
Always provide a `name` prop to the CustomIcon for improved accessibility. This sets the `aria-labelledby` attribute on the SVG.
```tsx
<CustomIcon name="laconic-logo-icon">
{/* SVG content */}
</CustomIcon>
```
For icons that are purely decorative, the component sets `role="presentation"` by default.

View File

@ -0,0 +1,23 @@
import React from "react";
import { CustomIcon, CustomIconProps } from "../CustomIcon";
export const LaconicIcon: React.FC<CustomIconProps> = (props) => {
return (
<CustomIcon
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
name="laconic-logo-icon"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.04924 12.6164C6.84238 9.85387 8.57128 6.03867 8.57051 1.82634C8.57154 1.25458 8.53962 0.689188 8.47618 0.130795L0 0.131558L0.000257231 16.2401C-0.000514887 18.1926 0.75217 20.1458 2.25767 21.6349C3.7633 23.124 5.73941 23.8693 7.71384 23.8683L7.71333 23.8688L24 23.8692L23.9994 15.4843C23.4361 15.4228 22.8645 15.3911 22.2851 15.391C18.0274 15.3915 14.17 17.1014 11.3769 19.864C9.34443 21.8239 6.08571 21.8243 4.07833 19.8388C2.07224 17.8545 2.07133 14.6303 4.04924 12.6164ZM22.2419 1.87395C19.9011 -0.441217 16.0981 -0.442108 13.7566 1.87395C11.415 4.18987 11.4159 7.95136 13.7566 10.2664C16.0985 12.5828 19.9003 12.5825 22.2419 10.2664C24.5835 7.95047 24.5838 4.19026 22.2419 1.87395Z"
fill="currentColor"
/>
</CustomIcon>
);
};

View File

@ -0,0 +1,50 @@
import React from "react";
import { CustomIcon, CustomIconProps } from "../CustomIcon";
export const LaconicWithTextIcon: React.FC<CustomIconProps> = (props) => {
return (
<CustomIcon
width="117"
height="21"
viewBox="0 0 117 21"
fill="none"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.22282 11.0194C6.57609 8.69185 8.03272 5.47748 8.03206 1.92852C8.03293 1.44681 8.00604 0.970455 7.95259 0.499999L0.811272 0.500642L0.811488 14.0723C0.810838 15.7174 1.44499 17.3629 2.7134 18.6175C3.98191 19.8721 5.64682 20.5001 7.31031 20.4992L7.30988 20.4997L21.0317 20.5L21.0311 13.4355C20.5566 13.3838 20.075 13.357 19.5869 13.3569C15.9997 13.3574 12.7498 14.798 10.3965 17.1255C8.6841 18.7768 5.93858 18.7771 4.24733 17.1043C2.55716 15.4325 2.5564 12.7161 4.22282 11.0194ZM19.5504 1.96863C17.5783 0.0180696 14.3742 0.017319 12.4014 1.96863C10.4286 3.91984 10.4293 7.08895 12.4014 9.03941C14.3745 10.991 17.5776 10.9907 19.5504 9.03941C21.5232 7.0882 21.5236 3.92016 19.5504 1.96863Z"
fill="currentColor"
/>
<path
d="M32.6326 19.0836H40.4995V16.83H35.2622V1.91329H32.6326V19.0836Z"
fill="currentColor"
/>
<path
d="M51.1715 1.91329H46.8108L42.2528 19.0836H44.97L46.1095 14.791H51.7413L52.8808 19.0836H55.7295L51.1715 1.91329ZM46.6574 12.6448L48.9363 3.75909H49.024L51.2153 12.6448H46.6574Z"
fill="currentColor"
/>
<path
d="M64.4348 8.56823H67.5027C67.5027 3.67471 65.903 1.57134 62.1777 1.57134C58.2552 1.57134 56.5679 4.23278 56.5679 10.4785C56.5679 16.7456 58.2552 19.4285 62.1777 19.4285C65.903 19.4285 67.5027 17.3895 67.5246 12.6462H64.4567C64.4348 16.3593 63.9746 17.2822 62.1777 17.2822C60.1179 17.2822 59.6138 15.93 59.6357 10.4785C59.6357 5.04833 60.1398 3.69616 62.1777 3.71761C63.9746 3.71761 64.4348 4.68351 64.4348 8.56823Z"
fill="currentColor"
/>
<path
d="M75.4027 1.57146C79.391 1.59302 81.1002 4.27581 81.1002 10.5C81.1002 16.7243 79.391 19.4072 75.4027 19.4286C71.3926 19.4501 69.6833 16.7672 69.6833 10.5C69.6833 4.23291 71.3926 1.55002 75.4027 1.57146ZM72.7512 10.5C72.7512 15.9302 73.2772 17.2823 75.4027 17.2823C77.5064 17.2823 78.0324 15.9302 78.0324 10.5C78.0324 5.04846 77.5064 3.69629 75.4027 3.71784C73.2772 3.73929 72.7512 5.09146 72.7512 10.5Z"
fill="currentColor"
/>
<path
d="M86.8315 19.0621L84.2019 19.0836V1.91329H88.8257L93.1427 15.9071H93.1865V1.91329H95.8156V19.0836H91.4773L86.8755 4.01667H86.8315V19.0621Z"
fill="currentColor"
/>
<path
d="M102.387 1.91329H99.7577V19.0836H102.387V1.91329Z"
fill="currentColor"
/>
<path
d="M113.176 8.56823H116.244C116.244 3.67471 114.644 1.57134 110.919 1.57134C106.997 1.57134 105.309 4.23278 105.309 10.4785C105.309 16.7456 106.997 19.4285 110.919 19.4285C114.644 19.4285 116.244 17.3895 116.266 12.6462H113.198C113.176 16.3593 112.716 17.2822 110.919 17.2822C108.859 17.2822 108.355 15.93 108.377 10.4785C108.377 5.04833 108.881 3.69616 110.919 3.71761C112.716 3.71761 113.176 4.68351 113.176 8.56823Z"
fill="currentColor"
/>
</CustomIcon>
);
};

View File

@ -0,0 +1,2 @@
export { LaconicIcon } from "./icons/LaconicIcon";
export { LaconicWithTextIcon } from "./icons/LaconicWithTextIcon";

View File

@ -1,13 +1,17 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
body { body {
margin: 0; margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif; sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
code { code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace; monospace;
} }

15
tailwind.config.ts Normal file
View File

@ -0,0 +1,15 @@
import type { Config } from "tailwindcss";
const config: Config = {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
colors: {
snowball: "#0f86f5",
},
},
},
plugins: [],
};
export default config;

View File

@ -3629,6 +3629,13 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8"
integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
"@types/tailwindcss@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@types/tailwindcss/-/tailwindcss-3.1.0.tgz#1185e4b3437c6e0f19d6cc8cd42738a94fd7b64f"
integrity sha512-JxPzrm609hzvF4nmOI3StLjbBEP3WWQxDDJESqR1nh94h7gyyy3XSl0hn5RBMJ9mPudlLjtaXs5YEBtLw7CnPA==
dependencies:
tailwindcss "*"
"@types/testing-library__jest-dom@^5.9.1": "@types/testing-library__jest-dom@^5.9.1":
version "5.14.9" version "5.14.9"
resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz#0fb1e6a0278d87b6737db55af5967570b67cb466" resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz#0fb1e6a0278d87b6737db55af5967570b67cb466"
@ -4607,6 +4614,18 @@ autoprefixer@^10.4.13:
picocolors "^1.0.0" picocolors "^1.0.0"
postcss-value-parser "^4.2.0" postcss-value-parser "^4.2.0"
autoprefixer@^10.4.20:
version "10.4.20"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.20.tgz#5caec14d43976ef42e32dcb4bd62878e96be5b3b"
integrity sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==
dependencies:
browserslist "^4.23.3"
caniuse-lite "^1.0.30001646"
fraction.js "^4.3.7"
normalize-range "^0.1.2"
picocolors "^1.0.1"
postcss-value-parser "^4.2.0"
available-typed-arrays@^1.0.7: available-typed-arrays@^1.0.7:
version "1.0.7" version "1.0.7"
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846"
@ -5017,6 +5036,16 @@ browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.21.10, browserslist@^
node-releases "^2.0.14" node-releases "^2.0.14"
update-browserslist-db "^1.0.13" update-browserslist-db "^1.0.13"
browserslist@^4.23.3:
version "4.23.3"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800"
integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==
dependencies:
caniuse-lite "^1.0.30001646"
electron-to-chromium "^1.5.4"
node-releases "^2.0.18"
update-browserslist-db "^1.1.0"
bs58@^4.0.0, bs58@^4.0.1: bs58@^4.0.0, bs58@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
@ -5127,6 +5156,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001591:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz#571cf4f3f1506df9bf41fcbb6d10d5d017817bce" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz#571cf4f3f1506df9bf41fcbb6d10d5d017817bce"
integrity sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA== integrity sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==
caniuse-lite@^1.0.30001646:
version "1.0.30001651"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138"
integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==
canonical-json@^0.0.4: canonical-json@^0.0.4:
version "0.0.4" version "0.0.4"
resolved "https://registry.yarnpkg.com/canonical-json/-/canonical-json-0.0.4.tgz#6579c072c3db5c477ec41dc978fbf2b8f41074a3" resolved "https://registry.yarnpkg.com/canonical-json/-/canonical-json-0.0.4.tgz#6579c072c3db5c477ec41dc978fbf2b8f41074a3"
@ -6225,6 +6259,11 @@ electron-to-chromium@^1.4.668:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.710.tgz#d0ec4ea8a97df4c5eaeb8c69d45bf81f248b3855" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.710.tgz#d0ec4ea8a97df4c5eaeb8c69d45bf81f248b3855"
integrity sha512-w+9yAVHoHhysCa+gln7AzbO9CdjFcL/wN/5dd+XW/Msl2d/4+WisEaCF1nty0xbAKaxdaJfgLB2296U7zZB7BA== integrity sha512-w+9yAVHoHhysCa+gln7AzbO9CdjFcL/wN/5dd+XW/Msl2d/4+WisEaCF1nty0xbAKaxdaJfgLB2296U7zZB7BA==
electron-to-chromium@^1.5.4:
version "1.5.5"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz#03bfdf422bdd2c05ee2657efedde21264a1a566b"
integrity sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==
elliptic@6.5.4: elliptic@6.5.4:
version "6.5.4" version "6.5.4"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
@ -6508,7 +6547,7 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1" is-date-object "^1.0.1"
is-symbol "^1.0.2" is-symbol "^1.0.2"
escalade@^3.1.1: escalade@^3.1.1, escalade@^3.1.2:
version "3.1.2" version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
@ -8869,7 +8908,7 @@ jest@^27.4.3:
import-local "^3.0.2" import-local "^3.0.2"
jest-cli "^27.5.1" jest-cli "^27.5.1"
jiti@^1.19.1, jiti@^1.21.0: jiti@^1.21.0:
version "1.21.0" version "1.21.0"
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d"
integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
@ -9710,6 +9749,11 @@ node-releases@^2.0.14:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==
node-releases@^2.0.18:
version "2.0.18"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f"
integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==
node-yaml@^4.0.1: node-yaml@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/node-yaml/-/node-yaml-4.0.1.tgz#3675d27c275fbea9c02e2b0faa18bb1699444cb3" resolved "https://registry.yarnpkg.com/node-yaml/-/node-yaml-4.0.1.tgz#3675d27c275fbea9c02e2b0faa18bb1699444cb3"
@ -10171,6 +10215,11 @@ picocolors@^1.0.0:
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
picocolors@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1:
version "2.3.1" version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
@ -10792,7 +10841,7 @@ postcss@^7.0.35:
picocolors "^0.2.1" picocolors "^0.2.1"
source-map "^0.6.1" source-map "^0.6.1"
postcss@^8.3.5, postcss@^8.4.23, postcss@^8.4.33, postcss@^8.4.4: postcss@^8.3.5, postcss@^8.4.23, postcss@^8.4.33:
version "8.4.36" version "8.4.36"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.36.tgz#dba513c3c3733c44e0288a712894f8910bbaabc6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.36.tgz#dba513c3c3733c44e0288a712894f8910bbaabc6"
integrity sha512-/n7eumA6ZjFHAsbX30yhHup/IMkOmlmvtEi7P+6RMYf+bGJSUHc3geH4a0NSZxAz/RJfiS9tooCTs9LAVYUZKw== integrity sha512-/n7eumA6ZjFHAsbX30yhHup/IMkOmlmvtEi7P+6RMYf+bGJSUHc3geH4a0NSZxAz/RJfiS9tooCTs9LAVYUZKw==
@ -10801,6 +10850,15 @@ postcss@^8.3.5, postcss@^8.4.23, postcss@^8.4.33, postcss@^8.4.4:
picocolors "^1.0.0" picocolors "^1.0.0"
source-map-js "^1.1.0" source-map-js "^1.1.0"
postcss@^8.4.41:
version "8.4.41"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681"
integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==
dependencies:
nanoid "^3.3.7"
picocolors "^1.0.1"
source-map-js "^1.2.0"
prelude-ls@^1.2.1: prelude-ls@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@ -11823,6 +11881,11 @@ source-map-js@^1.0.1, source-map-js@^1.1.0:
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.1.0.tgz#9e7d5cb46f0689fb6691b30f226937558d0fa94b" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.1.0.tgz#9e7d5cb46f0689fb6691b30f226937558d0fa94b"
integrity sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw== integrity sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw==
source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
source-map-loader@^3.0.0: source-map-loader@^3.0.0:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.2.tgz#af23192f9b344daa729f6772933194cc5fa54fee" resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.2.tgz#af23192f9b344daa729f6772933194cc5fa54fee"
@ -12249,10 +12312,10 @@ system-architecture@^0.1.0:
resolved "https://registry.yarnpkg.com/system-architecture/-/system-architecture-0.1.0.tgz#71012b3ac141427d97c67c56bc7921af6bff122d" resolved "https://registry.yarnpkg.com/system-architecture/-/system-architecture-0.1.0.tgz#71012b3ac141427d97c67c56bc7921af6bff122d"
integrity sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA== integrity sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==
tailwindcss@^3.0.2: tailwindcss@*, tailwindcss@^3.4.9:
version "3.4.1" version "3.4.9"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.1.tgz#f512ca5d1dd4c9503c7d3d28a968f1ad8f5c839d" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.9.tgz#9e04cddce1924d530df62af37d3520f0e2a9d85e"
integrity sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA== integrity sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg==
dependencies: dependencies:
"@alloc/quick-lru" "^5.2.0" "@alloc/quick-lru" "^5.2.0"
arg "^5.0.2" arg "^5.0.2"
@ -12262,7 +12325,7 @@ tailwindcss@^3.0.2:
fast-glob "^3.3.0" fast-glob "^3.3.0"
glob-parent "^6.0.2" glob-parent "^6.0.2"
is-glob "^4.0.3" is-glob "^4.0.3"
jiti "^1.19.1" jiti "^1.21.0"
lilconfig "^2.1.0" lilconfig "^2.1.0"
micromatch "^4.0.5" micromatch "^4.0.5"
normalize-path "^3.0.0" normalize-path "^3.0.0"
@ -12751,6 +12814,14 @@ update-browserslist-db@^1.0.13:
escalade "^3.1.1" escalade "^3.1.1"
picocolors "^1.0.0" picocolors "^1.0.0"
update-browserslist-db@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e"
integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==
dependencies:
escalade "^3.1.2"
picocolors "^1.0.1"
uqr@^0.1.2: uqr@^0.1.2:
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/uqr/-/uqr-0.1.2.tgz#5c6cd5dcff9581f9bb35b982cb89e2c483a41d7d" resolved "https://registry.yarnpkg.com/uqr/-/uqr-0.1.2.tgz#5c6cd5dcff9581f9bb35b982cb89e2c483a41d7d"