mirror of
https://github.com/kremalicious/ipfs.git
synced 2024-12-27 23:27:47 +01:00
postcss config, add typekit async loading
This commit is contained in:
parent
444907ae0f
commit
090e907884
64
.eslintrc
64
.eslintrc
@ -1,36 +1,34 @@
|
||||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
"project": "./tsconfig.json",
|
||||
"tsconfigRootDir": "./"
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:jsx-a11y/recommended",
|
||||
"prettier/@typescript-eslint",
|
||||
"prettier/react",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
"plugins": ["@typescript-eslint", "react"],
|
||||
"rules": {
|
||||
"react/prop-types": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off"
|
||||
},
|
||||
"env": {
|
||||
"es6": true,
|
||||
"browser": true,
|
||||
"jest": true
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
"extends": ["eslint:recommended", "prettier"],
|
||||
"env": { "es6": true, "browser": true, "node": true },
|
||||
"settings": { "react": { "version": "detect" } },
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.ts", "**/*.tsx"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
"project": "./tsconfig.json",
|
||||
"tsconfigRootDir": "./"
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:jsx-a11y/recommended",
|
||||
"prettier/@typescript-eslint",
|
||||
"prettier/react",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
"plugins": ["@typescript-eslint", "react"],
|
||||
"rules": {
|
||||
"react/prop-types": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,7 +1,7 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
.DS_Store
|
||||
/.next/
|
||||
/out/
|
||||
/build
|
||||
.next
|
||||
out
|
||||
build
|
||||
package-lock.json
|
@ -1,5 +1,6 @@
|
||||
const withCSS = require('@zeit/next-css')
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const withSvgr = (nextConfig = {}, nextComposePlugins = {}) => {
|
||||
return Object.assign({}, nextConfig, {
|
||||
webpack(config, options) {
|
||||
@ -28,7 +29,6 @@ module.exports = withSvgr(
|
||||
withCSS({
|
||||
cssModules: true,
|
||||
cssLoaderOptions: {
|
||||
importLoaders: 1,
|
||||
localIdentName: '[local]___[hash:base64:5]'
|
||||
}
|
||||
})
|
||||
|
16
package.json
16
package.json
@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@kremalicious/ipfs",
|
||||
"version": "1.0.0",
|
||||
"description": "Public IPFS Node.",
|
||||
"description": "A public IPFS node.",
|
||||
"scripts": {
|
||||
"start": "next dev",
|
||||
"build": "next build",
|
||||
"serve": "next start",
|
||||
"test": "eslint --ignore-path .gitignore 'src/**/*.{ts,tsx}'",
|
||||
"format": "prettier ./src/**/*.{css,yml,js,jsx,ts,tsx,json} --write"
|
||||
"test": "eslint --ignore-path .gitignore '**/*.{js,jsx,ts,tsx}'",
|
||||
"format": "prettier --ignore-path .gitignore '**/*.{css,yml,js,jsx,ts,tsx,json}' --write"
|
||||
},
|
||||
"author": "Matthias Kretschmann <m@kretschmann.io>",
|
||||
"license": "MIT",
|
||||
@ -29,15 +29,23 @@
|
||||
"@types/react": "^16.9.9",
|
||||
"@typescript-eslint/eslint-plugin": "^2.4.0",
|
||||
"@typescript-eslint/parser": "^2.4.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"eslint": "^6.5.1",
|
||||
"eslint-config-prettier": "^6.4.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||
"eslint-plugin-prettier": "^3.1.1",
|
||||
"eslint-plugin-react": "^7.16.0",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"prettier": "^1.18.2",
|
||||
"typescript": "^3.6.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "10.x"
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
]
|
||||
}
|
||||
|
8
postcss.config.js
Normal file
8
postcss.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-preset-env': {
|
||||
importFrom: './src/styles/_variables.css'
|
||||
},
|
||||
cssnano: {}
|
||||
}
|
||||
}
|
@ -3,5 +3,6 @@ module.exports = {
|
||||
description: 'A public IPFS Gateway',
|
||||
url: 'https://ipfs.kretschmann.io',
|
||||
ipfsGateway: 'https://ipfs.kretschmann.io',
|
||||
ipfsNodeUri: 'https://ipfs.kretschmann.io:443'
|
||||
ipfsNodeUri: 'https://ipfs.kretschmann.io:443',
|
||||
typekitId: 'msu4qap'
|
||||
}
|
||||
|
5
src/@types/ipfs.d.ts
vendored
Normal file
5
src/@types/ipfs.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export interface IpfsConfig {
|
||||
protocol: string
|
||||
host: string
|
||||
port: string
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
@import './styles/_variables.css';
|
||||
|
||||
.app {
|
||||
padding: var(--spacer);
|
||||
display: flex;
|
||||
|
@ -1,9 +1,8 @@
|
||||
import React, { ReactNode } from 'react'
|
||||
import Head from 'next/head'
|
||||
import { NextSeo } from 'next-seo'
|
||||
import Footer from './components/Footer'
|
||||
import styles from './Layout.module.css'
|
||||
import { title, description, url } from '../site.config'
|
||||
import styles from './Layout.module.css'
|
||||
|
||||
export default function Layout({
|
||||
children,
|
||||
@ -14,10 +13,6 @@ export default function Layout({
|
||||
}) {
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<Head>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<NextSeo
|
||||
title={pageTitle}
|
||||
description={description}
|
||||
|
@ -1,5 +1,3 @@
|
||||
@import '../styles/_variables.css';
|
||||
|
||||
.add {
|
||||
width: 100%;
|
||||
overflow-wrap: break-word;
|
||||
|
@ -3,16 +3,9 @@ import { ipfsNodeUri, ipfsGateway } from '../../site.config'
|
||||
import Dropzone from './Dropzone'
|
||||
import styles from './Add.module.css'
|
||||
import Loader from './Loader'
|
||||
import useIpfsApi, { IpfsConfig } from '../hooks/use-ipfs-api'
|
||||
|
||||
export function formatBytes(a: number, b: number) {
|
||||
if (a === 0) return '0 Bytes'
|
||||
const c = 1024
|
||||
const d = b || 2
|
||||
const e = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||
const f = Math.floor(Math.log(a) / Math.log(c))
|
||||
return parseFloat((a / Math.pow(c, f)).toFixed(d)) + ' ' + e[f]
|
||||
}
|
||||
import useIpfsApi from '../hooks/use-ipfs-api'
|
||||
import { IpfsConfig } from '../@types/ipfs'
|
||||
import { formatBytes, addToIpfs } from '../utils'
|
||||
|
||||
const { hostname, port, protocol } = new URL(ipfsNodeUri)
|
||||
|
||||
@ -22,24 +15,6 @@ const ipfsConfig: IpfsConfig = {
|
||||
port: port || '443'
|
||||
}
|
||||
|
||||
async function addToIpfs(
|
||||
files: File[],
|
||||
setFileSizeReceived: (size: string) => void,
|
||||
ipfs: any
|
||||
) {
|
||||
const file = [...files][0]
|
||||
const fileDetails = { path: file.name, content: file }
|
||||
|
||||
const response = await ipfs.add(fileDetails, {
|
||||
wrapWithDirectory: true,
|
||||
progress: (length: number) => setFileSizeReceived(formatBytes(length, 0))
|
||||
})
|
||||
|
||||
// CID of wrapping directory is returned last
|
||||
const cid = `${response[response.length - 1].hash}/${file.name}`
|
||||
return cid
|
||||
}
|
||||
|
||||
export default function Add() {
|
||||
const { ipfs, isIpfsReady, ipfsError } = useIpfsApi(ipfsConfig)
|
||||
const [fileHash, setFileHash] = useState()
|
||||
|
@ -1,15 +1,5 @@
|
||||
@import '../styles/_variables.css';
|
||||
|
||||
:root {
|
||||
--border-color: var(--brand-grey-dimmed);
|
||||
}
|
||||
|
||||
:global(.dark) {
|
||||
--border-color: var(--brand-grey);
|
||||
}
|
||||
|
||||
.dropzone {
|
||||
border: 0.4rem dashed var(--border-color);
|
||||
border: 0.4rem dashed var(--brand-grey-dimmed);
|
||||
border-radius: var(--border-radius);
|
||||
padding: calc(var(--spacer) * 2) var(--spacer);
|
||||
transition: 0.2s ease-out;
|
||||
@ -18,6 +8,10 @@
|
||||
color: var(--brand-grey-light);
|
||||
}
|
||||
|
||||
:global(.dark) .dropzone {
|
||||
border-color: var(--brand-grey);
|
||||
}
|
||||
|
||||
.dropzone:hover,
|
||||
.dropzone:focus,
|
||||
.dropzone:active {
|
||||
|
@ -1,5 +1,3 @@
|
||||
@import '../styles/_variables.css';
|
||||
|
||||
.footer {
|
||||
width: 100%;
|
||||
font-size: var(--font-size-mini);
|
||||
|
@ -1,5 +1,3 @@
|
||||
@import '../styles/_variables.css';
|
||||
|
||||
.info {
|
||||
font-size: var(--font-size-small);
|
||||
opacity: 0.8;
|
||||
|
@ -1,5 +1,3 @@
|
||||
@import '../styles/_variables.css';
|
||||
|
||||
.loader {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
@ -10,17 +8,15 @@
|
||||
|
||||
.loader:before,
|
||||
.loader:after {
|
||||
--size: 1.75rem;
|
||||
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
margin-top: calc(var(--size) * -1);
|
||||
margin-left: calc(var(--size) / -2);
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
margin-top: calc(var(--loaderSize) * -1);
|
||||
margin-left: calc(var(--loaderSize) / -2);
|
||||
width: var(--loaderSize);
|
||||
height: var(--loaderSize);
|
||||
border-radius: 50%;
|
||||
background-color: var(--brand-cyan);
|
||||
opacity: 0.6;
|
||||
|
@ -1,5 +1,3 @@
|
||||
@import '../styles/_variables.css';
|
||||
|
||||
/* default: red square */
|
||||
.status {
|
||||
width: 0.5rem;
|
||||
|
@ -1,10 +1,3 @@
|
||||
@import '../styles/_variables.css';
|
||||
|
||||
:root {
|
||||
--knob-size: 8px;
|
||||
--knob-space: 1px;
|
||||
}
|
||||
|
||||
.themeSwitch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
@ -33,8 +26,8 @@
|
||||
.checkboxFake {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: calc(var(--knob-size) * 2.5);
|
||||
height: calc(var(--knob-size) + calc(var(--knob-space) * 4));
|
||||
width: calc(var(--switch-knob-size) * 2.5);
|
||||
height: calc(var(--switch-knob-size) + calc(var(--switch-knob-space) * 4));
|
||||
border: 1px solid var(--brand-grey-light);
|
||||
border-radius: 15rem;
|
||||
margin-left: calc(var(--spacer) / 3);
|
||||
@ -44,10 +37,10 @@
|
||||
.checkboxFake::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: var(--knob-space);
|
||||
left: var(--knob-space);
|
||||
width: var(--knob-size);
|
||||
height: var(--knob-size);
|
||||
top: var(--switch-knob-space);
|
||||
left: var(--switch-knob-space);
|
||||
width: var(--switch-knob-size);
|
||||
height: var(--switch-knob-size);
|
||||
background-color: var(--brand-grey-light);
|
||||
border-radius: 15rem;
|
||||
transition: transform 0.2s var(--easing);
|
||||
|
24
src/components/Typekit.tsx
Normal file
24
src/components/Typekit.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { typekitId } from '../../site.config'
|
||||
|
||||
const typekitScript = `
|
||||
(function(d) {
|
||||
var config = {
|
||||
kitId: '${typekitId}',
|
||||
scriptTimeout: 3000,
|
||||
async: true
|
||||
},
|
||||
h=d.documentElement,t=setTimeout(function(){h.className=h.className.replace(/\bwf-loading\b/g,"")+" wf-inactive";},config.scriptTimeout),tk=d.createElement("script"),f=false,s=d.getElementsByTagName("script")[0],a;h.className+=" wf-loading";tk.src='https://use.typekit.net/'+config.kitId+'.js';tk.async=true;tk.onload=tk.onreadystatechange=function(){a=this.readyState;if(f||a&&a!="complete"&&a!="loaded")return;f=true;clearTimeout(t);try{Typekit.load(config)}catch(e){}};s.parentNode.insertBefore(tk,s)
|
||||
})(document);
|
||||
`
|
||||
|
||||
export default function Typekit() {
|
||||
return typekitId ? (
|
||||
<Head key="typekit">
|
||||
<link rel="dns-prefetch" href="https://use.typekit.net/" />
|
||||
<link rel="dns-prefetch" href="https://p.typekit.net/" />
|
||||
<script dangerouslySetInnerHTML={{ __html: typekitScript }} />
|
||||
</Head>
|
||||
) : null
|
||||
}
|
@ -1,21 +1,11 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import ipfsClient from 'ipfs-http-client'
|
||||
import { parseHTML } from '../utils'
|
||||
import { IpfsConfig } from '../@types/ipfs'
|
||||
|
||||
let ipfs: any = null
|
||||
let ipfsVersion = ''
|
||||
|
||||
export interface IpfsConfig {
|
||||
protocol: string
|
||||
host: string
|
||||
port: string
|
||||
}
|
||||
|
||||
function parseHTML(str: string) {
|
||||
const tmp = document.implementation.createHTMLDocument()
|
||||
tmp.body.innerHTML = str
|
||||
return tmp.body.children
|
||||
}
|
||||
|
||||
export default function useIpfsApi(config: IpfsConfig) {
|
||||
const [isIpfsReady, setIpfsReady] = useState(Boolean(ipfs))
|
||||
const [ipfsError, setIpfsError] = useState('')
|
||||
|
16
src/pages/_app.tsx
Normal file
16
src/pages/_app.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import '../styles/global.css'
|
||||
import App from 'next/app'
|
||||
import React from 'react'
|
||||
import Typekit from '../components/Typekit'
|
||||
|
||||
export default class MyApp extends App {
|
||||
render() {
|
||||
const { Component, pageProps } = this.props
|
||||
return (
|
||||
<>
|
||||
<Typekit />
|
||||
<Component {...pageProps} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
@import '../styles/_variables.css';
|
||||
|
||||
.header {
|
||||
margin-top: 10vh;
|
||||
margin-bottom: calc(var(--spacer) * 3);
|
||||
|
@ -1,7 +1,4 @@
|
||||
import React from 'react'
|
||||
|
||||
import '../styles/global.css'
|
||||
|
||||
import Add from '../components/Add'
|
||||
import { title, description } from '../../site.config'
|
||||
import styles from './index.module.css'
|
||||
|
@ -44,6 +44,10 @@
|
||||
|
||||
--easing: cubic-bezier(0.75, 0, 0.08, 1);
|
||||
|
||||
--switch-knob-size: 8px;
|
||||
--switch-knob-space: 1px;
|
||||
--loaderSize: 1.75rem;
|
||||
|
||||
--body-background-color: var(--brand-light);
|
||||
--color-text: var(--brand-grey);
|
||||
--color-headings: var(--brand-main);
|
||||
|
@ -1,5 +1,4 @@
|
||||
@import '_variables.css';
|
||||
@import url('https://use.typekit.net/msu4qap.css');
|
||||
|
||||
*,
|
||||
*:before,
|
||||
|
33
src/utils.ts
33
src/utils.ts
@ -1,5 +1,32 @@
|
||||
import axios from 'axios'
|
||||
|
||||
export function formatBytes(a: number, b: number) {
|
||||
if (a === 0) return '0 Bytes'
|
||||
const c = 1024
|
||||
const d = b || 2
|
||||
const e = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||
const f = Math.floor(Math.log(a) / Math.log(c))
|
||||
return parseFloat((a / Math.pow(c, f)).toFixed(d)) + ' ' + e[f]
|
||||
}
|
||||
|
||||
export async function addToIpfs(
|
||||
files: File[],
|
||||
setFileSizeReceived: (size: string) => void,
|
||||
ipfs: any
|
||||
) {
|
||||
const file = [...files][0]
|
||||
const fileDetails = { path: file.name, content: file }
|
||||
|
||||
const response = await ipfs.add(fileDetails, {
|
||||
wrapWithDirectory: true,
|
||||
progress: (length: number) => setFileSizeReceived(formatBytes(length, 0))
|
||||
})
|
||||
|
||||
// CID of wrapping directory is returned last
|
||||
const cid = `${response[response.length - 1].hash}/${file.name}`
|
||||
return cid
|
||||
}
|
||||
|
||||
export async function pingUrl(url: string) {
|
||||
try {
|
||||
const response = await axios(url, { timeout: 5000 })
|
||||
@ -10,3 +37,9 @@ export async function pingUrl(url: string) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function parseHTML(str: string) {
|
||||
const tmp = document.implementation.createHTMLDocument()
|
||||
tmp.body.innerHTML = str
|
||||
return tmp.body.children
|
||||
}
|
||||
|
@ -20,6 +20,6 @@
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"exclude": ["node_modules", ".next"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.mdx"]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user