├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── .npmrc ├── .nvmrc ├── README.md ├── next-sitemap.config.js ├── next.config.js ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── prettier ├── public ├── favicon.ico ├── favicon │ ├── apple-touch-icon.png │ ├── favicon-48x48.png │ ├── favicon.ico │ ├── favicon.svg │ ├── site.webmanifest │ ├── web-app-manifest-192x192.png │ └── web-app-manifest-512x512.png ├── fonts │ └── inter-var-latin.woff2 ├── images │ ├── logo.png │ ├── logo192.png │ └── logo256.png └── svg │ ├── Logo.svg │ └── Vercel.svg ├── src ├── app │ ├── _components │ │ ├── Nav.tsx │ │ └── SensorDetails.tsx │ ├── layout.tsx │ ├── page.tsx │ └── v3 │ │ └── page.tsx ├── constant │ ├── config.ts │ └── env.ts ├── lib │ ├── deob │ │ ├── clean.ts │ │ └── index.ts │ └── parse │ │ ├── v2 │ │ ├── dec.ts │ │ ├── index.ts │ │ └── utils.ts │ │ └── v3 │ │ ├── dec.ts │ │ ├── detailed.ts │ │ ├── index.ts │ │ └── utils.ts └── styles │ └── globals.css ├── tailwind.config.ts ├── tsconfig.json └── vercel.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | plugins: ['@typescript-eslint', 'simple-import-sort', 'unused-imports'], 8 | extends: [ 9 | 'eslint:recommended', 10 | 'next', 11 | 'next/core-web-vitals', 12 | 'plugin:@typescript-eslint/recommended', 13 | 'prettier', 14 | ], 15 | rules: { 16 | 'no-unused-vars': 'off', 17 | 'no-console': 'warn', 18 | '@typescript-eslint/explicit-module-boundary-types': 'off', 19 | 'react/no-unescaped-entities': 'off', 20 | 21 | 'react/display-name': 'off', 22 | 'react/jsx-curly-brace-presence': [ 23 | 'warn', 24 | { props: 'never', children: 'never' }, 25 | ], 26 | 27 | //#region //*=========== Unused Import =========== 28 | '@typescript-eslint/no-unused-vars': 'off', 29 | 'unused-imports/no-unused-imports': 'warn', 30 | 'unused-imports/no-unused-vars': [ 31 | 'warn', 32 | { 33 | vars: 'all', 34 | varsIgnorePattern: '^_', 35 | args: 'after-used', 36 | argsIgnorePattern: '^_', 37 | }, 38 | ], 39 | //#endregion //*======== Unused Import =========== 40 | 41 | //#region //*=========== Import Sort =========== 42 | 'simple-import-sort/exports': 'warn', 43 | 'simple-import-sort/imports': [ 44 | 'warn', 45 | { 46 | groups: [ 47 | // ext library & side effect imports 48 | ['^@?\\w', '^\\u0000'], 49 | // {s}css files 50 | ['^.+\\.s?css$'], 51 | // Lib and hooks 52 | ['^@/lib', '^@/hooks'], 53 | // static data 54 | ['^@/data'], 55 | // components 56 | ['^@/_components', '^@/container'], 57 | // zustand store 58 | ['^@/store'], 59 | // Other imports 60 | ['^@/'], 61 | // relative paths up until 3 level 62 | [ 63 | '^\\./?$', 64 | '^\\.(?!/?$)', 65 | '^\\.\\./?$', 66 | '^\\.\\.(?!/?$)', 67 | '^\\.\\./\\.\\./?$', 68 | '^\\.\\./\\.\\.(?!/?$)', 69 | '^\\.\\./\\.\\./\\.\\./?$', 70 | '^\\.\\./\\.\\./\\.\\.(?!/?$)', 71 | ], 72 | ['^@/types'], 73 | // other that didnt fit in 74 | ['^'], 75 | ], 76 | }, 77 | ], 78 | //#endregion //*======== Import Sort =========== 79 | }, 80 | globals: { 81 | React: true, 82 | JSX: true, 83 | }, 84 | }; 85 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env 30 | .env*.local 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | 39 | # next-sitemap 40 | robots.txt 41 | sitemap.xml 42 | sitemap-*.xml 43 | 44 | /ignore 45 | 46 | /public/collector.js -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | enable-pre-post-scripts=true -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20.10.0 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [https://abck.dev/](https://abck.dev/) 2 | -------------------------------------------------------------------------------- /next-sitemap.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('next-sitemap').IConfig} 3 | * @see https://github.com/iamvishnusankar/next-sitemap#readme 4 | */ 5 | module.exports = { 6 | siteUrl: 'https://abck.dev', 7 | generateRobotsTxt: true, 8 | robotsTxtOptions: { 9 | policies: [{ userAgent: '*', allow: '/' }], 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | eslint: { 4 | dirs: ['src'], 5 | }, 6 | 7 | reactStrictMode: true, 8 | swcMinify: true, 9 | 10 | // Uncoment to add domain whitelist 11 | // images: { 12 | // remotePatterns: [ 13 | // { 14 | // protocol: 'https', 15 | // hostname: 'res.cloudinary.com', 16 | // }, 17 | // ] 18 | // }, 19 | 20 | webpack(config) { 21 | // Grab the existing rule that handles SVG imports 22 | const fileLoaderRule = config.module.rules.find((rule) => 23 | rule.test?.test?.('.svg') 24 | ); 25 | 26 | config.module.rules.push( 27 | // Reapply the existing rule, but only for svg imports ending in ?url 28 | { 29 | ...fileLoaderRule, 30 | test: /\.svg$/i, 31 | resourceQuery: /url/, // *.svg?url 32 | }, 33 | // Convert all other *.svg imports to React components 34 | { 35 | test: /\.svg$/i, 36 | issuer: { not: /\.(css|scss|sass)$/ }, 37 | resourceQuery: { not: /url/ }, // exclude if *.svg?url 38 | loader: '@svgr/webpack', 39 | options: { 40 | dimensions: false, 41 | titleProp: true, 42 | }, 43 | } 44 | ); 45 | 46 | // Modify the file loader rule to ignore *.svg, since we have it handled now. 47 | fileLoaderRule.exclude = /\.svg$/i; 48 | 49 | return config; 50 | }, 51 | }; 52 | 53 | module.exports = nextConfig; 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-nextjs-tailwind-starter", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "lint:strict": "eslint --max-warnings=0 src", 11 | "typecheck": "tsc --noEmit --incremental false", 12 | "postbuild": "next-sitemap --config next-sitemap.config.js" 13 | }, 14 | "dependencies": { 15 | "next": "^14.2.13", 16 | "react": "^18.2.0" 17 | }, 18 | "devDependencies": { 19 | "@svgr/webpack": "^8.1.0", 20 | "@tailwindcss/forms": "^0.5.9", 21 | "@tailwindcss/typography": "^0.5.15", 22 | "@types/react": "^18.3.4", 23 | "@typescript-eslint/eslint-plugin": "^5.62.0", 24 | "@typescript-eslint/parser": "^5.62.0", 25 | "autoprefixer": "^10.4.20", 26 | "eslint": "^8.57.1", 27 | "eslint-config-next": "^14.2.13", 28 | "eslint-config-prettier": "^8.10.0", 29 | "eslint-plugin-simple-import-sort": "^7.0.0", 30 | "eslint-plugin-unused-imports": "^2.0.0", 31 | "next-router-mock": "^0.9.0", 32 | "next-sitemap": "^2.5.28", 33 | "postcss": "^8.4.45", 34 | "prettier": "^2.8.8", 35 | "prettier-plugin-tailwindcss": "^0.5.14", 36 | "tailwindcss": "^3.4.12", 37 | "typescript": "^4.9.5" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /prettier: -------------------------------------------------------------------------------- 1 | /** @type {import("prettier").Config} */ 2 | 3 | module.exports = { 4 | singleQuote: true, 5 | tabWidth: 2, 6 | semi: true, 7 | trailingComma: 'all', 8 | arrowParens: 'always', 9 | parser: 'typescript', 10 | plugins: ['prettier-plugin-tailwindcss'], 11 | }; 12 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedd3v/abck-dev/bc6264ba0a7a2e2ceeb2593dd638b50076bf8036/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedd3v/abck-dev/bc6264ba0a7a2e2ceeb2593dd638b50076bf8036/public/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /public/favicon/favicon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedd3v/abck-dev/bc6264ba0a7a2e2ceeb2593dd638b50076bf8036/public/favicon/favicon-48x48.png -------------------------------------------------------------------------------- /public/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedd3v/abck-dev/bc6264ba0a7a2e2ceeb2593dd638b50076bf8036/public/favicon/favicon.ico -------------------------------------------------------------------------------- /public/favicon/favicon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "abck.dev", 3 | "short_name": "abck", 4 | "icons": [ 5 | { 6 | "src": "/favicon/web-app-manifest-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png", 9 | "purpose": "maskable" 10 | }, 11 | { 12 | "src": "/favicon/web-app-manifest-512x512.png", 13 | "sizes": "512x512", 14 | "type": "image/png", 15 | "purpose": "maskable" 16 | } 17 | ], 18 | "theme_color": "#000000", 19 | "background_color": "#000000", 20 | "display": "standalone" 21 | } -------------------------------------------------------------------------------- /public/favicon/web-app-manifest-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedd3v/abck-dev/bc6264ba0a7a2e2ceeb2593dd638b50076bf8036/public/favicon/web-app-manifest-192x192.png -------------------------------------------------------------------------------- /public/favicon/web-app-manifest-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedd3v/abck-dev/bc6264ba0a7a2e2ceeb2593dd638b50076bf8036/public/favicon/web-app-manifest-512x512.png -------------------------------------------------------------------------------- /public/fonts/inter-var-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedd3v/abck-dev/bc6264ba0a7a2e2ceeb2593dd638b50076bf8036/public/fonts/inter-var-latin.woff2 -------------------------------------------------------------------------------- /public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedd3v/abck-dev/bc6264ba0a7a2e2ceeb2593dd638b50076bf8036/public/images/logo.png -------------------------------------------------------------------------------- /public/images/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedd3v/abck-dev/bc6264ba0a7a2e2ceeb2593dd638b50076bf8036/public/images/logo192.png -------------------------------------------------------------------------------- /public/images/logo256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedd3v/abck-dev/bc6264ba0a7a2e2ceeb2593dd638b50076bf8036/public/images/logo256.png -------------------------------------------------------------------------------- /public/svg/Logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/svg/Vercel.svg: -------------------------------------------------------------------------------- 1 | Vercel -------------------------------------------------------------------------------- /src/app/_components/Nav.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | import Link from 'next/link'; 3 | 4 | import Logo from '~/images/logo.png'; 5 | 6 | const Nav = () => { 7 | return ( 8 |
9 |
10 | 14 | V2 15 | 16 |
17 |
18 | Logo 19 |
20 |
21 | 25 | V3 26 | 27 |
28 |
29 | ); 30 | }; 31 | 32 | export default Nav; 33 | -------------------------------------------------------------------------------- /src/app/_components/SensorDetails.tsx: -------------------------------------------------------------------------------- 1 | export interface SensorDetailsProps { 2 | key: string; 3 | value: string; 4 | mismatch?: boolean; 5 | inverted?: boolean; 6 | } 7 | 8 | const SensorDetails = ({ key, value, mismatch = false, inverted = false }: SensorDetailsProps) => { 9 | return ( 10 |
11 |
{key}
12 | 20 |
21 | ); 22 | }; 23 | 24 | export default SensorDetails; 25 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next'; 2 | import * as React from 'react'; 3 | 4 | import '@/styles/globals.css'; 5 | 6 | import { siteConfig } from '@/constant/config'; 7 | 8 | export const metadata: Metadata = { 9 | metadataBase: new URL(siteConfig.url), 10 | title: { 11 | default: siteConfig.title, 12 | template: `%s | ${siteConfig.title}`, 13 | }, 14 | description: siteConfig.description, 15 | robots: { index: true, follow: true }, 16 | icons: { 17 | icon: '/favicon/favicon.ico', 18 | shortcut: '/favicon/favicon-16x16.png', 19 | apple: '/favicon/apple-touch-icon.png', 20 | }, 21 | manifest: `/favicon/site.webmanifest`, 22 | openGraph: { 23 | url: siteConfig.url, 24 | title: siteConfig.title, 25 | description: siteConfig.description, 26 | siteName: siteConfig.title, 27 | images: [`${siteConfig.url}/images/logo.png`], 28 | type: 'website', 29 | locale: 'en_US', 30 | }, 31 | twitter: { 32 | card: 'summary_large_image', 33 | title: siteConfig.title, 34 | description: siteConfig.description, 35 | images: [`${siteConfig.url}/images/logo.png`], 36 | }, 37 | }; 38 | 39 | export default function RootLayout({ children }: { children: React.ReactNode }) { 40 | return ( 41 | 42 | {children} 43 | 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React, { useEffect, useState } from 'react'; 4 | 5 | import { ParsedSensor, parseSensor } from '@/lib/parse/v2'; 6 | 7 | import Nav from '@/app/_components/Nav'; 8 | 9 | export default function HomePage() { 10 | const [sensorL, setSensorL] = useState(''); 11 | const [parsedSensorL, setParsedSensorL] = useState({}); 12 | 13 | useEffect(() => { 14 | if (sensorL) { 15 | setParsedSensorL(parseSensor(sensorL, false)); 16 | } 17 | }, [sensorL]); 18 | 19 | const [sensorR, setSensorR] = React.useState(''); 20 | const [parsedSensorR, setParsedSensorR] = useState({}); 21 | 22 | useEffect(() => { 23 | if (sensorR) { 24 | setParsedSensorR(parseSensor(sensorR, false)); 25 | } 26 | }, [sensorR]); 27 | 28 | return ( 29 |
30 |