mirror of
https://github.com/FlipsideCrypto/near-bos-vm.git
synced 2026-02-06 11:18:24 +00:00
Move VM to root
This commit is contained in:
parent
6f90e95caa
commit
5b68433497
2
.babelrc
2
.babelrc
@ -1,3 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/env", "@babel/preset-react"]
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"]
|
||||
}
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@
|
||||
|
||||
# production
|
||||
/build
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
84
README.md
84
README.md
@ -1,84 +0,0 @@
|
||||
# Browser
|
||||
|
||||
A framework for reusable components to render and modify SocialDB by Near Social.
|
||||
|
||||
## Setup & Development
|
||||
|
||||
Initialize repo:
|
||||
```
|
||||
yarn
|
||||
```
|
||||
|
||||
Start development version:
|
||||
```
|
||||
yarn start
|
||||
```
|
||||
|
||||
## Widget example
|
||||
|
||||
Profile view
|
||||
|
||||
```jsx
|
||||
let accountId = props.accountId || "eugenethedream";
|
||||
let profile = socialGetr(`${accountId}/profile`);
|
||||
|
||||
(
|
||||
<div>
|
||||
<img src={profile.image.url}/>
|
||||
<span>{profile.name}</span> <span>(@{accountId})</span>
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
Profile editor
|
||||
|
||||
```jsx
|
||||
let accountId = context.accountId;
|
||||
|
||||
if (!accountId) {
|
||||
return "Please sign in with NEAR wallet";
|
||||
}
|
||||
|
||||
const profile = socialGetr(`${accountId}/profile`);
|
||||
|
||||
if (profile === null) {
|
||||
return "Loading";
|
||||
}
|
||||
|
||||
initState({
|
||||
name: profile.name,
|
||||
url: profile.image.url,
|
||||
});
|
||||
|
||||
const data = {
|
||||
profile: {
|
||||
name: state.name,
|
||||
image: {
|
||||
url: state.url,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>account = {accountId}</div>
|
||||
<div>
|
||||
Name:
|
||||
<input type="text" value={state.name} />
|
||||
</div>
|
||||
<div>
|
||||
Image URL:
|
||||
<input type="text" value={state.url} />
|
||||
</div>
|
||||
<div>Preview</div>
|
||||
<div>
|
||||
<img src={state.url} alt="profile image" /> {state.name}
|
||||
</div>
|
||||
<div>
|
||||
<CommitButton data={data}>Save profile</CommitButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
```
|
||||
@ -4,11 +4,12 @@ const path = require("path");
|
||||
|
||||
module.exports = () => {
|
||||
return {
|
||||
output: {
|
||||
path: path.resolve(__dirname, "../dist"),
|
||||
publicPath: "./",
|
||||
filename: "[name].[contenthash].bundle.js",
|
||||
},
|
||||
// output: {
|
||||
// path: path.resolve(__dirname, "../dist"),
|
||||
// publicPath: "./",
|
||||
// // filename: "[name].[contenthash].bundle.js",
|
||||
// filename: "index.js",
|
||||
// },
|
||||
devtool: false,
|
||||
module: {
|
||||
rules: [
|
||||
@ -61,9 +62,9 @@ module.exports = () => {
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [new CssMinimizerPlugin(), "..."],
|
||||
runtimeChunk: {
|
||||
name: "runtime",
|
||||
},
|
||||
// runtimeChunk: {
|
||||
// name: "runtime",
|
||||
// },
|
||||
},
|
||||
performance: {
|
||||
hints: false,
|
||||
|
||||
120
package.json
120
package.json
@ -1,35 +1,86 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"version": "0.5.0",
|
||||
"homepage": "/",
|
||||
"private": true,
|
||||
"name": "near-social-vm",
|
||||
"version": "0.1.0",
|
||||
"description": "Near Social VM",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"@monaco-editor/react": "^4.4.6",
|
||||
"@near-wallet-selector/modal-ui": "^7.4.0",
|
||||
"@braintree/sanitize-url": "6.0.0",
|
||||
"@near-wallet-selector/core": "^7.4.0",
|
||||
"@near-wallet-selector/here-wallet": "^7.4.0",
|
||||
"@near-wallet-selector/meteor-wallet": "^7.4.0",
|
||||
"@near-wallet-selector/my-near-wallet": "^7.4.0",
|
||||
"@near-wallet-selector/near-wallet": "^7.4.0",
|
||||
"@near-wallet-selector/neth": "^7.4.0",
|
||||
"@near-wallet-selector/sender": "^7.4.0",
|
||||
"acorn": "^8.8.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"big.js": "^6.1.1",
|
||||
"bn.js": "^5.1.1",
|
||||
"bootstrap": "^5.2.1",
|
||||
"bootstrap-icons": "^1.9.0",
|
||||
"collections": "^5.1.12",
|
||||
"error-polyfill": "^0.1.2",
|
||||
"deep-equal": "^2.2.0",
|
||||
"elliptic": "^6.5.4",
|
||||
"idb": "^7.1.1",
|
||||
"local-storage": "^2.0.0",
|
||||
"mdast-util-find-and-replace": "^2.0.0",
|
||||
"near-api-js": "^0.45.1",
|
||||
"near-social-vm": "file:src/near-social-vm",
|
||||
"prettier": "^2.7.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.5.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"styled-components": "^5.3.6"
|
||||
"react-bootstrap-typeahead": "^6.0.0",
|
||||
"react-error-boundary": "^3.1.4",
|
||||
"react-files": "^3.0.0-alpha.3",
|
||||
"react-infinite-scroller": "^1.2.6",
|
||||
"react-markdown": "^7.1.0",
|
||||
"react-singleton-hook": "^3.1.1",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-uuid": "^1.0.2",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"styled-components": "^5.3.6",
|
||||
"tweetnacl": "^1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"buffer": "^6.0.3",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"copy-webpack-plugin": "^9.0.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^6.2.0",
|
||||
"css-minimizer-webpack-plugin": "^3.0.2",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"https-browserify": "^1.0.0",
|
||||
"mini-css-extract-plugin": "^2.2.2",
|
||||
"node-sass": "^7.0.3",
|
||||
"os-browserify": "^0.3.0",
|
||||
"postcss-loader": "^7.0.1",
|
||||
"process": "^0.11.10",
|
||||
"sass-loader": "^13.1.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"stream-http": "^3.2.0",
|
||||
"style-loader": "^3.2.1",
|
||||
"url": "^0.11.0",
|
||||
"webpack": "^5.52.0",
|
||||
"webpack-bundle-analyzer": "^4.4.2",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-dev-server": "^4.1.0",
|
||||
"webpack-manifest-plugin": "^5.0.0",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"webpack-node-externals": "^3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"serve": "webpack serve",
|
||||
"webpack": "webpack",
|
||||
"dev": "npm run serve -- --env mode=development",
|
||||
"prod": "npm run webpack -- --env mode=production",
|
||||
"prod:analyze": "npm run prod -- --env presets=analyze",
|
||||
"build": "npm run prod",
|
||||
"start": "npm run dev"
|
||||
"build": "npm run prod"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
@ -48,40 +99,5 @@
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.15.4",
|
||||
"@babel/core": "^7.15.5",
|
||||
"@babel/preset-env": "^7.15.4",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"assert": "^2.0.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"browserify-zlib": "^0.2.0",
|
||||
"buffer": "^6.0.3",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"copy-webpack-plugin": "^9.0.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^6.2.0",
|
||||
"css-minimizer-webpack-plugin": "^3.0.2",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"https-browserify": "^1.0.0",
|
||||
"mini-css-extract-plugin": "^2.2.2",
|
||||
"node-sass": "^7.0.3",
|
||||
"os-browserify": "^0.3.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"postcss-loader": "^7.0.1",
|
||||
"process": "^0.11.10",
|
||||
"sass-loader": "^13.1.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"stream-http": "^3.2.0",
|
||||
"style-loader": "^3.2.1",
|
||||
"url": "^0.11.0",
|
||||
"webpack": "^5.52.0",
|
||||
"webpack-bundle-analyzer": "^4.4.2",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-dev-server": "^4.1.0",
|
||||
"webpack-manifest-plugin": "^5.0.0",
|
||||
"webpack-merge": "^5.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
near.social
|
||||
@ -1 +0,0 @@
|
||||
/* /index.html 200
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
@ -1,33 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="favicon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Social data protocol built on NEAR"
|
||||
/>
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:site" content="@NearSocial_">
|
||||
<meta name="twitter:image" content="https://near.social/assets/logo.png">
|
||||
<meta property="og:image" content="https://near.social/assets/logo.png">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="Near Social" />
|
||||
<meta property="og:description" content="Social data protocol built on NEAR" />
|
||||
<link rel="apple-touch-icon" href="favicon.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<title>Near Social</title>
|
||||
<script defer data-domain="near.social" src="https://plausible.io/js/script.hash.js"></script>
|
||||
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }; window.analytics = function() { window.plausible(...arguments) }</script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
public/logo.png
BIN
public/logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB |
@ -1,15 +0,0 @@
|
||||
{
|
||||
"short_name": "Near Social",
|
||||
"name": "Near Social",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.png",
|
||||
"sizes": "1024x1024",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#333333",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
143
src/App.js
143
src/App.js
@ -1,143 +0,0 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import "error-polyfill";
|
||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
||||
import "@near-wallet-selector/modal-ui/styles.css";
|
||||
import "bootstrap/dist/js/bootstrap.bundle";
|
||||
import "App.scss";
|
||||
import { HashRouter as Router, Link, Route, Switch } from "react-router-dom";
|
||||
import EditorPage from "./pages/EditorPage";
|
||||
import ViewPage from "./pages/ViewPage";
|
||||
import { setupModal } from "@near-wallet-selector/modal-ui";
|
||||
import EmbedPage from "./pages/EmbedPage";
|
||||
import { useAccount, useInitNear, useNear, utils } from "near-social-vm";
|
||||
import Big from "big.js";
|
||||
import { NavigationWrapper } from "./components/navigation/NavigationWrapper";
|
||||
import { NetworkId, Widgets } from "./data/widgets";
|
||||
|
||||
export const refreshAllowanceObj = {};
|
||||
|
||||
function App(props) {
|
||||
console.log(useState);
|
||||
const [connected, setConnected] = useState(false);
|
||||
const [signedIn, setSignedIn] = useState(false);
|
||||
const [signedAccountId, setSignedAccountId] = useState(null);
|
||||
const [availableStorage, setAvailableStorage] = useState(null);
|
||||
const [walletModal, setWalletModal] = useState(null);
|
||||
const [widgetSrc, setWidgetSrc] = useState(null);
|
||||
|
||||
const { initNear } = useInitNear();
|
||||
const near = useNear();
|
||||
const account = useAccount();
|
||||
const accountId = account.accountId;
|
||||
|
||||
const location = window.location;
|
||||
|
||||
useEffect(() => {
|
||||
initNear &&
|
||||
initNear({
|
||||
networkId: NetworkId,
|
||||
});
|
||||
}, [initNear]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!location.search.includes("?account_id") &&
|
||||
!location.search.includes("&account_id") &&
|
||||
(location.search || location.href.includes("/?#"))
|
||||
) {
|
||||
window.history.replaceState({}, "/", "/" + location.hash);
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!near) {
|
||||
return;
|
||||
}
|
||||
near.selector.then((selector) => {
|
||||
setWalletModal(
|
||||
setupModal(selector, { contractId: near.config.contractName })
|
||||
);
|
||||
});
|
||||
}, [near]);
|
||||
|
||||
const requestSignIn = useCallback(
|
||||
(e) => {
|
||||
e && e.preventDefault();
|
||||
walletModal.show();
|
||||
return false;
|
||||
},
|
||||
[walletModal]
|
||||
);
|
||||
|
||||
const logOut = useCallback(async () => {
|
||||
if (!near) {
|
||||
return;
|
||||
}
|
||||
const wallet = await (await near.selector).wallet();
|
||||
wallet.signOut();
|
||||
near.accountId = null;
|
||||
setSignedIn(false);
|
||||
setSignedAccountId(null);
|
||||
}, [near]);
|
||||
|
||||
const refreshAllowance = useCallback(async () => {
|
||||
alert(
|
||||
"You're out of access key allowance. Need sign in again to refresh it"
|
||||
);
|
||||
await logOut();
|
||||
requestSignIn();
|
||||
}, [logOut, requestSignIn]);
|
||||
refreshAllowanceObj.refreshAllowance = refreshAllowance;
|
||||
|
||||
useEffect(() => {
|
||||
if (!near) {
|
||||
return;
|
||||
}
|
||||
setSignedIn(!!accountId);
|
||||
setSignedAccountId(accountId);
|
||||
setConnected(true);
|
||||
}, [near, accountId]);
|
||||
|
||||
useEffect(() => {
|
||||
setAvailableStorage(
|
||||
account.storageBalance
|
||||
? Big(account.storageBalance.available).div(utils.StorageCostPerByte)
|
||||
: Big(0)
|
||||
);
|
||||
}, [account]);
|
||||
|
||||
const passProps = {
|
||||
refreshAllowance: () => refreshAllowance(),
|
||||
setWidgetSrc,
|
||||
signedAccountId,
|
||||
signedIn,
|
||||
connected,
|
||||
availableStorage,
|
||||
widgetSrc,
|
||||
logOut,
|
||||
requestSignIn,
|
||||
widgets: Widgets,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<Router basename={process.env.PUBLIC_URL}>
|
||||
<Switch>
|
||||
<Route path={"/embed/:widgetSrc*"}>
|
||||
<EmbedPage {...passProps} />
|
||||
</Route>
|
||||
<Route path={"/edit/:widgetSrc*"}>
|
||||
<NavigationWrapper {...passProps} />
|
||||
<EditorPage {...passProps} />
|
||||
</Route>
|
||||
<Route path={"/:widgetSrc*"}>
|
||||
<NavigationWrapper {...passProps} />
|
||||
<ViewPage {...passProps} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
45
src/App.scss
45
src/App.scss
@ -1,45 +0,0 @@
|
||||
@import "bootstrap";
|
||||
|
||||
body, html {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-success, .btn-primary {
|
||||
.text-muted {
|
||||
color: #fff !important;
|
||||
};
|
||||
}
|
||||
|
||||
.outline-none {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
&.btn {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-items {
|
||||
&> div {
|
||||
border-right: 1px solid #e5e5e5;
|
||||
text-align: center;
|
||||
min-height: 4rem;
|
||||
max-height: 4rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&> div:not(.apps) {
|
||||
min-width: 4rem;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
}
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
|
||||
export default function OpenModal(props) {
|
||||
const onHide = props.onHide;
|
||||
const onOpen = props.onOpen;
|
||||
const onNew = props.onNew;
|
||||
const show = props.show;
|
||||
|
||||
const [widgetSrc, setWidgetSrc] = useState("");
|
||||
|
||||
return (
|
||||
<Modal centered scrollable show={show} onHide={onHide}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Open widget</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<label htmlFor="widget-src-input" className="form-label">
|
||||
Widget name <span className="text-muted">(or path)</span>
|
||||
</label>
|
||||
<input
|
||||
className="form-control"
|
||||
id="widget-src-input"
|
||||
type="text"
|
||||
value={widgetSrc}
|
||||
onChange={(e) =>
|
||||
setWidgetSrc(e.target.value.replaceAll(/[^a-zA-Z0-9_.\-\/]/g, ""))
|
||||
}
|
||||
/>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<button
|
||||
className="btn btn-success"
|
||||
disabled={!widgetSrc}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onOpen(widgetSrc);
|
||||
setWidgetSrc("");
|
||||
onHide();
|
||||
}}
|
||||
>
|
||||
Open
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-outline-success"
|
||||
disabled={widgetSrc && widgetSrc.indexOf("/") !== -1}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onNew(widgetSrc);
|
||||
setWidgetSrc("");
|
||||
onHide();
|
||||
}}
|
||||
>
|
||||
Create New
|
||||
</button>
|
||||
<button className="btn btn-secondary" onClick={onHide}>
|
||||
Close
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
|
||||
export default function RenameModal(props) {
|
||||
const onHide = props.onHide;
|
||||
const name = props.name;
|
||||
const onRename = props.onRename;
|
||||
const show = props.show;
|
||||
|
||||
const [newName, setNewName] = useState(name);
|
||||
|
||||
return (
|
||||
<Modal centered scrollable show={show} onHide={onHide}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Rename</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<label htmlFor="rename-input" className="form-label">
|
||||
New name
|
||||
</label>
|
||||
<input
|
||||
className="form-control"
|
||||
id="rename-input"
|
||||
type="text"
|
||||
value={newName}
|
||||
onChange={(e) =>
|
||||
setNewName(e.target.value.replaceAll(/[^a-zA-Z0-9_.\-]/g, ""))
|
||||
}
|
||||
/>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<button
|
||||
className="btn btn-success"
|
||||
disabled={!newName || newName === name}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onRename(newName);
|
||||
onHide();
|
||||
}}
|
||||
>
|
||||
Confirm
|
||||
</button>
|
||||
<button className="btn btn-secondary" onClick={onHide}>
|
||||
Close
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
import React from "react";
|
||||
import { Button } from "./Button";
|
||||
import styled from "styled-components";
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
background-color: var(--blue-light-9);
|
||||
border-color: var(--blue-light-9);
|
||||
color: white;
|
||||
`;
|
||||
|
||||
export function BlueButton(props) {
|
||||
return <StyledButton {...props}>{props.children}</StyledButton>;
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
const StyledButton = styled.button`
|
||||
border-radius: 8px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: transparent;
|
||||
padding: 8px 16px;
|
||||
font-weight: var(--font-weight-bold);
|
||||
display: inline-block;
|
||||
height: 40px;
|
||||
`;
|
||||
|
||||
export function Button(props) {
|
||||
return (
|
||||
<StyledButton
|
||||
className={props.className}
|
||||
onClick={props.onClick}
|
||||
title={props.title}
|
||||
disabled={props.disabled}
|
||||
>
|
||||
{props.children}
|
||||
</StyledButton>
|
||||
);
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
import React from "react";
|
||||
import { Button } from "./Button";
|
||||
import styled from "styled-components";
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
background-color: var(--slate-dark-6);
|
||||
border-color: var(--slate-dark-8);
|
||||
color: white;
|
||||
`;
|
||||
|
||||
export function GrayBorderButton(props) {
|
||||
return <StyledButton {...props}>{props.children}</StyledButton>;
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function ArrowUpRight() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="arrow-up-right"
|
||||
>
|
||||
<path
|
||||
d="M17.25 15.25V6.75H8.75"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M17 7L6.75 17.25"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function Book() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19.25 5.75C19.25 5.19772 18.8023 4.75 18.25 4.75H14C12.8954 4.75 12 5.64543 12 6.75V19.25L12.8284 18.4216C13.5786 17.6714 14.596 17.25 15.6569 17.25H18.25C18.8023 17.25 19.25 16.8023 19.25 16.25V5.75Z"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M4.75 5.75C4.75 5.19772 5.19772 4.75 5.75 4.75H10C11.1046 4.75 12 5.64543 12 6.75V19.25L11.1716 18.4216C10.4214 17.6714 9.40401 17.25 8.34315 17.25H5.75C5.19772 17.25 4.75 16.8023 4.75 16.25V5.75Z"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function Close() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17.25 6.75L6.75 17.25"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M6.75 6.75L17.25 17.25"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function Code() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M4.75 6.75C4.75 5.64543 5.64543 4.75 6.75 4.75H17.25C18.3546 4.75 19.25 5.64543 19.25 6.75V17.25C19.25 18.3546 18.3546 19.25 17.25 19.25H6.75C5.64543 19.25 4.75 18.3546 4.75 17.25V6.75Z"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M8.75 10.75L11.25 13L8.75 15.25"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function Fork() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.25 7C9.25 8.24264 8.24264 9.25 7 9.25C5.75736 9.25 4.75 8.24264 4.75 7C4.75 5.75736 5.75736 4.75 7 4.75C8.24264 4.75 9.25 5.75736 9.25 7Z"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M19.25 7C19.25 8.24264 18.2426 9.25 17 9.25C15.7574 9.25 14.75 8.24264 14.75 7C14.75 5.75736 15.7574 4.75 17 4.75C18.2426 4.75 19.25 5.75736 19.25 7Z"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M14.25 17C14.25 18.2426 13.2426 19.25 12 19.25C10.7574 19.25 9.75 18.2426 9.75 17C9.75 15.7574 10.7574 14.75 12 14.75C13.2426 14.75 14.25 15.7574 14.25 17Z"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M6.75 9.5V10.25C6.75 11.3546 7.64543 12.25 8.75 12.25H12M17.25 9.5V10.25C17.25 11.3546 16.3546 12.25 15.25 12.25H12M12 12.25V14.5"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function Home() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6.75024 19.2502H17.2502C18.3548 19.2502 19.2502 18.3548 19.2502 17.2502V9.75025L12.0002 4.75024L4.75024 9.75025V17.2502C4.75024 18.3548 5.64568 19.2502 6.75024 19.2502Z"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M9.74963 15.7493C9.74963 14.6447 10.6451 13.7493 11.7496 13.7493H12.2496C13.3542 13.7493 14.2496 14.6447 14.2496 15.7493V19.2493H9.74963V15.7493Z"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function LogOut() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M15.75 8.75L19.25 12L15.75 15.25"
|
||||
stroke="#697177"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M19 12H10.75"
|
||||
stroke="#697177"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M15.25 4.75H6.75C5.64543 4.75 4.75 5.64543 4.75 6.75V17.25C4.75 18.3546 5.64543 19.25 6.75 19.25H15.25"
|
||||
stroke="#697177"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function NearSocialLogo() {
|
||||
return (
|
||||
<svg
|
||||
width="29"
|
||||
height="20"
|
||||
viewBox="0 0 29 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.55396 17.509L2 9.99996L9.55396 2.49097"
|
||||
stroke="#3D7FFF"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M19.536 2.49097L27 9.99996L19.536 17.509"
|
||||
stroke="#3D7FFF"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function Pretend() {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="none"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path
|
||||
strokeWidth="0.3px"
|
||||
fill="#697177"
|
||||
d="M1.5 1a.5.5 0 0 0-.5.5v3a.5.5 0 0 1-1 0v-3A1.5 1.5 0 0 1 1.5 0h3a.5.5 0 0 1 0 1h-3zM11 .5a.5.5 0 0 1 .5-.5h3A1.5 1.5 0 0 1 16 1.5v3a.5.5 0 0 1-1 0v-3a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 1-.5-.5zM.5 11a.5.5 0 0 1 .5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 1 0 1h-3A1.5 1.5 0 0 1 0 14.5v-3a.5.5 0 0 1 .5-.5zm15 0a.5.5 0 0 1 .5.5v3a1.5 1.5 0 0 1-1.5 1.5h-3a.5.5 0 0 1 0-1h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 1 .5-.5z"
|
||||
/>
|
||||
<path
|
||||
strokeWidth="0.3px"
|
||||
fill="#697177"
|
||||
d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm8-9a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function StopPretending() {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="none"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path
|
||||
strokeWidth="0.3px"
|
||||
fill="#697177"
|
||||
d="M13.879 10.414a2.501 2.501 0 0 0-3.465 3.465l3.465-3.465Zm.707.707-3.465 3.465a2.501 2.501 0 0 0 3.465-3.465Zm-4.56-1.096a3.5 3.5 0 1 1 4.949 4.95 3.5 3.5 0 0 1-4.95-4.95ZM11 5a3 3 0 1 1-6 0 3 3 0 0 1 6 0Zm-9 8c0 1 1 1 1 1h5.256A4.493 4.493 0 0 1 8 12.5a4.49 4.49 0 0 1 1.544-3.393C9.077 9.038 8.564 9 8 9c-5 0-6 3-6 4Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function User() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M15.25 8C15.25 9.79493 13.7949 11.25 12 11.25C10.2051 11.25 8.75 9.79493 8.75 8C8.75 6.20507 10.2051 4.75 12 4.75C13.7949 4.75 15.25 6.20507 15.25 8Z"
|
||||
stroke="#697177"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M6.84751 19.25H17.1525C18.2944 19.25 19.174 18.2681 18.6408 17.2584C17.8563 15.7731 16.068 14 12 14C7.93201 14 6.14367 15.7731 5.35924 17.2584C4.82597 18.2681 5.70559 19.25 6.84751 19.25Z"
|
||||
stroke="#697177"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function UserCircle() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19.25 12C19.25 16.0041 16.0041 19.25 12 19.25C7.99594 19.25 4.75 16.0041 4.75 12C4.75 7.99594 7.99594 4.75 12 4.75C16.0041 4.75 19.25 7.99594 19.25 12Z"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M14.25 10C14.25 11.2426 13.2426 12.25 12 12.25C10.7574 12.25 9.75 11.2426 9.75 10C9.75 8.75736 10.7574 7.75 12 7.75C13.2426 7.75 14.25 8.75736 14.25 10Z"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.19745 17C8.34392 15.625 10.0698 14.75 12 14.75C13.9302 14.75 15.6561 15.625 16.8025 17"
|
||||
stroke="#9BA1A6"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export function Withdraw() {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeWidth="0.3px"
|
||||
d="M14.9634 10.8766C15.2234 11.1366 15.2234 11.5567 14.9634 11.8167L12.4701 14.3067C12.2101 14.5701 11.79 14.5701 11.5301 14.3067L9.03676 11.8167C8.77679 11.5567 8.77679 11.1366 9.03676 10.8766C9.30016 10.6133 9.72011 10.6133 9.98008 10.8766L11.3333 12.2267V6.66667C11.3333 5.1933 12.5266 4 14 4H17.3333C18.8067 4 20 5.1933 20 6.66667V17.3333C20 18.8067 18.8067 20 17.3333 20H6.66667C5.1933 20 4 18.8067 4 17.3333V6.66667C4 5.1933 5.1933 4 6.66667 4H9.33333C9.7 4 10 4.3 10 4.66667C10 5.03333 9.7 5.33333 9.33333 5.33333H6.66667C5.93006 5.33333 5.33333 5.93006 5.33333 6.66667V17.3333C5.33333 18.0699 5.93006 18.6667 6.66667 18.6667H17.3333C18.0699 18.6667 18.6667 18.0699 18.6667 17.3333V6.66667C18.6667 5.93006 18.0699 5.33333 17.3333 5.33333H14C13.2634 5.33333 12.6667 5.93006 12.6667 6.66667V12.2267L14.0199 10.8766C14.28 10.6134 14.7 10.6134 14.9634 10.8766Z"
|
||||
fill="#697177"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -1,51 +0,0 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { NavLink } from "react-router-dom";
|
||||
|
||||
const StyledNavigationButton = styled.div`
|
||||
a {
|
||||
color: var(--slate-dark-11);
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
font-weight: var(--font-weight-bold);
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
background-color: var(--slate-dark-6);
|
||||
}
|
||||
}
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
`;
|
||||
|
||||
export function NavigationButton(props) {
|
||||
return (
|
||||
<StyledNavigationButton className={props.disabled ? "disabled" : ""}>
|
||||
{props.route ? (
|
||||
<NavLink
|
||||
onClick={(e) => {
|
||||
if (props.disabled) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}}
|
||||
to={props.route}
|
||||
exact={true}
|
||||
>
|
||||
{props.children}
|
||||
</NavLink>
|
||||
) : (
|
||||
<a href={props.href} target="_blank" rel="noopener noreferrer">
|
||||
{props.children}
|
||||
</a>
|
||||
)}
|
||||
</StyledNavigationButton>
|
||||
);
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { DesktopNavigation } from "./desktop/DesktopNavigation";
|
||||
import { MobileNavigation } from "./mobile/MobileNavigation";
|
||||
|
||||
export function NavigationWrapper(props) {
|
||||
const [matches, setMatches] = useState(
|
||||
window.matchMedia("(min-width: 992px)").matches
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
window
|
||||
.matchMedia("(min-width: 992px)")
|
||||
.addEventListener("change", (e) => setMatches(e.matches));
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
{matches && <DesktopNavigation {...props} />}
|
||||
{!matches && <MobileNavigation {...props} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Widget } from "near-social-vm";
|
||||
|
||||
const StyledNotificationWidget = styled.div`
|
||||
margin: 0 15px;
|
||||
background-color: var(--slate-dark-5);
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 50%;
|
||||
|
||||
> div,
|
||||
a {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--slate-dark-11) !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
i {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
}
|
||||
|
||||
:hover {
|
||||
a,
|
||||
i {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function NotificationWidget({ notificationButtonSrc }) {
|
||||
return (
|
||||
<StyledNotificationWidget className="nav-notification-widget">
|
||||
<Widget src={notificationButtonSrc} />
|
||||
</StyledNotificationWidget>
|
||||
);
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import { Widget, useAccount } from "near-social-vm";
|
||||
|
||||
export default function PretendModal(props) {
|
||||
const account = useAccount();
|
||||
const onHide = props.onHide;
|
||||
const show = props.show;
|
||||
|
||||
const [accountId, setAccountId] = useState("");
|
||||
|
||||
return (
|
||||
<Modal centered show={show} onHide={onHide}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Pretend to be another account</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<div>
|
||||
<label htmlFor="widget-src-input" className="form-label">
|
||||
Pretend to be account ID:
|
||||
</label>
|
||||
<input
|
||||
className="form-control"
|
||||
id="widget-src-input"
|
||||
type="text"
|
||||
value={accountId}
|
||||
onChange={(e) =>
|
||||
setAccountId(
|
||||
e.target.value.toLowerCase().replaceAll(/[^a-z0-9_.\-]/g, "")
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<Widget
|
||||
src={props.widgets.profileInlineBlock}
|
||||
props={{ accountId }}
|
||||
/>
|
||||
</div>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<button
|
||||
className="btn btn-success"
|
||||
disabled={!accountId || !account.startPretending}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
account.startPretending(accountId);
|
||||
setAccountId("");
|
||||
onHide();
|
||||
}}
|
||||
>
|
||||
Pretend
|
||||
</button>
|
||||
<button className="btn btn-secondary" onClick={onHide}>
|
||||
Cancel
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
import React from "react";
|
||||
import { GrayBorderButton } from "../common/buttons/GrayBorderButton";
|
||||
|
||||
export function SignInButton(props) {
|
||||
return (
|
||||
<GrayBorderButton className="nav-sign-in-btn" onClick={props.onSignIn}>
|
||||
Sign In
|
||||
</GrayBorderButton>
|
||||
);
|
||||
}
|
||||
@ -1,91 +0,0 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Logotype } from "../Logotype";
|
||||
import { NavigationButton } from "../NavigationButton";
|
||||
import { ArrowUpRight } from "../../icons/ArrowUpRight";
|
||||
import { SignInButton } from "../SignInButton";
|
||||
import { UserDropdown } from "./UserDropdown";
|
||||
import { DevActionsDropdown } from "./DevActionsDropdown";
|
||||
import { NotificationWidget } from "../NotificationWidget";
|
||||
|
||||
const StyledNavigation = styled.div`
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
background-color: var(--slate-dark-1);
|
||||
z-index: 1000;
|
||||
padding: 12px 0;
|
||||
|
||||
.user-section {
|
||||
margin-left: auto;
|
||||
> button {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.navigation-section {
|
||||
margin-left: 50px;
|
||||
display: flex;
|
||||
|
||||
> div {
|
||||
> a {
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.nav-create-btn {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.arrow-up-right {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function DesktopNavigation(props) {
|
||||
return (
|
||||
<StyledNavigation>
|
||||
<div className="container">
|
||||
<Link to="/" className="logo-link">
|
||||
<Logotype />
|
||||
</Link>
|
||||
<div className="navigation-section">
|
||||
<NavigationButton route="/">Home</NavigationButton>
|
||||
<NavigationButton route="/edit">Create</NavigationButton>
|
||||
<NavigationButton href="https://thewiki.near.page/near.social_docs">
|
||||
Documentation
|
||||
<ArrowUpRight />
|
||||
</NavigationButton>
|
||||
</div>
|
||||
<div className="user-section">
|
||||
{!props.signedIn && (
|
||||
<SignInButton onSignIn={() => props.requestSignIn()} />
|
||||
)}
|
||||
{props.signedIn && (
|
||||
<>
|
||||
<DevActionsDropdown {...props} />
|
||||
<NotificationWidget
|
||||
notificationButtonSrc={props.widgets.notificationButton}
|
||||
/>
|
||||
<UserDropdown {...props} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</StyledNavigation>
|
||||
);
|
||||
}
|
||||
@ -1,133 +0,0 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Fork } from "../../icons/Fork";
|
||||
import { Code } from "../../icons/Code";
|
||||
import { useAccount } from "near-social-vm";
|
||||
|
||||
const StyledDropdown = styled.div`
|
||||
.dropdown-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--slate-dark-5);
|
||||
border-radius: 50px;
|
||||
outline: none;
|
||||
border: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
||||
&:after {
|
||||
display none;
|
||||
}
|
||||
|
||||
.menu {
|
||||
width: 18px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
|
||||
div {
|
||||
background-color: var(--slate-dark-11);;
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
border-radius: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
:hover {
|
||||
.menu {
|
||||
div {
|
||||
background-color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
background-color: var(--slate-dark-5);
|
||||
width: 100%;
|
||||
|
||||
li {
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
button,
|
||||
a {
|
||||
color: var(--slate-dark-11);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
|
||||
:hover,
|
||||
:focus {
|
||||
text-decoration: none;
|
||||
background-color: var(--slate-dark-1);
|
||||
color: white;
|
||||
|
||||
svg {
|
||||
path {
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
margin-right: 7px;
|
||||
path {
|
||||
stroke: var(--slate-dark-9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function DevActionsDropdown(props) {
|
||||
const account = useAccount();
|
||||
|
||||
if (props.widgetSrc?.edit || props.widgetSrc?.view) {
|
||||
return (
|
||||
<StyledDropdown className="dropdown">
|
||||
<button
|
||||
className="dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownMenu2222"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<div className="menu">
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
</button>
|
||||
<ul className="dropdown-menu" aria-labelledby="dropdownMenu2222">
|
||||
{props.widgetSrc?.edit && (
|
||||
<li>
|
||||
<Link to={`/edit/${props.widgetSrc?.edit}`}>
|
||||
<Fork />
|
||||
{props.widgetSrc.edit.startsWith(`${account.accountId}/widget/`)
|
||||
? "Edit widget"
|
||||
: "Fork widget"}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{props.widgetSrc?.view && (
|
||||
<li>
|
||||
<Link
|
||||
to={`/${props.widgets.viewSource}?src=${props.widgetSrc?.view}`}
|
||||
>
|
||||
<Code />
|
||||
View source
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</StyledDropdown>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -1,200 +0,0 @@
|
||||
import React, { useCallback } from "react";
|
||||
import { Widget, useNear, useAccount } from "near-social-vm";
|
||||
import styled from "styled-components";
|
||||
import { User } from "../../icons/User";
|
||||
import { LogOut } from "../../icons/LogOut";
|
||||
import { Withdraw } from "../../icons/Withdraw";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import PretendModal from "../PretendModal";
|
||||
import { Pretend } from "../../icons/Pretend";
|
||||
import { StopPretending } from "../../icons/StopPretending";
|
||||
|
||||
const StyledDropdown = styled.div`
|
||||
button,
|
||||
a {
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
.dropdown-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: left;
|
||||
background-color: var(--slate-dark-5);
|
||||
border-radius: 50px;
|
||||
outline: none;
|
||||
border: 0;
|
||||
|
||||
&:after {
|
||||
margin: 0 15px;
|
||||
border-top-color: var(--slate-dark-11);
|
||||
}
|
||||
|
||||
img {
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
|
||||
.profile-info {
|
||||
margin: 5px 10px;
|
||||
line-height: normal;
|
||||
max-width: 140px;
|
||||
|
||||
.profile-name,
|
||||
.profile-username {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
color: var(--slate-dark-12);
|
||||
}
|
||||
.profile-username {
|
||||
color: var(--slate-dark-11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
background-color: var(--slate-dark-5);
|
||||
width: 100%;
|
||||
|
||||
li {
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
button,
|
||||
a {
|
||||
color: var(--slate-dark-11);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
|
||||
:hover,
|
||||
:focus {
|
||||
text-decoration: none;
|
||||
background-color: var(--slate-dark-1);
|
||||
color: white;
|
||||
|
||||
svg {
|
||||
path {
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
margin-right: 7px;
|
||||
min-width: 24px;
|
||||
path {
|
||||
stroke: var(--slate-dark-9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function UserDropdown(props) {
|
||||
const near = useNear();
|
||||
const account = useAccount();
|
||||
|
||||
const withdrawStorage = useCallback(async () => {
|
||||
await near.contract.storage_withdraw({}, undefined, "1");
|
||||
}, [near]);
|
||||
|
||||
const [showPretendModal, setShowPretendModal] = React.useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledDropdown className="dropdown">
|
||||
<button
|
||||
className="dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownMenu2222"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<Widget
|
||||
src={props.widgets.profileImage}
|
||||
props={{
|
||||
accountId: account.accountId,
|
||||
className: "d-inline-block",
|
||||
style: { width: "40px", height: "40px" },
|
||||
}}
|
||||
/>
|
||||
<div className="profile-info">
|
||||
{props.widgets.profileName && (
|
||||
<div className="profile-name">
|
||||
<Widget src={props.widgets.profileName} />
|
||||
</div>
|
||||
)}
|
||||
<div className="profile-username">{account.accountId}</div>
|
||||
</div>
|
||||
</button>
|
||||
<ul
|
||||
className="dropdown-menu"
|
||||
aria-labelledby="dropdownMenu2222"
|
||||
style={{ minWidth: "fit-content" }}
|
||||
>
|
||||
<li>
|
||||
<NavLink
|
||||
className="dropdown-item"
|
||||
type="button"
|
||||
to={`/${props.widgets.profilePage}?accountId=${account.accountId}`}
|
||||
>
|
||||
<User />
|
||||
My Profile
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
className="dropdown-item"
|
||||
type="button"
|
||||
onClick={() => withdrawStorage()}
|
||||
>
|
||||
<Withdraw />
|
||||
Withdraw {props.availableStorage.div(1000).toFixed(2)}kb
|
||||
</button>
|
||||
</li>
|
||||
{account.pretendAccountId ? (
|
||||
<li>
|
||||
<button
|
||||
className="dropdown-item"
|
||||
type="button"
|
||||
disabled={!account.startPretending}
|
||||
onClick={() => account.startPretending(undefined)}
|
||||
>
|
||||
<StopPretending />
|
||||
Stop pretending
|
||||
</button>
|
||||
</li>
|
||||
) : (
|
||||
<li>
|
||||
<button
|
||||
className="dropdown-item"
|
||||
type="button"
|
||||
onClick={() => setShowPretendModal(true)}
|
||||
>
|
||||
<Pretend />
|
||||
Pretend to be another account
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
<li>
|
||||
<button
|
||||
className="dropdown-item"
|
||||
type="button"
|
||||
onClick={() => props.logOut()}
|
||||
>
|
||||
<LogOut />
|
||||
Sign Out
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</StyledDropdown>
|
||||
<PretendModal
|
||||
show={showPretendModal}
|
||||
onHide={() => setShowPretendModal(false)}
|
||||
widgets={props.widgets}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,256 +0,0 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Close } from "../../icons/Close";
|
||||
import { Home } from "../../icons/Home";
|
||||
import { Book } from "../../icons/Book";
|
||||
import { Code } from "../../icons/Code";
|
||||
import { LogOut } from "../../icons/LogOut";
|
||||
import { Fork } from "../../icons/Fork";
|
||||
import { UserCircle } from "../../icons/UserCircle";
|
||||
import { Widget } from "near-social-vm";
|
||||
import { NavigationButton } from "../NavigationButton";
|
||||
import { SignInButton } from "../SignInButton";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const StyledMenu = styled.div`
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
transition: 350ms;
|
||||
transform: translateX(-100%);
|
||||
|
||||
&.show {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.left-side {
|
||||
flex: 80;
|
||||
background-color: var(--slate-dark-1);
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 25px;
|
||||
overflow-x: auto;
|
||||
|
||||
.nav-sign-in-btn {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.profile-link {
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
|
||||
:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
color: var(--slate-dark-12);
|
||||
font-weight: var(--font-weight-bold);
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.profile-username {
|
||||
color: var(--slate-dark-11);
|
||||
}
|
||||
|
||||
.profile-name,
|
||||
.profile-username {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.top-links,
|
||||
.bottom-links {
|
||||
a,
|
||||
button {
|
||||
justify-content: flex-start;
|
||||
padding: 28px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--slate-dark-11);
|
||||
font-weight: var(--font-weight-bold);
|
||||
|
||||
svg {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
&.active,
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
svg {
|
||||
path {
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top-links {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.bottom-links {
|
||||
margin-top: auto;
|
||||
|
||||
a,
|
||||
button {
|
||||
padding: 14px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.log-out-button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--slate-dark-11);
|
||||
font-weight: var(--font-weight-bold);
|
||||
padding: 28px 0;
|
||||
|
||||
svg {
|
||||
path {
|
||||
stroke: #9ba1a6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
background: none;
|
||||
border: none;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
padding: 10px;
|
||||
|
||||
svg {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.right-side {
|
||||
flex: 20;
|
||||
opacity: 0.8;
|
||||
background-color: var(--slate-dark-1);
|
||||
}
|
||||
`;
|
||||
|
||||
export function Menu(props) {
|
||||
return (
|
||||
<StyledMenu className={props.showMenu ? "show" : ""}>
|
||||
<div className="left-side">
|
||||
{props.signedIn ? (
|
||||
<Link
|
||||
to={`/${props.widgets.profilePage}?accountId=${props.signedAccountId}`}
|
||||
className="profile-link"
|
||||
>
|
||||
<Widget
|
||||
src={props.widgets.profileImage}
|
||||
props={{
|
||||
accountId: props.signedAccountId,
|
||||
className: "d-inline-block",
|
||||
style: { width: "56px", height: "56px" },
|
||||
}}
|
||||
/>
|
||||
{props.widgets.profileName && (
|
||||
<div className="profile-name">
|
||||
<Widget src={props.widgets.profileName} />
|
||||
</div>
|
||||
)}
|
||||
<div className="profile-username">{props.signedAccountId}</div>
|
||||
</Link>
|
||||
) : (
|
||||
<SignInButton
|
||||
onSignIn={() => {
|
||||
props.onCloseMenu();
|
||||
props.requestSignIn();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<ul className="top-links">
|
||||
<li>
|
||||
<NavigationButton route="/">
|
||||
<Home />
|
||||
Home
|
||||
</NavigationButton>
|
||||
</li>
|
||||
<li>
|
||||
<NavigationButton
|
||||
disabled={!props.signedIn}
|
||||
route={`/${props.widgets.profilePage}?accountId=${props.signedAccountId}`}
|
||||
>
|
||||
<UserCircle />
|
||||
Profile
|
||||
</NavigationButton>
|
||||
</li>
|
||||
<li>
|
||||
<NavigationButton route="/edit">
|
||||
<Code />
|
||||
Create
|
||||
</NavigationButton>
|
||||
</li>
|
||||
<li>
|
||||
<NavigationButton href="https://thewiki.near.page/near.social_docs">
|
||||
<Book />
|
||||
Documentation
|
||||
</NavigationButton>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="bottom-links">
|
||||
{props.widgetSrc?.edit && (
|
||||
<li>
|
||||
<Link to={`/edit/${props.widgetSrc?.edit}`}>
|
||||
<Fork />
|
||||
{props.widgetSrc.edit.startsWith(
|
||||
`${props.signedAccountId}/widget/`
|
||||
)
|
||||
? "Edit widget"
|
||||
: "Fork widget"}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{props.widgetSrc?.view && (
|
||||
<li>
|
||||
<Link
|
||||
to={`/${props.widgets.viewSource}?src=${props.widgetSrc?.view}`}
|
||||
>
|
||||
<Code />
|
||||
View source
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{props.signedIn && (
|
||||
<li>
|
||||
<button onClick={() => props.logOut()} className="log-out-button">
|
||||
<LogOut />
|
||||
Sign Out
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
<button className="close-button" onClick={props.onCloseMenu}>
|
||||
<Close />
|
||||
</button>
|
||||
</div>
|
||||
<div className="right-side" onClick={props.onCloseMenu} />
|
||||
</StyledMenu>
|
||||
);
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
const StyledMobileMenuButton = styled.button`
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: white;
|
||||
font-weight: var(--font-weight-bold);
|
||||
padding: 0;
|
||||
|
||||
.menu {
|
||||
width: 18px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
margin-right: 10px;
|
||||
|
||||
div {
|
||||
background-color: white;
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
border-radius: 30px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function MobileMenuButton(props) {
|
||||
return (
|
||||
<StyledMobileMenuButton onClick={props.onClick}>
|
||||
<div className="menu">
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
{props.currentPage}
|
||||
</StyledMobileMenuButton>
|
||||
);
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Navigation } from "./Navigation";
|
||||
import { Menu } from "./Menu";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import useScrollBlock from ".././../../hooks/useScrollBlock";
|
||||
|
||||
export function MobileNavigation(props) {
|
||||
const [showMenu, setShowMenu] = useState(false);
|
||||
const [currentPage, setCurrentPage] = useState("");
|
||||
const location = useLocation();
|
||||
const [blockScroll, allowScroll] = useScrollBlock();
|
||||
|
||||
useEffect(() => {
|
||||
setShowMenu(false);
|
||||
getCurrentPage();
|
||||
allowScroll();
|
||||
}, [location.pathname]);
|
||||
|
||||
const getCurrentPage = () => {
|
||||
switch (location.pathname) {
|
||||
case "/":
|
||||
return setCurrentPage("Home");
|
||||
case `/${props.widgets.profilePage}`:
|
||||
return setCurrentPage("Profile");
|
||||
case "/edit":
|
||||
return setCurrentPage("Create");
|
||||
default:
|
||||
return setCurrentPage("");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navigation
|
||||
{...props}
|
||||
currentPage={currentPage}
|
||||
onClickShowMenu={() => {
|
||||
setShowMenu(true);
|
||||
blockScroll();
|
||||
}}
|
||||
/>
|
||||
<Menu
|
||||
{...props}
|
||||
showMenu={showMenu}
|
||||
onCloseMenu={() => {
|
||||
setShowMenu(false);
|
||||
allowScroll();
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Link } from "react-router-dom";
|
||||
import { MobileMenuButton } from "./MobileMenuButton";
|
||||
import { NearSocialLogo } from "../../icons/NearSocialLogo";
|
||||
import { NotificationWidget } from "../NotificationWidget";
|
||||
import { SignInButton } from "../SignInButton";
|
||||
|
||||
const StyledNavigation = styled.div`
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
background-color: var(--slate-dark-1);
|
||||
z-index: 1000;
|
||||
padding: 16px 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.logo-link {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.nav-notification-widget {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nav-sign-in-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
padding-right: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
export function Navigation(props) {
|
||||
return (
|
||||
<StyledNavigation>
|
||||
<MobileMenuButton
|
||||
onClick={props.onClickShowMenu}
|
||||
currentPage={props.currentPage}
|
||||
/>
|
||||
<Link to="/" className="logo-link">
|
||||
<NearSocialLogo />
|
||||
</Link>
|
||||
{props.signedIn ? (
|
||||
<NotificationWidget
|
||||
notificationButtonSrc={props.widgets.notificationButton}
|
||||
/>
|
||||
) : (
|
||||
<SignInButton onSignIn={() => props.requestSignIn()} />
|
||||
)}
|
||||
</StyledNavigation>
|
||||
);
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
const TestnetDomains = {
|
||||
"test.near.social": true,
|
||||
"127.0.0.1": true,
|
||||
};
|
||||
|
||||
export const NetworkId =
|
||||
window.location.hostname in TestnetDomains ? "testnet" : "mainnet";
|
||||
const TestnetWidgets = {
|
||||
image: "eugenethedream/widget/Image",
|
||||
default: "eugenethedream/widget/Welcome",
|
||||
viewSource: "eugenethedream/widget/WidgetSource",
|
||||
widgetMetadataEditor: "eugenethedream/widget/WidgetMetadataEditor",
|
||||
widgetMetadata: "eugenethedream/widget/WidgetMetadata",
|
||||
profileImage: "eugenethedream/widget/ProfileImage",
|
||||
profilePage: "eugenethedream/widget/Profile",
|
||||
profileName: "eugenethedream/widget/ProfileName",
|
||||
notificationButton: "eugenethedream/widget/NotificationButton",
|
||||
};
|
||||
|
||||
const MainnetWidgets = {
|
||||
image: "mob.near/widget/Image",
|
||||
default: "mob.near/widget/Homepage",
|
||||
viewSource: "mob.near/widget/WidgetSource",
|
||||
widgetMetadataEditor: "mob.near/widget/WidgetMetadataEditor",
|
||||
widgetMetadata: "mob.near/widget/WidgetMetadata",
|
||||
profileImage: "mob.near/widget/ProfileImage",
|
||||
notificationButton: "mob.near/widget/NotificationButton",
|
||||
profilePage: "mob.near/widget/ProfilePage",
|
||||
profileName: "patrick.near/widget/ProfileName",
|
||||
editorComponentSearch: "mob.near/widget/Editor.ComponentSearch",
|
||||
profileInlineBlock: "mob.near/widget/Profile.InlineBlock",
|
||||
};
|
||||
|
||||
export const Widgets =
|
||||
NetworkId === "testnet" ? TestnetWidgets : MainnetWidgets;
|
||||
@ -1,8 +0,0 @@
|
||||
import { useLocation } from "react-router-dom";
|
||||
import React from "react";
|
||||
|
||||
export function useQuery() {
|
||||
const { search } = useLocation();
|
||||
|
||||
return React.useMemo(() => new URLSearchParams(search), [search]);
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
import { useRef } from "react";
|
||||
|
||||
const safeDocument = typeof document !== "undefined" ? document : {};
|
||||
|
||||
/**
|
||||
* Usage:
|
||||
* const [blockScroll, allowScroll] = useScrollBlock();
|
||||
*/
|
||||
export default () => {
|
||||
const scrollBlocked = useRef();
|
||||
const html = safeDocument.documentElement;
|
||||
const { body } = safeDocument;
|
||||
|
||||
const blockScroll = () => {
|
||||
if (!body || !body.style || scrollBlocked.current) return;
|
||||
|
||||
const scrollBarWidth = window.innerWidth - html.clientWidth;
|
||||
const bodyPaddingRight =
|
||||
parseInt(
|
||||
window.getComputedStyle(body).getPropertyValue("padding-right")
|
||||
) || 0;
|
||||
|
||||
/**
|
||||
* 1. Fixes a bug in iOS and desktop Safari whereby setting
|
||||
* `overflow: hidden` on the html/body does not prevent scrolling.
|
||||
* 2. Fixes a bug in desktop Safari where `overflowY` does not prevent
|
||||
* scroll if an `overflow-x` style is also applied to the body.
|
||||
*/
|
||||
html.style.position = "relative"; /* [1] */
|
||||
html.style.overflow = "hidden"; /* [2] */
|
||||
body.style.position = "relative"; /* [1] */
|
||||
body.style.overflow = "hidden"; /* [2] */
|
||||
body.style.paddingRight = `${bodyPaddingRight + scrollBarWidth}px`;
|
||||
|
||||
scrollBlocked.current = true;
|
||||
};
|
||||
|
||||
const allowScroll = () => {
|
||||
if (!body || !body.style || !scrollBlocked.current) return;
|
||||
|
||||
html.style.position = "";
|
||||
html.style.overflow = "";
|
||||
body.style.position = "";
|
||||
body.style.overflow = "";
|
||||
body.style.paddingRight = "";
|
||||
|
||||
scrollBlocked.current = false;
|
||||
};
|
||||
|
||||
return [blockScroll, allowScroll];
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 9.0 KiB |
@ -1,4 +0,0 @@
|
||||
<svg width="331" height="203" viewBox="0 0 331 203" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M107.137 185L18 101.5L107.137 18" stroke="#3D7FFF" stroke-width="35" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M224.924 18L313 101.5L224.924 185" stroke="#3D7FFF" stroke-width="35" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 362 B |
@ -1,13 +0,0 @@
|
||||
:root {
|
||||
--slate-dark-1: #151718;
|
||||
--slate-dark-5: #2B2F31;
|
||||
--slate-dark-6: #313538;
|
||||
--slate-dark-8: #4C5155;
|
||||
--slate-dark-9: #697177;
|
||||
--slate-dark-11: #9BA1A6;
|
||||
--slate-dark-12: #ECEDEE;
|
||||
--blue-light-9: #0091FF;
|
||||
|
||||
--font-weight-medium: 500;
|
||||
--font-weight-bold: 600;
|
||||
}
|
||||
22
src/index.js
22
src/index.js
@ -1,8 +1,18 @@
|
||||
import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
import { useAccount, useAccountId } from "./lib/data/account";
|
||||
import { useInitNear, useNear } from "./lib/data/near";
|
||||
import { Widget } from "./lib/components/Widget";
|
||||
import { useCache } from "./lib/data/cache";
|
||||
import * as utils from "./lib/data/utils";
|
||||
import { CommitButton } from "./lib/components/Commit";
|
||||
|
||||
const container = document.getElementById("root");
|
||||
const root = createRoot(container);
|
||||
root.render(<App />);
|
||||
export {
|
||||
Widget,
|
||||
CommitButton,
|
||||
useInitNear,
|
||||
useNear,
|
||||
useCache,
|
||||
useAccount,
|
||||
useAccountId,
|
||||
utils,
|
||||
};
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"]
|
||||
}
|
||||
33
src/near-social-vm/.gitignore
vendored
33
src/near-social-vm/.gitignore
vendored
@ -1,33 +0,0 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
#IDE
|
||||
.idea
|
||||
|
||||
target
|
||||
neardev
|
||||
|
||||
# OS X
|
||||
.DS_Store
|
||||
@ -1,13 +0,0 @@
|
||||
const path = require("path");
|
||||
|
||||
const srcPath = path.resolve(__dirname, "../src");
|
||||
const distPath = path.resolve(__dirname, "../dist");
|
||||
const publicPath = path.resolve(__dirname, "../public");
|
||||
const nodeModulesPath = path.resolve(__dirname, "../node_modules");
|
||||
|
||||
module.exports = {
|
||||
srcPath,
|
||||
distPath,
|
||||
publicPath,
|
||||
nodeModulesPath,
|
||||
};
|
||||
@ -1,13 +0,0 @@
|
||||
const { merge } = require("webpack-merge");
|
||||
|
||||
const loadPresets = (env = { presets: [] }) => {
|
||||
const presets = env.presets || [];
|
||||
/** @type {string[]} */
|
||||
const mergedPresets = [].concat(...[presets]);
|
||||
const mergedConfigs = mergedPresets.map((presetName) =>
|
||||
require(`./webpack.${presetName}.js`)(env)
|
||||
);
|
||||
|
||||
return merge({}, ...mergedConfigs);
|
||||
};
|
||||
module.exports = loadPresets;
|
||||
@ -1,6 +0,0 @@
|
||||
const WebpackBundleAnalyzer =
|
||||
require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
|
||||
|
||||
module.exports = () => ({
|
||||
plugins: [new WebpackBundleAnalyzer()],
|
||||
});
|
||||
@ -1,48 +0,0 @@
|
||||
const path = require("path");
|
||||
const { HotModuleReplacementPlugin } = require("webpack");
|
||||
|
||||
module.exports = () => ({
|
||||
devtool: false,
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(scss|css)$/,
|
||||
use: [
|
||||
{
|
||||
// inject CSS to page
|
||||
loader: "style-loader",
|
||||
},
|
||||
{
|
||||
// translates CSS into CommonJS modules
|
||||
loader: "css-loader",
|
||||
},
|
||||
{
|
||||
// Run postcss actions
|
||||
loader: "postcss-loader",
|
||||
options: {
|
||||
// `postcssOptions` is needed for postcss 8.x;
|
||||
// if you use postcss 7.x skip the key
|
||||
postcssOptions: {
|
||||
// postcss plugins, can be exported to postcss.config.js
|
||||
plugins: function () {
|
||||
return [require("autoprefixer")];
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// compiles Sass to CSS
|
||||
loader: "sass-loader",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
devServer: {
|
||||
open: true,
|
||||
static: path.resolve(__dirname, "../dist"),
|
||||
port: 3000,
|
||||
compress: true,
|
||||
},
|
||||
plugins: [new HotModuleReplacementPlugin()],
|
||||
});
|
||||
@ -1,75 +0,0 @@
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
|
||||
const path = require("path");
|
||||
|
||||
module.exports = () => {
|
||||
return {
|
||||
// output: {
|
||||
// path: path.resolve(__dirname, "../dist"),
|
||||
// publicPath: "./",
|
||||
// // filename: "[name].[contenthash].bundle.js",
|
||||
// filename: "index.js",
|
||||
// },
|
||||
devtool: false,
|
||||
module: {
|
||||
rules: [
|
||||
// {
|
||||
// test: /\.(css)$/,
|
||||
// use: [MiniCssExtractPlugin.loader, "css-loader"],
|
||||
// // options: {
|
||||
// // sourceMap: false,
|
||||
// // },
|
||||
// },
|
||||
{
|
||||
test: /\.(scss|css)$/,
|
||||
use: [
|
||||
{
|
||||
// inject CSS to page
|
||||
loader: "style-loader",
|
||||
},
|
||||
{
|
||||
// translates CSS into CommonJS modules
|
||||
loader: "css-loader",
|
||||
},
|
||||
{
|
||||
// Run postcss actions
|
||||
loader: "postcss-loader",
|
||||
options: {
|
||||
// `postcssOptions` is needed for postcss 8.x;
|
||||
// if you use postcss 7.x skip the key
|
||||
postcssOptions: {
|
||||
// postcss plugins, can be exported to postcss.config.js
|
||||
plugins: function () {
|
||||
return [require("autoprefixer")];
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// compiles Sass to CSS
|
||||
loader: "sass-loader",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "styles/[name].[contenthash].css",
|
||||
chunkFilename: "[id].css",
|
||||
}),
|
||||
],
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [new CssMinimizerPlugin(), "..."],
|
||||
// runtimeChunk: {
|
||||
// name: "runtime",
|
||||
// },
|
||||
},
|
||||
performance: {
|
||||
hints: false,
|
||||
maxEntrypointSize: 512000,
|
||||
maxAssetSize: 512000,
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -1,103 +0,0 @@
|
||||
{
|
||||
"name": "near-social-vm",
|
||||
"version": "0.1.0",
|
||||
"description": "Near Social VM",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "6.0.0",
|
||||
"@near-wallet-selector/core": "^7.4.0",
|
||||
"@near-wallet-selector/here-wallet": "^7.4.0",
|
||||
"@near-wallet-selector/meteor-wallet": "^7.4.0",
|
||||
"@near-wallet-selector/my-near-wallet": "^7.4.0",
|
||||
"@near-wallet-selector/near-wallet": "^7.4.0",
|
||||
"@near-wallet-selector/neth": "^7.4.0",
|
||||
"@near-wallet-selector/sender": "^7.4.0",
|
||||
"acorn": "^8.8.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"big.js": "^6.1.1",
|
||||
"bn.js": "^5.1.1",
|
||||
"bootstrap": "^5.2.1",
|
||||
"bootstrap-icons": "^1.9.0",
|
||||
"collections": "^5.1.12",
|
||||
"deep-equal": "^2.2.0",
|
||||
"elliptic": "^6.5.4",
|
||||
"idb": "^7.1.1",
|
||||
"local-storage": "^2.0.0",
|
||||
"mdast-util-find-and-replace": "^2.0.0",
|
||||
"near-api-js": "^0.45.1",
|
||||
"prettier": "^2.7.1",
|
||||
"react-bootstrap": "^2.5.0",
|
||||
"react-bootstrap-typeahead": "^6.0.0",
|
||||
"react-error-boundary": "^3.1.4",
|
||||
"react-files": "^3.0.0-alpha.3",
|
||||
"react-infinite-scroller": "^1.2.6",
|
||||
"react-markdown": "^7.1.0",
|
||||
"react-singleton-hook": "^3.1.1",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-uuid": "^1.0.2",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"styled-components": "^5.3.6",
|
||||
"tweetnacl": "^1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"buffer": "^6.0.3",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"copy-webpack-plugin": "^9.0.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^6.2.0",
|
||||
"css-minimizer-webpack-plugin": "^3.0.2",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"https-browserify": "^1.0.0",
|
||||
"mini-css-extract-plugin": "^2.2.2",
|
||||
"node-sass": "^7.0.3",
|
||||
"os-browserify": "^0.3.0",
|
||||
"postcss-loader": "^7.0.1",
|
||||
"process": "^0.11.10",
|
||||
"sass-loader": "^13.1.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"stream-http": "^3.2.0",
|
||||
"style-loader": "^3.2.1",
|
||||
"url": "^0.11.0",
|
||||
"webpack": "^5.52.0",
|
||||
"webpack-bundle-analyzer": "^4.4.2",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-dev-server": "^4.1.0",
|
||||
"webpack-manifest-plugin": "^5.0.0",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"webpack-node-externals": "^3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"webpack": "webpack",
|
||||
"prod": "npm run webpack -- --env mode=production",
|
||||
"build": "npm run prod"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
import React from "react";
|
||||
import { useAccount, useAccountId } from "./lib/data/account";
|
||||
import { useInitNear, useNear } from "./lib/data/near";
|
||||
import { Widget } from "./lib/components/Widget";
|
||||
import { useCache } from "./lib/data/cache";
|
||||
import * as utils from "./lib/data/utils";
|
||||
import { CommitButton } from "./lib/components/Commit";
|
||||
|
||||
export {
|
||||
Widget,
|
||||
CommitButton,
|
||||
useInitNear,
|
||||
useNear,
|
||||
useCache,
|
||||
useAccount,
|
||||
useAccountId,
|
||||
utils,
|
||||
};
|
||||
@ -1,83 +0,0 @@
|
||||
const webpack = require("webpack");
|
||||
const paths = require("./config/paths");
|
||||
const path = require("path");
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
const { merge } = require("webpack-merge");
|
||||
const loadPreset = require("./config/presets/loadPreset");
|
||||
const loadConfig = (mode) => require(`./config/webpack.${mode}.js`)(mode);
|
||||
const nodeExternals = require("webpack-node-externals");
|
||||
|
||||
module.exports = function (env) {
|
||||
const { mode = "production" } = env || {};
|
||||
return merge(
|
||||
{
|
||||
mode,
|
||||
entry: `${paths.srcPath}/index.js`,
|
||||
output: {
|
||||
path: paths.distPath,
|
||||
filename: "index.js",
|
||||
libraryTarget: "umd",
|
||||
},
|
||||
externals: [
|
||||
nodeExternals(),
|
||||
{
|
||||
react: {
|
||||
commonjs: "react",
|
||||
commonjs2: "react",
|
||||
amd: "react",
|
||||
root: "React",
|
||||
},
|
||||
"react-dom": {
|
||||
commonjs: "react-dom",
|
||||
commonjs2: "react-dom",
|
||||
amd: "react-dom",
|
||||
root: "ReactDOM",
|
||||
},
|
||||
},
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: ["babel-loader"],
|
||||
exclude: path.resolve(__dirname, "node_modules"),
|
||||
},
|
||||
// Images: Copy image files to build folder
|
||||
{ test: /\.(?:ico|gif|png|jpg|jpeg)$/i, type: "asset/resource" },
|
||||
|
||||
// Fonts and SVGs: Inline files
|
||||
{ test: /\.(woff(2)?|eot|ttf|otf|svg|)$/, type: "asset/inline" },
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
modules: [paths.srcPath, "node_modules"],
|
||||
extensions: [".js", ".jsx", ".json"],
|
||||
fallback: {
|
||||
crypto: require.resolve("crypto-browserify"),
|
||||
stream: require.resolve("stream-browserify"),
|
||||
},
|
||||
},
|
||||
target: "node",
|
||||
plugins: [
|
||||
// new webpack.EnvironmentPlugin({
|
||||
// // Configure environment variables here.
|
||||
// ENVIRONMENT: "browser",
|
||||
// }),
|
||||
new CleanWebpackPlugin(),
|
||||
new webpack.ProgressPlugin(),
|
||||
new webpack.ProvidePlugin({
|
||||
process: "process/browser",
|
||||
Buffer: [require.resolve("buffer/"), "Buffer"],
|
||||
}),
|
||||
],
|
||||
},
|
||||
loadConfig(mode),
|
||||
loadPreset(env)
|
||||
);
|
||||
};
|
||||
@ -1,693 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import ls from "local-storage";
|
||||
import prettier from "prettier";
|
||||
import parserBabel from "prettier/parser-babel";
|
||||
import { useHistory, useParams } from "react-router-dom";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import {
|
||||
Widget,
|
||||
useCache,
|
||||
useNear,
|
||||
CommitButton,
|
||||
useAccountId,
|
||||
} from "near-social-vm";
|
||||
import { Nav, OverlayTrigger, Tooltip } from "react-bootstrap";
|
||||
import RenameModal from "../components/Editor/RenameModal";
|
||||
import OpenModal from "../components/Editor/OpenModal";
|
||||
|
||||
const StorageDomain = {
|
||||
page: "editor",
|
||||
};
|
||||
|
||||
const StorageType = {
|
||||
Code: "code",
|
||||
Files: "files",
|
||||
};
|
||||
|
||||
const Filetype = {
|
||||
Widget: "widget",
|
||||
Module: "module",
|
||||
};
|
||||
|
||||
const LsKey = "social.near:v01:";
|
||||
const EditorLayoutKey = LsKey + "editorLayout:";
|
||||
const WidgetPropsKey = LsKey + "widgetProps:";
|
||||
|
||||
const DefaultEditorCode = "return <div>Hello World</div>;";
|
||||
|
||||
const Tab = {
|
||||
Editor: "Editor",
|
||||
Props: "Props",
|
||||
Metadata: "Metadata",
|
||||
Widget: "Widget",
|
||||
};
|
||||
|
||||
const Layout = {
|
||||
Tabs: "Tabs",
|
||||
Split: "Split",
|
||||
};
|
||||
|
||||
export default function EditorPage(props) {
|
||||
const { widgetSrc } = useParams();
|
||||
const history = useHistory();
|
||||
const setWidgetSrc = props.setWidgetSrc;
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [code, setCode] = useState(undefined);
|
||||
const [path, setPath] = useState(undefined);
|
||||
const [files, setFiles] = useState(undefined);
|
||||
const [lastPath, setLastPath] = useState(undefined);
|
||||
const [showRenameModal, setShowRenameModal] = useState(false);
|
||||
const [showOpenModal, setShowOpenModal] = useState(false);
|
||||
|
||||
const [renderCode, setRenderCode] = useState(code);
|
||||
const [widgetProps, setWidgetProps] = useState(
|
||||
ls.get(WidgetPropsKey) || "{}"
|
||||
);
|
||||
const [parsedWidgetProps, setParsedWidgetProps] = useState({});
|
||||
const [propsError, setPropsError] = useState(null);
|
||||
const [metadata, setMetadata] = useState(undefined);
|
||||
const near = useNear();
|
||||
const cache = useCache();
|
||||
const accountId = useAccountId();
|
||||
|
||||
const [tab, setTab] = useState(Tab.Editor);
|
||||
const [layout, setLayoutState] = useState(
|
||||
ls.get(EditorLayoutKey) || Layout.Tabs
|
||||
);
|
||||
|
||||
const setLayout = useCallback(
|
||||
(layout) => {
|
||||
ls.set(EditorLayoutKey, layout);
|
||||
setLayoutState(layout);
|
||||
},
|
||||
[setLayoutState]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setWidgetSrc({
|
||||
edit: null,
|
||||
view: widgetSrc,
|
||||
});
|
||||
}, [widgetSrc, setWidgetSrc]);
|
||||
|
||||
const updateCode = useCallback(
|
||||
(path, code) => {
|
||||
cache.localStorageSet(
|
||||
StorageDomain,
|
||||
{
|
||||
path,
|
||||
type: StorageType.Code,
|
||||
},
|
||||
{
|
||||
code,
|
||||
time: Date.now(),
|
||||
}
|
||||
);
|
||||
setCode(code);
|
||||
},
|
||||
[cache, setCode]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
ls.set(WidgetPropsKey, widgetProps);
|
||||
try {
|
||||
const parsedWidgetProps = JSON.parse(widgetProps);
|
||||
setParsedWidgetProps(parsedWidgetProps);
|
||||
setPropsError(null);
|
||||
} catch (e) {
|
||||
setParsedWidgetProps({});
|
||||
setPropsError(e.message);
|
||||
}
|
||||
}, [widgetProps]);
|
||||
|
||||
const removeFromFiles = useCallback(
|
||||
(path) => {
|
||||
path = JSON.stringify(path);
|
||||
setFiles((files) =>
|
||||
files.filter((file) => JSON.stringify(file) !== path)
|
||||
);
|
||||
setLastPath(path);
|
||||
},
|
||||
[setFiles, setLastPath]
|
||||
);
|
||||
|
||||
const addToFiles = useCallback(
|
||||
(path) => {
|
||||
const jpath = JSON.stringify(path);
|
||||
setFiles((files) => {
|
||||
const newFiles = [...files];
|
||||
if (!files.find((file) => JSON.stringify(file) === jpath)) {
|
||||
newFiles.push(path);
|
||||
}
|
||||
return newFiles;
|
||||
});
|
||||
setLastPath(path);
|
||||
},
|
||||
[setFiles, setLastPath]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (files && lastPath) {
|
||||
cache.localStorageSet(
|
||||
StorageDomain,
|
||||
{
|
||||
type: StorageType.Files,
|
||||
},
|
||||
{ files, lastPath }
|
||||
);
|
||||
}
|
||||
}, [files, lastPath, cache]);
|
||||
|
||||
const openFile = useCallback(
|
||||
(path, code) => {
|
||||
setPath(path);
|
||||
addToFiles(path);
|
||||
setMetadata(undefined);
|
||||
setRenderCode(null);
|
||||
if (code !== undefined) {
|
||||
updateCode(path, code);
|
||||
} else {
|
||||
setLoading(true);
|
||||
cache
|
||||
.asyncLocalStorageGet(StorageDomain, {
|
||||
path,
|
||||
type: StorageType.Code,
|
||||
})
|
||||
.then(({ code }) => {
|
||||
updateCode(path, code);
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
},
|
||||
[updateCode, addToFiles]
|
||||
);
|
||||
|
||||
const toPath = useCallback((type, nameOrPath) => {
|
||||
const name =
|
||||
nameOrPath.indexOf("/") >= 0
|
||||
? nameOrPath.split("/").slice(2).join("/")
|
||||
: nameOrPath;
|
||||
return { type, name };
|
||||
}, []);
|
||||
|
||||
const loadFile = useCallback(
|
||||
(nameOrPath) => {
|
||||
if (!near) {
|
||||
return;
|
||||
}
|
||||
const widgetSrc =
|
||||
nameOrPath.indexOf("/") >= 0
|
||||
? nameOrPath
|
||||
: `${accountId}/widget/${nameOrPath}`;
|
||||
const c = () => {
|
||||
const code = cache.socialGet(
|
||||
near,
|
||||
widgetSrc,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
c
|
||||
);
|
||||
if (code) {
|
||||
const name = widgetSrc.split("/").slice(2).join("/");
|
||||
openFile(toPath(Filetype.Widget, widgetSrc), code);
|
||||
}
|
||||
};
|
||||
|
||||
c();
|
||||
},
|
||||
[accountId, openFile, toPath, near, cache]
|
||||
);
|
||||
|
||||
const generateNewName = useCallback(
|
||||
(type) => {
|
||||
for (let i = 0; ; i++) {
|
||||
const name = `Draft-${i}`;
|
||||
const path = toPath(type, name);
|
||||
path.unnamed = true;
|
||||
const jPath = JSON.stringify(path);
|
||||
if (!files?.find((file) => JSON.stringify(file) === jPath)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
},
|
||||
[toPath, files]
|
||||
);
|
||||
|
||||
const createFile = useCallback(
|
||||
(type) => {
|
||||
const path = generateNewName(type);
|
||||
openFile(path, DefaultEditorCode);
|
||||
},
|
||||
[generateNewName, openFile]
|
||||
);
|
||||
|
||||
const renameFile = useCallback(
|
||||
(newName, code) => {
|
||||
const newPath = toPath(path.type, newName);
|
||||
const jNewPath = JSON.stringify(newPath);
|
||||
const jPath = JSON.stringify(path);
|
||||
setFiles((files) => {
|
||||
const newFiles = files.filter(
|
||||
(file) => JSON.stringify(file) !== jNewPath
|
||||
);
|
||||
const i = newFiles.findIndex((file) => JSON.stringify(file) === jPath);
|
||||
if (i >= 0) {
|
||||
newFiles[i] = newPath;
|
||||
}
|
||||
return newFiles;
|
||||
});
|
||||
setLastPath(newPath);
|
||||
setPath(newPath);
|
||||
updateCode(newPath, code);
|
||||
},
|
||||
[path, toPath, updateCode]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
cache
|
||||
.asyncLocalStorageGet(StorageDomain, { type: StorageType.Files })
|
||||
.then((value) => {
|
||||
const { files, lastPath } = value || {};
|
||||
setFiles(files || []);
|
||||
setLastPath(lastPath);
|
||||
});
|
||||
}, [cache]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!near || !files) {
|
||||
return;
|
||||
}
|
||||
if (widgetSrc) {
|
||||
if (widgetSrc === "new") {
|
||||
createFile(Filetype.Widget);
|
||||
} else {
|
||||
loadFile(widgetSrc);
|
||||
}
|
||||
analytics("edit", {
|
||||
props: {
|
||||
widget: widgetSrc,
|
||||
},
|
||||
});
|
||||
history.replace(`/edit/`);
|
||||
} else if (path === undefined) {
|
||||
if (files.length === 0) {
|
||||
createFile(Filetype.Widget);
|
||||
} else {
|
||||
openFile(lastPath, undefined);
|
||||
}
|
||||
}
|
||||
}, [near, createFile, lastPath, files, path, widgetSrc, openFile, loadFile]);
|
||||
|
||||
const reformat = useCallback(
|
||||
(path, code) => {
|
||||
try {
|
||||
const formattedCode = prettier.format(code, {
|
||||
parser: "babel",
|
||||
plugins: [parserBabel],
|
||||
});
|
||||
updateCode(path, formattedCode);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
},
|
||||
[updateCode]
|
||||
);
|
||||
|
||||
const reformatProps = useCallback(
|
||||
(props) => {
|
||||
try {
|
||||
const formattedProps = JSON.stringify(JSON.parse(props), null, 2);
|
||||
setWidgetProps(formattedProps);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
},
|
||||
[setWidgetProps]
|
||||
);
|
||||
|
||||
const layoutClass = layout === Layout.Split ? "col-lg-6" : "";
|
||||
|
||||
const onLayoutChange = useCallback(
|
||||
(e) => {
|
||||
const layout = e.target.value;
|
||||
if (layout === Layout.Split && tab === Tab.Widget) {
|
||||
setTab(Tab.Editor);
|
||||
}
|
||||
setLayout(layout);
|
||||
},
|
||||
[setLayout, tab, setTab]
|
||||
);
|
||||
|
||||
const widgetName = path?.name;
|
||||
|
||||
const commitButton = (
|
||||
<CommitButton
|
||||
className="btn btn-primary"
|
||||
disabled={!widgetName}
|
||||
near={near}
|
||||
data={{
|
||||
widget: {
|
||||
[widgetName]: {
|
||||
"": code,
|
||||
metadata,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
Save Widget
|
||||
</CommitButton>
|
||||
);
|
||||
|
||||
const widgetPath = `${accountId}/${path?.type}/${path?.name}`;
|
||||
const jpath = JSON.stringify(path);
|
||||
|
||||
return (
|
||||
<div className="container-fluid mt-1">
|
||||
<RenameModal
|
||||
key={`rename-modal-${jpath}`}
|
||||
show={showRenameModal}
|
||||
name={path?.name}
|
||||
onRename={(newName) => renameFile(newName, code)}
|
||||
onHide={() => setShowRenameModal(false)}
|
||||
/>
|
||||
<OpenModal
|
||||
show={showOpenModal}
|
||||
onOpen={(newName) => loadFile(newName)}
|
||||
onNew={(newName) =>
|
||||
newName
|
||||
? openFile(toPath(Filetype.Widget, newName), DefaultEditorCode)
|
||||
: createFile(Filetype.Widget)
|
||||
}
|
||||
onHide={() => setShowOpenModal(false)}
|
||||
/>
|
||||
<div className="mb-3">
|
||||
<Nav
|
||||
variant="pills mb-1"
|
||||
activeKey={jpath}
|
||||
onSelect={(key) => openFile(JSON.parse(key))}
|
||||
>
|
||||
{files?.map((p, idx) => {
|
||||
const jp = JSON.stringify(p);
|
||||
return (
|
||||
<Nav.Item key={jp}>
|
||||
<Nav.Link className="text-decoration-none" eventKey={jp}>
|
||||
{p.name}
|
||||
<button
|
||||
className={`btn btn-sm border-0 py-0 px-1 ms-1 rounded-circle ${
|
||||
jp === jpath
|
||||
? "btn-outline-light"
|
||||
: "btn-outline-secondary"
|
||||
}`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
removeFromFiles(p);
|
||||
if (jp === jpath) {
|
||||
if (files.length > 1) {
|
||||
openFile(files[idx - 1] || files[idx + 1]);
|
||||
} else {
|
||||
createFile(Filetype.Widget);
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<i className="bi bi-x"></i>
|
||||
</button>
|
||||
</Nav.Link>
|
||||
</Nav.Item>
|
||||
);
|
||||
})}
|
||||
<Nav.Item>
|
||||
<Nav.Link
|
||||
className="text-decoration-none"
|
||||
onClick={() => setShowOpenModal(true)}
|
||||
>
|
||||
<i className="bi bi-file-earmark-plus"></i> Add
|
||||
</Nav.Link>
|
||||
</Nav.Item>
|
||||
</Nav>
|
||||
{props.widgets.editorComponentSearch && (
|
||||
<div>
|
||||
<Widget
|
||||
src={props.widgets.editorComponentSearch}
|
||||
props={useMemo(
|
||||
() => ({
|
||||
extraButtons: ({ widgetName, widgetPath, onHide }) => (
|
||||
<OverlayTrigger
|
||||
placement="auto"
|
||||
overlay={
|
||||
<Tooltip>
|
||||
Open "{widgetName}" component in the editor
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
loadFile(widgetPath);
|
||||
onHide && onHide();
|
||||
}}
|
||||
>
|
||||
Open
|
||||
</button>
|
||||
</OverlayTrigger>
|
||||
),
|
||||
}),
|
||||
[loadFile]
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="d-flex align-content-start">
|
||||
<div className="me-2">
|
||||
<div
|
||||
className="btn-group-vertical"
|
||||
role="group"
|
||||
aria-label="Layout selection"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
className="btn-check"
|
||||
name="layout-radio"
|
||||
id="layout-tabs"
|
||||
autoComplete="off"
|
||||
checked={layout === Layout.Tabs}
|
||||
onChange={onLayoutChange}
|
||||
value={Layout.Tabs}
|
||||
title={"Set layout to Tabs mode"}
|
||||
/>
|
||||
<label className="btn btn-outline-secondary" htmlFor="layout-tabs">
|
||||
<i className="bi bi-square" />
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
className="btn-check"
|
||||
name="layout-radio"
|
||||
id="layout-split"
|
||||
autoComplete="off"
|
||||
checked={layout === Layout.Split}
|
||||
value={Layout.Split}
|
||||
title={"Set layout to Split mode"}
|
||||
onChange={onLayoutChange}
|
||||
/>
|
||||
<label className="btn btn-outline-secondary" htmlFor="layout-split">
|
||||
<i className="bi bi-layout-split" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-grow-1">
|
||||
<div className="row">
|
||||
<div className={layoutClass}>
|
||||
<ul className={`nav nav-tabs mb-2`}>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-link ${tab === Tab.Editor ? "active" : ""}`}
|
||||
aria-current="page"
|
||||
onClick={() => setTab(Tab.Editor)}
|
||||
>
|
||||
Editor
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-link ${tab === Tab.Props ? "active" : ""}`}
|
||||
aria-current="page"
|
||||
onClick={() => setTab(Tab.Props)}
|
||||
>
|
||||
Props
|
||||
</button>
|
||||
</li>
|
||||
{props.widgets.widgetMetadataEditor && (
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-link ${
|
||||
tab === Tab.Metadata ? "active" : ""
|
||||
}`}
|
||||
aria-current="page"
|
||||
onClick={() => setTab(Tab.Metadata)}
|
||||
>
|
||||
Metadata
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
{layout === Layout.Tabs && (
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-link ${
|
||||
tab === Tab.Widget ? "active" : ""
|
||||
}`}
|
||||
aria-current="page"
|
||||
onClick={() => {
|
||||
setRenderCode(code);
|
||||
setTab(Tab.Widget);
|
||||
}}
|
||||
>
|
||||
Widget Preview
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
|
||||
<div className={`${tab === Tab.Editor ? "" : "visually-hidden"}`}>
|
||||
<div className="form-control mb-3" style={{ height: "70vh" }}>
|
||||
<Editor
|
||||
value={code}
|
||||
path={widgetPath}
|
||||
defaultLanguage="javascript"
|
||||
onChange={(code) => updateCode(path, code)}
|
||||
wrapperProps={{
|
||||
onBlur: () => reformat(path, code),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3 d-flex gap-2 flex-wrap">
|
||||
<button
|
||||
className="btn btn-success"
|
||||
onClick={() => {
|
||||
setRenderCode(code);
|
||||
if (layout === Layout.Tabs) {
|
||||
setTab(Tab.Widget);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Render preview
|
||||
</button>
|
||||
{!path?.unnamed && commitButton}
|
||||
<button
|
||||
className={`btn ${
|
||||
path?.unnamed ? "btn-primary" : "btn-secondary"
|
||||
}`}
|
||||
onClick={() => {
|
||||
setShowRenameModal(true);
|
||||
}}
|
||||
>
|
||||
Rename {path?.type}
|
||||
</button>
|
||||
{path && accountId && (
|
||||
<a
|
||||
className="btn btn-outline-primary"
|
||||
href={`#/${widgetPath}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Open Component in a new tab
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${tab === Tab.Props ? "" : "visually-hidden"}`}>
|
||||
<div className="form-control" style={{ height: "70vh" }}>
|
||||
<Editor
|
||||
value={widgetProps}
|
||||
defaultLanguage="json"
|
||||
onChange={(props) => setWidgetProps(props)}
|
||||
wrapperProps={{
|
||||
onBlur: () => reformatProps(widgetProps),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className=" mb-3">^^ Props for debugging (in JSON)</div>
|
||||
{propsError && (
|
||||
<pre className="alert alert-danger">{propsError}</pre>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={`${
|
||||
tab === Tab.Metadata && props.widgets.widgetMetadataEditor
|
||||
? ""
|
||||
: "visually-hidden"
|
||||
}`}
|
||||
>
|
||||
<div className="mb-3">
|
||||
<Widget
|
||||
src={props.widgets.widgetMetadataEditor}
|
||||
key={`metadata-editor-${jpath}`}
|
||||
props={useMemo(
|
||||
() => ({
|
||||
widgetPath,
|
||||
onChange: setMetadata,
|
||||
}),
|
||||
[widgetPath]
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">{commitButton}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`${
|
||||
tab === Tab.Widget ||
|
||||
(layout === Layout.Split && tab !== Tab.Metadata)
|
||||
? layoutClass
|
||||
: "visually-hidden"
|
||||
}`}
|
||||
>
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="d-inline-block position-relative overflow-hidden">
|
||||
{renderCode ? (
|
||||
<Widget
|
||||
key={`preview-${jpath}`}
|
||||
code={renderCode}
|
||||
props={parsedWidgetProps}
|
||||
/>
|
||||
) : (
|
||||
'Click "Render preview" button to render the widget'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`${
|
||||
tab === Tab.Metadata ? layoutClass : "visually-hidden"
|
||||
}`}
|
||||
>
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="d-inline-block position-relative overflow-hidden">
|
||||
<Widget
|
||||
key={`metadata-${jpath}`}
|
||||
src={props.widgets.widgetMetadata}
|
||||
props={useMemo(
|
||||
() => ({ metadata, accountId, widgetName }),
|
||||
[metadata, accountId, widgetName]
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Widget } from "near-social-vm";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useQuery } from "../hooks/useQuery";
|
||||
|
||||
export default function EmbedPage(props) {
|
||||
const { widgetSrc } = useParams();
|
||||
const query = useQuery();
|
||||
const [widgetProps, setWidgetProps] = useState({});
|
||||
|
||||
const src = widgetSrc || props.widgets.default;
|
||||
|
||||
useEffect(() => {
|
||||
setWidgetProps(
|
||||
[...query.entries()].reduce((props, [key, value]) => {
|
||||
props[key] = value;
|
||||
return props;
|
||||
}, {})
|
||||
);
|
||||
}, [query]);
|
||||
|
||||
useEffect(() => {
|
||||
analytics("embed", {
|
||||
props: {
|
||||
widget: src,
|
||||
},
|
||||
});
|
||||
}, [src]);
|
||||
|
||||
return (
|
||||
<div className="d-inline-block position-relative overflow-hidden">
|
||||
<Widget key={src} src={src} props={widgetProps} />{" "}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Widget } from "near-social-vm";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useQuery } from "../hooks/useQuery";
|
||||
|
||||
export default function ViewPage(props) {
|
||||
const { widgetSrc } = useParams();
|
||||
const query = useQuery();
|
||||
const [widgetProps, setWidgetProps] = useState({});
|
||||
|
||||
const src = widgetSrc || props.widgets.default;
|
||||
const setWidgetSrc = props.setWidgetSrc;
|
||||
const viewSourceWidget = props.widgets.viewSource;
|
||||
|
||||
useEffect(() => {
|
||||
setWidgetProps(Object.fromEntries([...query.entries()]));
|
||||
}, [query]);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setWidgetSrc(
|
||||
src === viewSourceWidget && query.get("src")
|
||||
? {
|
||||
edit: query.get("src"),
|
||||
view: null,
|
||||
}
|
||||
: {
|
||||
edit: src,
|
||||
view: src,
|
||||
}
|
||||
);
|
||||
analytics("view", {
|
||||
props: {
|
||||
widget: src,
|
||||
},
|
||||
});
|
||||
}, 1);
|
||||
}, [src, query, setWidgetSrc, viewSourceWidget]);
|
||||
|
||||
return (
|
||||
<div className="container-xl">
|
||||
<div className="row">
|
||||
<div
|
||||
className="d-inline-block position-relative overflow-hidden"
|
||||
style={{
|
||||
"--body-top-padding": "24px",
|
||||
paddingTop: "var(--body-top-padding)",
|
||||
}}
|
||||
>
|
||||
<Widget key={src} src={src} props={widgetProps} />{" "}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,14 +1,11 @@
|
||||
const webpack = require("webpack");
|
||||
const paths = require("./config/paths");
|
||||
const path = require("path");
|
||||
const ManifestPlugin = require("webpack-manifest-plugin");
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
const HTMLWebpackPlugin = require("html-webpack-plugin");
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const { merge } = require("webpack-merge");
|
||||
const loadPreset = require("./config/presets/loadPreset");
|
||||
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
|
||||
const loadConfig = (mode) => require(`./config/webpack.${mode}.js`)(mode);
|
||||
const nodeExternals = require("webpack-node-externals");
|
||||
|
||||
module.exports = function (env) {
|
||||
const { mode = "production" } = env || {};
|
||||
@ -18,9 +15,26 @@ module.exports = function (env) {
|
||||
entry: `${paths.srcPath}/index.js`,
|
||||
output: {
|
||||
path: paths.distPath,
|
||||
filename: "[name].bundle.js",
|
||||
publicPath: "/",
|
||||
filename: "index.js",
|
||||
libraryTarget: "umd",
|
||||
},
|
||||
externals: [
|
||||
nodeExternals(),
|
||||
{
|
||||
react: {
|
||||
commonjs: "react",
|
||||
commonjs2: "react",
|
||||
amd: "react",
|
||||
root: "React",
|
||||
},
|
||||
"react-dom": {
|
||||
commonjs: "react-dom",
|
||||
commonjs2: "react-dom",
|
||||
amd: "react-dom",
|
||||
root: "ReactDOM",
|
||||
},
|
||||
},
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
@ -45,56 +59,22 @@ module.exports = function (env) {
|
||||
modules: [paths.srcPath, "node_modules"],
|
||||
extensions: [".js", ".jsx", ".json"],
|
||||
fallback: {
|
||||
// fs: false,
|
||||
// path: require.resolve("path-browserify"),
|
||||
// http: require.resolve("stream-http"),
|
||||
// https: require.resolve("https-browserify"),
|
||||
// zlib: require.resolve("browserify-zlib"),
|
||||
crypto: require.resolve("crypto-browserify"),
|
||||
stream: require.resolve("stream-browserify"),
|
||||
},
|
||||
alias:
|
||||
mode === "production"
|
||||
? {}
|
||||
: {
|
||||
react: path.join(__dirname, "node_modules/react"),
|
||||
"react-dom": path.join(__dirname, "node_modules/react-dom"),
|
||||
"styled-components": path.join(
|
||||
__dirname,
|
||||
"node_modules/styled-components"
|
||||
),
|
||||
},
|
||||
},
|
||||
target: "node",
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin({
|
||||
// Configure environment variables here.
|
||||
ENVIRONMENT: "browser",
|
||||
}),
|
||||
// new webpack.EnvironmentPlugin({
|
||||
// // Configure environment variables here.
|
||||
// ENVIRONMENT: "browser",
|
||||
// }),
|
||||
new CleanWebpackPlugin(),
|
||||
// Copies files from target to destination folder
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: paths.publicPath,
|
||||
to: "assets",
|
||||
globOptions: {
|
||||
ignore: ["*.DS_Store"],
|
||||
},
|
||||
noErrorOnMissing: true,
|
||||
},
|
||||
],
|
||||
}),
|
||||
new HTMLWebpackPlugin({
|
||||
template: `${paths.publicPath}/index.html`,
|
||||
favicon: `${paths.publicPath}/favicon.png`,
|
||||
robots: `${paths.publicPath}/robots.txt`,
|
||||
}),
|
||||
new webpack.ProgressPlugin(),
|
||||
new webpack.ProvidePlugin({
|
||||
process: "process/browser",
|
||||
Buffer: [require.resolve("buffer/"), "Buffer"],
|
||||
}),
|
||||
new ManifestPlugin.WebpackManifestPlugin(),
|
||||
],
|
||||
},
|
||||
loadConfig(mode),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user