diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..c51365a --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,25 @@ +name: publish specs + +on: + push: + branches: + - "main" + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: ⬇️ Checkout repo + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: ⎔ Setup Node + uses: actions/setup-node@v1 + with: + node-version: 18.x + - name: 📦 Install deps + run: npm install + - name: 🚀 Deploy + run: npm run deploy-main + env: + DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5caacbb..61a1457 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ dist-ssr *.njsproj *.sln *.sw? + +package-lock.json \ No newline at end of file diff --git a/.gitpod.yml b/.gitpod.yml deleted file mode 100644 index 8238b63..0000000 --- a/.gitpod.yml +++ /dev/null @@ -1,11 +0,0 @@ -# This configuration file was automatically generated by Gitpod. -# Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) -# and commit this file to your remote git repository to share the goodness with others. - -# Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart - -tasks: - - init: yarn install && yarn run build - command: yarn run dev - - diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index bdef820..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["svelte.svelte-vscode"] -} diff --git a/.yarnrc.yml b/.yarnrc.yml deleted file mode 100644 index 3186f3f..0000000 --- a/.yarnrc.yml +++ /dev/null @@ -1 +0,0 @@ -nodeLinker: node-modules diff --git a/README.md b/README.md index 512c8b6..99f2475 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# specs +# specs. Where permaweb standards evolve! @@ -51,6 +51,3 @@ Contributions are welcome, use the issues to create an issue and then a branch t If you need help contributing, feel free to connect to our discord server and get help in the #dev channel. https://discord.gg/kyzkeF2qs8 - - - diff --git a/index.html b/index.html index f58f75a..1b220a8 100644 --- a/index.html +++ b/index.html @@ -1,21 +1,15 @@ - - - - - - - SPECS - - - - - - - -
- - - - \ No newline at end of file + + + SPECS + + + + + + +
+ + + diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index e596c58..0000000 --- a/jsconfig.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "moduleResolution": "Node", - "target": "ESNext", - "module": "ESNext", - /** - * svelte-preprocess cannot figure out whether you have - * a value or a type, so tell TypeScript to enforce using - * `import type` instead of `import` for Types. - */ - "importsNotUsedAsValues": "error", - "isolatedModules": true, - "resolveJsonModule": true, - /** - * To have warnings / errors of the Svelte compiler at the - * correct position, enable source maps by default. - */ - "sourceMap": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable this if you'd like to use dynamic types. - */ - "checkJs": true - }, - /** - * Use global.d.ts instead of compilerOptions.types - * to avoid limiting type declarations. - */ - "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] -} diff --git a/package.json b/package.json index 5486a2f..1cc0c2c 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,83 @@ { - "name": "specs.g8way.io", "private": true, + "name": "preact-specs", "version": "0.0.0", + "license": "MIT", "type": "module", "scripts": { "dev": "vite", "build": "vite build", - "preview": "vite preview" + "preview": "vite preview", + "lint": "eslint src", + "test": "jest", + "tw:build": "npx tailwindcss -i src/tailwind.css -c tailwind.config.js -o src/index.css", + "tw:watch": "npx tailwindcss -i src/tailwind.css -c tailwind.config.js -o src/index.css --watch", + "deploy-main": "tw:build && vite build && permaweb-deploy --ant-process 4bKkvG1AvzX6Ks2vjopkZQwvxUT0-jvvgAD3Xa0JDVs" }, - "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^2.0.3", - "autoprefixer": "^10.4.14", - "daisyui": "^2.51.5", - "postcss": "^8.4.21", - "svelte": "^3.55.1", - "tailwindcss": "^3.2.7", - "tinro": "^0.6.12", - "vite": "^4.2.0" + "eslintConfig": { + "parser": "@typescript-eslint/parser", + "extends": [ + "preact", + "plugin:@typescript-eslint/recommended" + ], + "ignorePatterns": [ + "build/" + ] }, "dependencies": { - "@permaweb/stampjs": "^0.3.2", - "@tailwindcss/typography": "^0.5.9", - "arweave": "^1.13.5", - "arweave-wallet-connector": "^1.0.1", - "convert-yaml": "^2.0.5", + "@permaweb/aoconnect": "^0.0.54", + "@permaweb/stampjs": "file:/Users/jackfrain/Desktop/stamp/packages/stampjs", + "@tailwindcss/typography": "^0.5.15", + "arweave-wallet-connector": "^1.0.2", "crocks": "^0.12.4", - "date-fns": "^2.29.3", + "daisyui": "^4.12.10", + "date-fns": "^3.6.0", + "easymde": "^2.18.0", "front-matter": "^4.0.2", - "marked": "^4.3.0", - "ramda": "^0.28.0", - "robot3": "^0.4.0", - "svelte-robot-factory": "^2.0.5", - "warp-contracts": "^1.4.10", - "warp-contracts-plugin-deploy": "^1.0.8", - "zod": "^3.21.4" + "hyper-async": "^1.1.2", + "js-yaml": "^4.1.0", + "marked": "^14.1.2", + "permaweb-deploy": "^1.1.8", + "preact": "^10.10.0", + "preact-render-to-string": "^5.2.1", + "preact-robot": "^0.3.0", + "preact-router": "^3.2.1", + "ramda": "^0.30.1", + "robot3": "^0.4.1", + "warp-contracts": "^1.4.45", + "warp-contracts-plugin-deploy": "^1.0.13", + "zod": "^3.23.8" + }, + "devDependencies": { + "@preact/preset-vite": "^2.9.1", + "@types/crocks": "^0.12.6", + "@types/enzyme": "^3.10.12", + "@types/jest": "^27.4.1", + "@types/ramda": "^0.30.2", + "@typescript-eslint/eslint-plugin": "^5.30.6", + "@typescript-eslint/parser": "^5.30.6", + "autoprefixer": "^10.4.20", + "cosmiconfig": "^8.2.0", + "cross-env": "^7.0.3", + "enzyme": "^3.11.0", + "enzyme-adapter-preact-pure": "^4.0.1", + "eslint": "^8.20.0", + "eslint-config-preact": "^1.3.0", + "jest": "^27.5.1", + "jest-preset-preact": "^4.0.5", + "postcss": "^8.4.45", + "preact-cli": "^3.4.0", + "preact-cli-plugin-env-vars": "^1.2.1", + "sirv-cli": "^2.0.2", + "tailwindcss": "^3.4.10", + "typescript": "^4.5.2", + "vite": "^5.4.5" + }, + "jest": { + "preset": "jest-preset-preact", + "setupFiles": [ + "/tests/__mocks__/browserMocks.ts", + "/tests/__mocks__/setupTests.ts" + ] } } diff --git a/preact.config.js b/preact.config.js new file mode 100644 index 0000000..1a0784d --- /dev/null +++ b/preact.config.js @@ -0,0 +1,8 @@ +export default (config) => { + // Resolve .tsx and .ts extensions + config.resolve.extensions.push('.ts', '.tsx') + config.node = { + process: true, + }; + // Additional configurations can be added here +} diff --git a/src/App.svelte b/src/App.svelte deleted file mode 100644 index 17edff7..0000000 --- a/src/App.svelte +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - {#if tx} - - {:else} - - {/if} - - -
- - - - - - - - - - - - - - diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..edd81f7 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,61 @@ +import { Route, Router } from 'preact-router'; +import { FunctionalComponent, h } from 'preact'; +import HomePage from './pages/home'; +import ShowPage from './pages/show'; +import Editor from './pages/form'; +import RelatedPage from './pages/related'; +import LearnPage from './pages/learn'; +import { useEffect, useState } from 'preact/hooks'; +import Match from 'preact-router/match'; + +const FadeInComponent: FunctionalComponent = ({ children }) => { + const [fadeClass, setFadeClass] = useState('fade-in'); + + useEffect(() => { + setFadeClass('fade-in'); + const timer = setTimeout(() => setFadeClass(''), 700); + return () => clearTimeout(timer); + }, [children]); + + return
{children}
; +}; + + +const App = () => { + const [path, setPath] = useState('/'); + + const handleRouteChange = (e: { url: string }) => { + setPath(e.url); + }; + + return ( + + + + + {({ matches, url }) => { + if (matches) { + const tx: string = url.match(/\/view\/([a-zA-Z0-9_-]+)/)?.[1]; + return ; + } + return
Not Found
; + }} +
+ + {({ matches, url }) => { + if (matches) { + const tx: string = url.match(/\/related\/([a-zA-Z0-9_-]+)/)?.[1]; + return ; + } + return
Not Found
; + }} +
+ + + +
+
+ ); +}; + +export default App; diff --git a/src/app.css b/src/app.css deleted file mode 100644 index 4130c14..0000000 --- a/src/app.css +++ /dev/null @@ -1,5 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap"); - -@tailwind utilities; -@tailwind components; -@tailwind base; diff --git a/src/components/announcer.svelte b/src/components/announcer.svelte deleted file mode 100644 index 35b3840..0000000 --- a/src/components/announcer.svelte +++ /dev/null @@ -1,24 +0,0 @@ - - -
- {#key current} - Navigated to {current} - {/key} -
- - diff --git a/src/components/announcer.tsx b/src/components/announcer.tsx new file mode 100644 index 0000000..ac8218b --- /dev/null +++ b/src/components/announcer.tsx @@ -0,0 +1,34 @@ +import { FunctionalComponent, h } from 'preact'; +import { useEffect, useState } from 'preact/hooks'; +import { getCurrentUrl } from 'preact-router' + +const Announcer: FunctionalComponent = () => { + const [current, setCurrent] = useState("Home"); + const curRoute = getCurrentUrl() + + useEffect(() => { + setCurrent(curRoute === "/" ? "Home" : curRoute.slice(1)); + }, []); + + return ( +
+ Navigated to {current} +
+ ); +}; + +export default Announcer; diff --git a/src/components/error.svelte b/src/components/error.svelte deleted file mode 100644 index 7c31964..0000000 --- a/src/components/error.svelte +++ /dev/null @@ -1,19 +0,0 @@ - - - - diff --git a/src/components/error.tsx b/src/components/error.tsx new file mode 100644 index 0000000..1b60464 --- /dev/null +++ b/src/components/error.tsx @@ -0,0 +1,42 @@ +import { useState } from 'preact/hooks'; + +interface ErrorModalProps { + open?: boolean; + error?: string; +} + +const ErrorModal = ({ open = false, error = "Unknown Error" }: ErrorModalProps) => { + const [isOpen, setIsOpen] = useState(open); + + return ( +
+ setIsOpen(!isOpen)} + /> + {isOpen && ( +
+
+
+
+ An error occurred while trying to stamp specification. +
+
{error}
+ +
+
+
+ )} +
+ ); +}; + +export default ErrorModal; \ No newline at end of file diff --git a/src/components/foo.tsx b/src/components/foo.tsx new file mode 100644 index 0000000..95e6236 --- /dev/null +++ b/src/components/foo.tsx @@ -0,0 +1,103 @@ +const foo = () => { + return ( + <>

Path-Manifest Schema

+

Status: Published

+

Version: v1

+

Abstract

+

The Arweave Path Manifest Schema is a specification for defining path manifests used in the Arweave blockchain protocol. Path manifests are JSON objects that describe the mapping between subpaths and the content they resolve to. The schema includes mandatory fields such as manifest (identifying the manifest type as arweave/paths) and version (specifying the version of the schema). Optional fields like index allow defining default behaviors when accessing the manifest directly. The paths field is essential, providing the mapping between subpaths and the corresponding transaction IDs to resolve for each subpath.

+

Motivation

+

To provide a standardized and structured way to define and manage the mapping between subpaths and content within the Arweave blockchain protocol. It serves several purposes:

+
    +
  1. Efficient Content Resolution: The path manifest allows efficient resolution of content within the Arweave network. By specifying the transaction IDs associated with specific subpaths, clients can easily retrieve the desired content without the need to search or traverse the entire blockchain.
  2. +
  3. Improved User Experience: The manifest enables a better user experience by providing default behaviors and a clear mapping between subpaths and content. Clients or gateways can use the manifest to determine the default path to load and serve the appropriate content. It simplifies the process of accessing and navigating content stored on the Arweave network.
  4. +
  5. Consistency and Interoperability: The schema promotes consistency and interoperability across different implementations and applications utilizing the Arweave protocol. By defining a standardized structure for path manifests, developers can create tools, services, and applications that can interpret and utilize path mappings consistently.
  6. +
+

This manifest enables gateways to serve content similar to a web server and its specified routes. This allows developers the ability to server web content from an Arweave Gateway.

+

Specification

+

Schema

+

Path manifests are JSON objects with the following keys.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldMandatory?TypeDescription
manifeststringThe manifest type identifier, this MUST be arweave/paths.
versionstringThe manifest specification version, currently "0.1.0". This will be updated with future updates according to semver.
index +objectThe behavior gateways SHOULD follow when the manifest is accessed directly. When defined, index MUST contain a member describing the behavior to adopt. Currently, the only supported behavior is path. index MAY be be omitted, in which case gateways SHOULD serve a listing of all paths.
index.path +stringThe default path to load. If defined, the field MUST reference a key in the paths object (it MUST NOT reference a transaction ID directly).
pathsobjectThe path mapping between subpaths and the content they resolve to. The object keys represent the subpaths, and the values tell us which content to resolve to.
paths[path].idstringThe transaction ID to resolve to for the given path.
+

A path manifest transaction MUST NOT contain any data other than this JSON object.
If path name is equal to '*' then all routes that are not found will be directed to the tx id in the value object.

+

The Content-Type tag for manifest files MUST be application/x.arweave-manifest+json, users MAY add other arbitrary user defined tags.

+

Example manifest

+
+  
+    {'{'}
+    "manifest": "arweave/paths",
+  "version": "0.1.0",
+  "index": {'{'}
+    "path": "index.html"
+  {'}'},
+  "paths": {'{'}
+    "index.html": {'{'}
+      "id": "cG7Hdi_iTQPoEYgQJFqJ8NMpN4KoZ-vH_j7pG4iP7NI"
+      {'}'},
+    "js/style.css": {'{'}
+      "id": "fZ4d7bkCAUiXSfo3zFsPiQvpLVKVtXUKB6kiLNt2XVQ"
+      {'}'},
+    "css/style.css": {'{'}
+      "id": "fZ4d7bkCAUiXSfo3zFsPiQvpLVKVtXUKB6kiLNt2XVQ"
+      {'}'},
+    "css/mobile.css": {'{'}
+      "id": "fZ4d7bkCAUiXSfo3zFsPiQvpLVKVtXUKB6kiLNt2XVQ"
+      {'}'},
+    "assets/img/logo.png": {'{'}
+      "id": "QYWh-QsozsYu2wor0ZygI5Zoa_fRYFc8_X1RkYmw_fU"
+      {'}'},
+    "assets/img/icon.png": {'{'}
+      "id": "0543SMRGYuGKTaqLzmpOyK4AxAB96Fra2guHzYxjRGo"
+      {'}'},
+    "*": {'{'}
+      "id": "cG7Hdi_iTQPoEYgQJFqJ8NMpN4KoZ-vH_j7pG4iP7NI"
+      {'}'}
+      {'}'}
+      {'}'}
+
) +} + +export default foo \ No newline at end of file diff --git a/src/components/item.svelte b/src/components/item.svelte deleted file mode 100644 index 9c8158d..0000000 --- a/src/components/item.svelte +++ /dev/null @@ -1,92 +0,0 @@ - - -
-
-
-
- -
- -

- {title} - {groupId ? `(${groupId})` : ""} -

-
-
-
- - - - - - -
-
- -
- - - - Stamps: ({stamps}) - Date: {timestamp > 0 - ? format(fromUnixTime(timestamp), "M/d/yyyy") - : "pending"} - Height: {height} - -
-
-
diff --git a/src/components/item.tsx b/src/components/item.tsx new file mode 100644 index 0000000..ff2b4a3 --- /dev/null +++ b/src/components/item.tsx @@ -0,0 +1,94 @@ +import { take, takeLast } from 'ramda'; +import { fromUnixTime, format } from 'date-fns'; +import { AoSpec } from 'src/types/Spec' + +interface AssetProps extends AoSpec { + onClick?: () => void; +} + +const shortHash = (h: string) => `${take(5, h)}...${takeLast(5, h)}`; + +const Asset = ({ + id, + BlockHeight, + Authors = [], + Description = "Description", + Owner = "", + Title = "Title", + GroupId = "GroupId", + Timestamp = "Pending", + stamps = 0, + onClick +}: AssetProps) => { + + const date = + typeof Timestamp === 'string' && +Timestamp > 0 + ? format(fromUnixTime(Math.floor(Number(Timestamp))), 'M/d/yyyy') + : 'pending' + return ( +
+
+
+
+ {/* Uncomment if you want to use avatar + */} +
+ {/* Uncomment if you want to display creator details +
+

{creator.name}

+
+

{creator.handle}

+ + + + */} +

+ {Title} {GroupId ? `(${GroupId})` : ''} +

+
+
+ +
+ +
+ + {shortHash(id)} + + {/* Stamps: ({stamps}) */} + + Date: {date} + + Height: {BlockHeight} +
+
+
+ ); +}; + +export default Asset; diff --git a/src/components/loading.svelte b/src/components/loading.svelte deleted file mode 100644 index 992ce99..0000000 --- a/src/components/loading.svelte +++ /dev/null @@ -1,13 +0,0 @@ - - - - diff --git a/src/components/loading.tsx b/src/components/loading.tsx new file mode 100644 index 0000000..083f16a --- /dev/null +++ b/src/components/loading.tsx @@ -0,0 +1,34 @@ +const Modal = ({ open, setOpen }: { + open: boolean, + setOpen?: (checked: boolean) => void +}) => { + const handleChange = (event) => { + if (setOpen) { + setOpen(event.target.checked); + } + }; + + return ( +
+ + {open && ( + + )} +
+ ); +}; + +export default Modal; diff --git a/src/components/publish-dialog.svelte b/src/components/publish-dialog.svelte deleted file mode 100644 index e69de29..0000000 diff --git a/src/components/sidebar-related.svelte b/src/components/sidebar-related.svelte deleted file mode 100644 index e3448de..0000000 --- a/src/components/sidebar-related.svelte +++ /dev/null @@ -1,111 +0,0 @@ - - -