diff --git a/.github/workflows/every-core-mainnet.yml b/.github/workflows/every-core-mainnet.yml new file mode 100644 index 0000000..723e269 --- /dev/null +++ b/.github/workflows/every-core-mainnet.yml @@ -0,0 +1,18 @@ +name: Deploy 'every.near' App Components to Mainnet + +on: + push: + branches: [main] + +jobs: + deploy-mainnet: + uses: nearbuilders/bos-workspace/.github/workflows/deploy.yml@main + with: + bw-legacy: false + deploy-env: "mainnet" + app-name: "core" + deploy-account-address: every.near + signer-account-address: every.near + signer-public-key: + secrets: + SIGNER_PRIVATE_KEY: ${{ secrets.EVERY_CORE_SIGNER_PRIVATE_KEY_MAINNET }} \ No newline at end of file diff --git a/.github/workflows/every-core-testnet.yml b/.github/workflows/every-core-testnet.yml new file mode 100644 index 0000000..c3b780f --- /dev/null +++ b/.github/workflows/every-core-testnet.yml @@ -0,0 +1,18 @@ +name: Deploy 'every.near' App Components to Testnet + +on: + push: + branches: [develop] + +jobs: + deploy-mainnet: + uses: nearbuilders/bos-workspace/.github/workflows/deploy.yml@main + with: + bw-legacy: false + deploy-env: "testnet" + app-name: "core" + deploy-account-address: allthethings.testnet + signer-account-address: allthethings.testnet + signer-public-key: + secrets: + SIGNER_PRIVATE_KEY: ${{ secrets.EVERY_CORE_SIGNER_PRIVATE_KEY_TESTNET }} \ No newline at end of file diff --git a/.github/workflows/every-video-mainnet.yml b/.github/workflows/every-video-mainnet.yml new file mode 100644 index 0000000..47de1ea --- /dev/null +++ b/.github/workflows/every-video-mainnet.yml @@ -0,0 +1,18 @@ +name: Deploy 'every.video.near' App Components to Mainnet + +on: + push: + branches: [main] + +jobs: + deploy-mainnet: + uses: nearbuilders/bos-workspace/.github/workflows/deploy.yml@main + with: + bw-legacy: false + deploy-env: "mainnet" + app-name: "video" + deploy-account-address: video.every.near + signer-account-address: video.every.near + signer-public-key: ed25519:4u1tcYqemMsr84btLphGq5wnUKgPSGgTH1ft8tFPhozB + secrets: + SIGNER_PRIVATE_KEY: ${{ secrets.EVERY_VIDEO_SIGNER_PRIVATE_KEY_MAINNET }} \ No newline at end of file diff --git a/.github/workflows/every-video-testnet.yml b/.github/workflows/every-video-testnet.yml new file mode 100644 index 0000000..f52e0cd --- /dev/null +++ b/.github/workflows/every-video-testnet.yml @@ -0,0 +1,18 @@ +name: Deploy 'every.video.near' App Components to Testnet + +on: + push: + branches: [main] + +jobs: + deploy-mainnet: + uses: nearbuilders/bos-workspace/.github/workflows/deploy.yml@main + with: + bw-legacy: false + deploy-env: "testnet" + app-name: "video" + deploy-account-address: video.allthethings.testnet + signer-account-address: video.allthethings.testnet + signer-public-key: + secrets: + SIGNER_PRIVATE_KEY: ${{ secrets.EVERY_VIDEO_SIGNER_PRIVATE_KEY_TESTNET }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index aa275b5..078fa96 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +node_modules +.vscode .DS_Store -/node_modules -/build \ No newline at end of file + +/build +/dist +tree.json + +test-results \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..40b878d --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..372532f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "printWidth": 100, + "tabWidth": 2, + "singleQuote": false, + "trailingComma": "es5", + "semi": true +} diff --git a/README.md b/README.md index 26a5f80..c8cc92a 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,15 @@ -# sdks.near +# every.near -## Setup & Development +## Getting started -Install packages: +1. Install packages ```cmd -yarn +yarn install ``` -Start development version: +2. Start dev environment ```cmd -yarn dev -``` - -This will start both a local gateway (http://127.0.0.1:4040) and http server for loading your local components. - -Optionally, to open local widgets in existing, supported gateways: - -1. Visit either of the following sites: - -- https://near.org/flags -- https://everything.dev/flags - -2. Paste the Bos Loader Http URL (http://127.0.0.1:4040/api/loader) +yarn run dev +``` \ No newline at end of file diff --git a/aliases.mainnet.json b/aliases.mainnet.json new file mode 100644 index 0000000..11f13ef --- /dev/null +++ b/aliases.mainnet.json @@ -0,0 +1,4 @@ +{ + "mob": "mob.near", + "near": "near" +} diff --git a/aliases.testnet.json b/aliases.testnet.json new file mode 100644 index 0000000..0c08670 --- /dev/null +++ b/aliases.testnet.json @@ -0,0 +1,4 @@ +{ + "mob": "mike.testnet", + "near": "discom.testnet" +} diff --git a/apps/core/bos.config.json b/apps/core/bos.config.json new file mode 100644 index 0000000..0132a61 --- /dev/null +++ b/apps/core/bos.config.json @@ -0,0 +1,10 @@ +{ + "account": "every.near", + "aliases": ["../../aliases.mainnet.json"], + "overrides": { + "testnet": { + "account": "allthethings.testnet", + "aliases": ["../../aliases.testnet.json"] + } + } +} diff --git a/apps/core/data.json b/apps/core/data.json new file mode 100644 index 0000000..dfc63d2 --- /dev/null +++ b/apps/core/data.json @@ -0,0 +1,3 @@ +{ + "every.near": {} +} diff --git a/apps/core/widget/components.jsx b/apps/core/widget/components.jsx new file mode 100644 index 0000000..1951870 --- /dev/null +++ b/apps/core/widget/components.jsx @@ -0,0 +1,18 @@ +const { Avatar } = VM.require("${config_account}/widget/components.ui.avatar"); +const { AvatarGroup } = VM.require("${config_account}/widget/components.ui.avatar-group"); +const { Badge } = VM.require("${config_account}/widget/components.ui.badge"); +const { Button } = VM.require("${config_account}/widget/components.ui.button"); +const { Chip } = VM.require("${config_account}/widget/components.ui.chip"); +const { Container } = VM.require("${config_account}/widget/components.ui.container"); +const { Logo } = VM.require("${config_account}/widget/components.ui.logo"); +const { Tag } = VM.require("${config_account}/widget/components.ui.tag"); +return { + Avatar, + AvatarGroup, + Badge, + Button, + Chip, + Container, + Logo, + Tag, +}; diff --git a/apps/core/widget/components/chips.jsx b/apps/core/widget/components/chips.jsx new file mode 100644 index 0000000..4d89643 --- /dev/null +++ b/apps/core/widget/components/chips.jsx @@ -0,0 +1,53 @@ +const { Chip } = VM.require("${config_account}/widget/components") || { + Chip: () => <>, +}; + +const items = props.items ?? []; +const onSelect = props.onSelect ?? (() => {}); + +const [selectedItems, setSelectedItems] = useState([]); + +const handleClick = (item) => { + if (props.multiple) { + if (!selectedItems.includes(item)) { + setSelectedItems((prev) => [...prev, item]); + } else if (selectedItems.includes(item)) { + setSelectedItems((prev) => prev.filter((i) => i !== item)); + } + } else { + if (selectedItems !== item) { + setSelectedItems(item); + } else if (selectedItems === item) { + setSelectedItems(null); + } + } +}; + +useEffect(() => { + onSelect(selectedItems); +}, [selectedItems, onSelect]); + +if (items.length === 0) { + return
No items passed
; +} + +const duplicates = items.filter((item, index) => items.indexOf(item) !== index); +if (duplicates.length > 0) { + return
Duplicate Items Found
; +} + +return ( +
+ {items.map((item) => ( + handleClick(item)} + size={props.size} + multiple={props.multiple} + > + {item} + + ))} +
+); diff --git a/apps/core/widget/components/navbar.jsx b/apps/core/widget/components/navbar.jsx new file mode 100644 index 0000000..95e70d7 --- /dev/null +++ b/apps/core/widget/components/navbar.jsx @@ -0,0 +1,492 @@ +const { Avatar, Button, Badge, Logo } = VM.require("${config_account}/widget/components") || { + Avatar: () => <>, + Button: () => <>, + Badge: () => <>, + Logo: () => <>, +}; + +const { MobileRight } = VM.require("${config_account}/widget/components.navbar.mobile-right") || { + MobileRight: () => <>, +}; +const { MobileLeft } = VM.require("${config_account}/widget/components.navbar.mobile-left") || { + MobileLeft: () => <>, +}; + +const { + Bell, + Check, + ChevronDown, + ChevronUp, + Code, + Download, + Everything, + FileCode, + GitFork, + Grip, + History, + LayoutTemplate, + LogOut, + Menu, + Moon, + PaintRoller, + PartyPopper, + QRCode, + ShoppingCart, + Sun, + UserCircle, + Video, +} = VM.require("${config_account}/widget/icons") || { + Bell: () => <>, + Check: () => <>, + ChevronDown: () => <>, + ChevronUp: () => <>, + Code: () => <>, + Download: () => <>, + Everything: () => <>, + FileCode: () => <>, + GitFork: () => <>, + Grip: () => <>, + History: () => <>, + LayoutTemplate: () => <>, + LogOut: () => <>, + Menu: () => <>, + Moon: () => <>, + PaintRoller: () => <>, + PartyPopper: () => <>, + QRCode: () => <>, + ShoppingCart: () => <>, + Sun: () => <>, + UserCircle: () => <>, + Video: () => <>, +}; + +const [appMenuOpen, setAppMenuOpen] = useState(false); +const [codeMenuOpen, setCodeMenuOpen] = useState(false); +const [menuDropdownOpen, setMenuDropdownOpen] = useState(false); + +const toggleAppMenu = useCallback(() => { + setMenuDropdownOpen(false); + setCodeMenuOpen(false); + setAppMenuOpen((prev) => !prev); +}, []); + +const toggleCodeMenu = useCallback(() => { + setMenuDropdownOpen(false); + setAppMenuOpen(false); + setCodeMenuOpen((prev) => !prev); +}, []); + +const toggleMenuDropdown = useCallback(() => { + setCodeMenuOpen(false); + setAppMenuOpen(false); + setMenuDropdownOpen((prev) => !prev); +}, []); + +// mobile +const [mobileRight, setMobileRight] = useState(false); +const [mobileLeft, setMobileLeft] = useState(false); + +const toggleMobileRight = useCallback(() => { + setMobileRight((prev) => !prev); +}, []); + +const toggleMobileLeft = useCallback(() => { + setMobileLeft((prev) => !prev); +}, []); + +const StyledNavbar = styled.div` + display: flex; + padding: 12px 40px; + align-items: center; + justify-content: space-between; + gap: 16px; + background: var(--bg, #fff); + border-bottom: 1px solid var(--stroke, #e2e2e2); + @media (max-width: 768px) { + padding: 16px; + gap: 8px; + } +`; + +const DropdownContent = styled.div` + position: absolute; + top: 100%; + width: 100%; + min-width: 200px; + margin-top: 4px; + display: flex; + padding: 8px 0; + flex-direction: column; + align-items: stretch; + background: var(--bg, #fff); + border-radius: 12px; + border: 1px solid var(--stroke, #e2e2e2); + box-shadow: 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06); + + button { + margin: 0 8px; + justify-content: flex-start; + color: var(--dropdown-button-color, #1c2024); + } +`; + +const BellCounter = styled.div` + position: absolute; + top: 35%; + right: 35%; + transform: translate(50%, -50%); + display: flex; + width: 10px; + height: 10px; + justify-content: center; + align-items: center; + border: 2px solid white; + gap: 4px; + flex-shrink: 0; + border-radius: 100%; + background: var(--btn-primary-danger-bg, #dc3d43); + border: 1.5px solid var(--btn-secondary-bg, #fff); + font-size: 12px; + font-weight: 500; + line-height: 140%; + letter-spacing: -0.12px; +`; + +const Separator = styled.div` + height: 1px; + background: var(--separator-color, #e2e2e2); + margin: 4px 0; + width: 100%; +`; + +const DropdownHeading = styled.div` + display: flex; + padding: 16px 16px 8px 16px; + margin: 0 8px; + align-items: center; + align-self: stretch; + color: #8f8f8f; + font-family: Poppins, sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 140%; /* 19.6px */ + letter-spacing: -0.14px; +`; + +const AppGrid = styled.div` + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1rem; +`; + +const AppCard = styled.div` + position: relative; + display: flex; + min-width: 160px; + padding: 16px; + flex-direction: column; + align-items: flex-start; + gap: 8px; + flex: 1 0 0; + border-radius: 20px; + border: 1px solid var(--stroke, #e2e2e2); + background: var(--btn-secondary-bg, #fff); + color: var(--btn-secondary-color, #000); + + /* Poppins/Text/M - 16px/Medium */ + font-family: Poppins, sans-serif; + font-weight: 500; + line-height: 150%; /* 24px */ + letter-spacing: -0.16px; + + .icon { + display: flex; + width: 40px; + height: 40px; + justify-content: center; + align-items: center; + border-radius: 12px; + background: var(--btn-secondary-hover-bg, #c7c7c7); + + svg { + height: 20px; + width: 20px; + } + + svg, + path { + color: var(--btn-secondary-color, #000); + stroke: var(--btn-secondary-color, #000); + } + } + + transition: all 300ms ease; + + &:hover { + cursor: pointer; + background: var(--btn-secondary-hover-bg, #c7c7c7); + } + &.disabled { + cursor: not-allowed; + background: var(--btn-secondary-hover-bg, #c7c7c7); + color: #6f6f6f; + svg, + path { + color: #c7c7c7; + stroke: #c7c7c7; + } + } +`; + +const getNotificationCount = () => { + const notificationFeedSrc = "mob.near/widget/NotificationFeed"; + + const lastBlockHeight = Storage.get("lastBlockHeight", notificationFeedSrc); + if (lastBlockHeight === null) { + return ""; + } + + const notifications = Social.index("notify", context.accountId, { + order: "asc", + from: (lastBlockHeight ?? 0) + 1, + // subscribe: true, + }); + + return notifications.length; +}; + +const unreadNotifications = getNotificationCount(); + +const MemoizedUserDropdown = useMemo( + () => ( + + ), + [context.accountId, menuDropdownOpen] +); + +const profile = Social.getr(`${context.accountId}/profile`); +const theme = profile.every.theme ?? "light"; + +return ( + <> + +
+
+ {/* Desktop */} + + + {appMenuOpen && ( + + + +
+
+ Video +
+ +
+ +
+ Canvas +
+ +
+ +
+ Event +
+ +
+ +
+ Profile +
+ + + Coming Soon + +
+ +
+ Marketplace +
+ +
+ +
+ App +
+ +
+ +
+ App +
+ +
+ +
+ App +
+
+
+ )} +
+ + + +
+
+ {context.accountId ? ( + <> +
+ + {unreadNotifications && } +
+
+ {MemoizedUserDropdown} + {menuDropdownOpen && ( + + + + + + + + )} +
+ + ) : ( + + )} +
+ + {codeMenuOpen && ( + + SOURCE CODE + + + + + APPEARANCE + + + {!context.accountId && ( + + Please login to change theme + + )} + + )} +
+
+
+ {context.accountId && ( +
+ + {unreadNotifications && } +
+ )} + +
+
+ {mobileRight && } + {mobileLeft && } + +); diff --git a/apps/core/widget/components/navbar/mobile-left.jsx b/apps/core/widget/components/navbar/mobile-left.jsx new file mode 100644 index 0000000..730b800 --- /dev/null +++ b/apps/core/widget/components/navbar/mobile-left.jsx @@ -0,0 +1,227 @@ +const { Badge, Button, Logo } = VM.require("${config_account}/widget/components") || { + Badge: () => <>, + Button: () => <>, + Logo: () => <>, +}; + +const { Code, Everything, LayoutTemplate, PaintRoller, PartyPopper, ShoppingCart, X, Video } = + VM.require("${config_account}/widget/icons") || { + Code: () => <>, + Everything: () => <>, + LayoutTemplate: () => <>, + PaintRoller: () => <>, + PartyPopper: () => <>, + ShoppingCart: () => <>, + X: () => <>, + Video: () => <>, + }; + +const Container = styled.div` + display: none; + + @media (max-width: 768px) { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--bg, #fff); + z-index: 1049; + display: flex; + flex-direction: column; + overflow-y: auto; + + .close-button { + svg { + width: 28px; + height: 28px; + stroke-width: 0; + } + } + } +`; + +const Heading = styled.div` + display: flex; + padding: 16px 16px 8px 16px; + margin: 0 8px; + align-items: center; + align-self: stretch; + color: #8f8f8f; + font-family: Poppins, sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 140%; /* 19.6px */ + letter-spacing: -0.14px; +`; + +const AppGrid = styled.div` + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1rem; + padding: 1rem; +`; + +const AppCard = styled.div` + position: relative; + display: flex; + min-width: 160px; + padding: 16px; + flex-direction: column; + align-items: flex-start; + gap: 8px; + flex: 1 0 0; + border-radius: 20px; + border: 1px solid var(--stroke, #e2e2e2); + background: var(--btn-secondary-bg, #fff); + color: var(--btn-secondary-color, #000); + + /* Poppins/Text/M - 16px/Medium */ + font-family: Poppins, sans-serif; + font-weight: 500; + line-height: 150%; /* 24px */ + letter-spacing: -0.16px; + + .icon { + display: flex; + width: 40px; + height: 40px; + justify-content: center; + align-items: center; + border-radius: 12px; + background: var(--btn-secondary-hover-bg, #c7c7c7); + + svg { + height: 20px; + width: 20px; + } + + svg, + path { + color: var(--btn-secondary-color, #000); + stroke: var(--btn-secondary-color, #000); + } + } + + transition: all 300ms ease; + + &:hover { + cursor: pointer; + background: var(--btn-secondary-hover-bg, #c7c7c7); + } + &.disabled { + cursor: not-allowed; + background: var(--app-card-disabled-bg, #c7c7c7); + color: #6f6f6f; + svg, + path { + color: #c7c7c7; + stroke: #c7c7c7; + } + } +`; + +const Links = styled.div` + display: flex; + flex-direction: column; + align-items: stretch; + padding: 16px; + flex-grow: 1; + + button { + justify-content: flex-start; + padding: 8px; + line-height: 140%; /* 19.6px */ + letter-spacing: -0.14px; + } + + .active { + color: var(--color); + font-weight: 500; + } +`; + +const MobileLeft = ({ toggle }) => { + return ( + +
+ + +
+ + + +
+ ALL APPS + + +
+
+ Video +
+ +
+ +
+ Canvas +
+ +
+ +
+ Event +
+ +
+ +
+ Profile +
+ + + Soon + +
+ +
+ Marketplace +
+ +
+ +
+ App +
+ +
+ +
+ App +
+ +
+ +
+ App +
+
+
+
+ ); +}; +return { MobileLeft }; diff --git a/apps/core/widget/components/navbar/mobile-right.jsx b/apps/core/widget/components/navbar/mobile-right.jsx new file mode 100644 index 0000000..a2d11d7 --- /dev/null +++ b/apps/core/widget/components/navbar/mobile-right.jsx @@ -0,0 +1,256 @@ +const { Avatar, Button, Logo } = VM.require("${config_account}/widget/components") || { + Avatar: () => <>, + Button: () => <>, + Logo: () => <>, +}; + +const { + Everything, + X, + GitFork, + Sun, + Moon, + Check, + FileCode, + History, + UserCircle, + QRCode, + Download, + LogOut, +} = VM.require("${config_account}/widget/icons") || { + Everything: () => <>, + X: () => <>, + GitFork: () => <>, + Sun: () => <>, + Moon: () => <>, + Check: () => <>, + FileCode: () => <>, + History: () => <>, + UserCircle: () => <>, + QRCode: () => <>, + Download: () => <>, + LogOut: () => <>, +}; + +const Container = styled.div` + display: none; + + @media (max-width: 768px) { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--bg, #fff); + z-index: 1049; + display: flex; + flex-direction: column; + overflow-y: auto; + + .close-button { + svg { + width: 28px; + height: 28px; + stroke-width: 0; + } + } + } +`; + +const ProfileSection = styled.div` + display: flex; + padding: 24px 8px; + flex-direction: column; + align-items: stretch; + gap: 10px; + flex: 1 0 0; + align-self: stretch; +`; + +const ProfileButtons = styled.div` + display: flex; + flex-direction: column; + button { + justify-content: flex-start; + color: var(--dropdown-button-color, #1c2024); + padding: 8px 12px 8px 8px; + } +`; + +const OptionSection = styled.div` + display: flex; + padding: 8px; + flex-direction: column; + align-items: stretch; + align-self: stretch; + button { + justify-content: flex-start; + color: var(--dropdown-button-color, #1c2024); + padding: 8px 12px 8px 8px; + } +`; + +const Heading = styled.div` + display: flex; + padding: 16px 16px 8px 16px; + margin: 0 8px; + align-items: center; + align-self: stretch; + color: #8f8f8f; + font-family: Poppins, sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 140%; /* 19.6px */ + letter-spacing: -0.14px; +`; + +const Separator = styled.div` + height: 1px; + background: var(--separator-color, #e2e2e2); + margin: 4px 0; + width: 100%; +`; + +const UserInfo = styled.div` + display: flex; + flex-direction: column; + padding: 0 16px; + + h6 { + color: var(--color, #0d0d0d); + font-family: Poppins, sans-serif; + font-weight: 500; + line-height: 150%; /* 24px */ + letter-spacing: -0.16px; + margin: 0; + } + + p { + color: var(--color, #0d0d0d); + font-family: Poppins, sans-serif; + font-size: 14px; + line-height: 140%; /* 19.6px */ + letter-spacing: -0.14px; + margin: 0; + } +`; + +const MobileRight = ({ toggle, accountId }) => { + const profile = Social.getr(`${accountId}/profile`); + const theme = profile.every.theme ?? "light"; + + return ( + +
+ {accountId ? : } + +
+ {accountId && ( + +
{profile.name}
+

{accountId}

+
+ )} + + {accountId ? ( + <> + ) : ( + <> + + + )} + + + + + + + + SOURCE CODE + + + + + APPEARANCE + + + {!accountId && ( + + Please login to change theme + + )} + + + +
+ ); +}; + +return { MobileRight }; diff --git a/apps/core/widget/components/ui/avatar-group.jsx b/apps/core/widget/components/ui/avatar-group.jsx new file mode 100644 index 0000000..f6ff70c --- /dev/null +++ b/apps/core/widget/components/ui/avatar-group.jsx @@ -0,0 +1,47 @@ +const { Avatar } = VM.require("${config_account}/widget/components.ui.avatar") || { + Avatar: () => <>, +}; + +const AvatarGroup = ({ accountIds, large, size, maxCount }) => { + const amount = accountIds.length; + const remaining = amount - maxCount; + + return ( +
+ {accountIds.splice(0, maxCount ?? amount).map((accountId) => ( + + ))} + {remaining > 0 && ( +
+ +{remaining} +
+ )} +
+ ); +}; + +return { AvatarGroup }; diff --git a/apps/core/widget/components/ui/avatar.jsx b/apps/core/widget/components/ui/avatar.jsx new file mode 100644 index 0000000..293909e --- /dev/null +++ b/apps/core/widget/components/ui/avatar.jsx @@ -0,0 +1,65 @@ +const { User } = VM.require("${config_account}/widget/icons") || { + User: () => <>, +}; + +const Avatar = ({ accountId, size, large, form, imageStyle, key }) => { + const imageForm = form ?? "circle"; + const profile = Social.getr(`${accountId}/profile`); + if (!profile.image) { + return ( +
+ {profile.name ? ( + profile.name[0] + ) : ( + + )} +
+ ); + } + + return ( + + ); +}; + +return { Avatar }; diff --git a/apps/core/widget/components/ui/badge.jsx b/apps/core/widget/components/ui/badge.jsx new file mode 100644 index 0000000..a77bc64 --- /dev/null +++ b/apps/core/widget/components/ui/badge.jsx @@ -0,0 +1,145 @@ +const StyledBadge = styled.div` + display: inline-flex; + height: 28px; + min-width: 28px; + padding: 4px 8px; + justify-content: center; + align-items: center; + gap: 4px; + flex-shrink: 0; + + border-radius: 100px; + + background: rgba(0, 0, 0, 0.05); + color: #171717; + background: ${(props) => { + if (props.variant === "outline") { + return "white"; + } + + if (props.color === "black") { + return props.variant === "alpha" ? "rgba(0, 0, 0, 0.05)" : "#171717"; + } else if (props.color === "blue") { + return props.variant === "alpha" ? "rgba(2, 128, 255, 0.07)" : "#0081F1"; + } else if (props.color === "green") { + return props.variant === "alpha" ? "rgba(2, 186, 60, 0.09)" : "#299764"; + } else if (props.color === "yellow") { + return props.variant === "alpha" ? "rgba(255, 234, 1, 0.18)" : "#F7CE00"; + } else if (props.color === "red") { + return props.variant === "alpha" ? "rgba(255, 1, 1, 0.06)" : "#DC3D43"; + } + }}; + + color: ${(props) => { + if (props.variant === "outline") { + if (props.color === "black") { + return "var(--badge-alpha-black-color, #171717)"; + } else if (props.color === "blue") { + return "#006ADC"; + } else if (props.color === "green") { + return "#18794E"; + } else if (props.color === "yellow") { + return "#35290F"; + } else if (props.color === "red") { + return "#CD2B31"; + } + } + if (props.color === "black") { + return props.variant === "alpha" ? "var(--badge-alpha-black-color, #171717)" : "#fff"; + } else if (props.color === "blue") { + return props.variant === "alpha" ? "#006ADC" : "#fff"; + } else if (props.color === "green") { + return props.variant === "alpha" ? "#18794E" : "#fff"; + } else if (props.color === "yellow") { + return props.variant === "alpha" ? "#35290F" : "#fff"; + } else if (props.color === "red") { + return props.variant === "alpha" ? "#CD2B31" : "#fff"; + } + }}; + + border: 1px solid + ${(props) => { + if (props.variant === "outline") { + if (props.color === "black") { + return "var(--badge-alpha-black-color, #171717)"; + } else if (props.color === "blue") { + return "#006ADC"; + } else if (props.color === "green") { + return "#18794E"; + } else if (props.color === "yellow") { + return "#35290F"; + } else if (props.color === "red") { + return "#CD2B31"; + } + } + }}; + + svg, + path { + fill: ${(props) => { + if (props.variant === "outline") { + if (props.color === "black") { + return "var(--badge-alpha-black-color, #171717)"; + } else if (props.color === "blue") { + return "#006ADC"; + } else if (props.color === "green") { + return "#18794E"; + } else if (props.color === "yellow") { + return "#35290F"; + } else if (props.color === "red") { + return "#CD2B31"; + } + } + if (props.color === "black") { + return props.variant === "alpha" ? "var(--badge-alpha-black-color, #171717)" : "#fff"; + } else if (props.color === "blue") { + return props.variant === "alpha" ? "#006ADC" : "#fff"; + } else if (props.color === "green") { + return props.variant === "alpha" ? "#18794E" : "#fff"; + } else if (props.color === "yellow") { + return props.variant === "alpha" ? "#35290F" : "#fff"; + } else if (props.color === "red") { + return props.variant === "alpha" ? "#CD2B31" : "#fff"; + } + }}; + } + + font-family: Poppins, sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 140%; /* 19.6px */ + letter-spacing: -0.14px; + + ${(props) => { + if (props.size === "small") { + return { + height: "24px", + minWidth: "24px", + fontSize: "12px", + }; + } else if (props.size === "x-small") { + return { + height: "20px", + minWidth: "20px", + fontSize: "12px", + padding: "4px", + }; + } else if (props.size === "xx-small") { + return { + height: "16px", + minWidth: "16px", + padding: "4px", + }; + } + }} +`; + +const Badge = ({ children, size, variant, color, ...restProps }) => { + return ( + + {children} + + ); +}; + +return { Badge }; diff --git a/apps/core/widget/components/ui/button.jsx b/apps/core/widget/components/ui/button.jsx new file mode 100644 index 0000000..1207657 --- /dev/null +++ b/apps/core/widget/components/ui/button.jsx @@ -0,0 +1,269 @@ +const StyledButton = styled.button` + /* base style */ + all: unset; + display: inline-flex; + padding: 8px 20px; + justify-content: center; + align-items: center; + gap: 8px; + border-radius: 12px; + + /* font */ + font-family: Poppins, sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 150%; /* 24px */ + letter-spacing: -0.16px; + + /* transition */ + transition: all 300ms ease; + + /* variant styles */ + background: ${(props) => { + if (props.variant === "primary" && props.type === "danger") { + return "var(--btn-primary-danger-bg, #DC3D43)"; + } else if (props.variant === "primary") { + return "var(--btn-primary-bg, #171717)"; + } else if (props.variant === "secondary" || props.variant === "tertiary") { + return "var(--btn-secondary-bg, #fff)"; + } + }}; + + border: ${(props) => { + if (props.variant === "secondary" && props.type === "danger") { + return "1px solid var(--btn-secondary-danger-stroke, #F3AEAF)"; + } else if (props.variant === "secondary") { + return "1px solid var(--btn-secondary-stroke, #DBDBDB)"; + } else { + return ""; // No border for other cases + } + }}; + + color: ${(props) => { + if (props.variant === "primary") { + return "var(--btn-primary-color, #fff)"; + } else if ( + (props.variant === "secondary" || props.variant === "tertiary") && + props.type === "danger" + ) { + return "var(--btn-secondary-danger-color, #CD2B31) !important"; + } else if (props.variant === "secondary") { + return "var(--btn-secondary-color, #171717)"; + } else if (props.variant === "tertiary") { + return "var(--btn-tertiary-color, #6F6F6F)"; + } + }}; + + /* handle svg */ + svg, + path { + stroke: ${(props) => { + if (props.variant === "primary") { + return "var(--btn-primary-color, #fff)"; + } else if ( + (props.variant === "secondary" || props.variant === "tertiary") && + props.type === "danger" + ) { + return "var(--btn-secondary-danger-color, #CD2B31) !important"; + } else if (props.variant === "secondary") { + return "var(--btn-secondary-color, #171717)"; + } else if (props.variant === "tertiary") { + return "var(--btn-tertiary-color, #6F6F6F)"; + } + }}; + } + + font-size: ${(props) => { + if (props.size === "large") { + return "16px"; + } + }}; + + height: ${(props) => { + if (props.size === "large") { + return "32px"; + } else if (props.size === "medium") { + return "24px"; + } else if (props.size === "small") { + return "16px"; + } + }}; + + width: ${(props) => { + if (props.icon) { + if (props.size === "large") { + return "32px"; + } else if (props.size === "medium") { + return "24px"; + } else if (props.size === "small") { + return "16px"; + } + } + }}; + + padding: ${(props) => { + if (props.icon) { + return "8px"; + } + }}; + + &:hover { + cursor: pointer; + background: ${(props) => { + if (props.variant === "primary" && props.type === "danger") { + return "#CD2B31"; + } else if (props.variant === "primary") { + return "var(--btn-primary-hover-bg, #6F6F6F)"; + } else if (props.variant === "secondary") { + return "var(btn-secondary-hover-bg, #FCFCFC)"; + } else if (props.variant === "tertiary" && props.type === "danger") { + return "var(--btn-tertiary-danger-hover-bg,#FF050508)"; + } else if (props.variant === "tertiary") { + return "var(--btn-tertiary-hover-bg, #F8F8F8)"; + } + }}; + + border: ${(props) => { + if (props.variant === "secondary") { + return "1px solid var(--btn-secondary-hover-stroke, #C7C7C7)"; + } + }}; + } + + &:disabled { + cursor: not-allowed; + background: ${(props) => { + if (props.variant === "primary") { + return "var(--btn-primary-disabled-bg, #C7C7C7)"; + } + }}; + border: ${(props) => { + if (props.variant === "secondary") { + return "1px solid var(--btn-secondary-disabled-stroke, #DBDBDB)"; + } + }}; + color: ${(props) => { + if (props.variant === "primary") { + return "rgba(255, 255, 255, 0.59)"; + } else if (props.variant === "secondary" || props.variant === "tertiary") { + return "var(--btn-primary-disabled-bg, #C7C7C7)"; + } + }}; + + svg, + path { + stroke: ${(props) => { + if (props.variant === "primary") { + return "rgba(255, 255, 255, 0.59)"; + } else if (props.variant === "secondary" || props.variant === "tertiary") { + return "var(--btn-primary-disabled-bg, #C7C7C7)"; + } + }}; + } + } +`; + +const StyledLink = styled.button` + all: unset; + + display: inline-flex; + padding: 2px 4px; + justify-content: center; + align-items: center; + gap: 8px; + border-radius: 12px; + + color: #006adc; + + svg, + path { + stroke: #006adc; + } + + font-family: Poppins, sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 140%; /* 19.6px */ + letter-spacing: -0.14px; + + font-size: ${(props) => { + if (props.size === "large") { + return "16px"; + } + }}; + + transition: all 300ms ease; + + &:hover { + cursor: pointer; + text-decoration: none; + background: #f5faff; + color: #006adc; + + svg, + path { + stroke: #006adc; + } + } + + &:active { + color: #006adc; + + svg, + path { + stroke: #006adc; + } + } + + &:disabled { + color: #c7c7c7; + svg, + path { + stroke: #c7c7c7; + } + } +`; + +const Button = ({ + children, + onClick, + variant, + size, + href, + type, + icon, + linkClassName, + ...restProps +}) => { + if (href) { + return ( + + + {children} + + + ); + } + + return ( + + {children} + + ); +}; + +return { Button }; diff --git a/apps/core/widget/components/ui/chip.jsx b/apps/core/widget/components/ui/chip.jsx new file mode 100644 index 0000000..c00b43d --- /dev/null +++ b/apps/core/widget/components/ui/chip.jsx @@ -0,0 +1,65 @@ +const { Plus, X } = VM.require("${config_account}/widget/icons") || { + Plus: () => <>, + X: () => <>, +}; + +const StyledChip = styled.div` + display: inline-flex; + height: 32px; + padding: 8px 16px; + justify-content: center; + align-items: center; + gap: 8px; + flex-shrink: 0; + + ${(props) => { + if (props.size === "small") { + return { + height: "24px", + padding: "8px 12px", + }; + } + }} + + border-radius: 12px; + background: var(--chip-bg, #f3f3f3); + + color: var(--chip-color, #171717); + font-family: Poppins, sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 140%; /* 19.6px */ + letter-spacing: -0.14px; + + transition: all 300ms ease; + cursor: pointer; + + &:hover { + background: var(--chip-hover-bg, #e8e8e8); + } + + &.selected { + background: var(--chip-selected-bg, #171717); + color: var(--chip-selected-color, #fff); + + svg { + path { + fill: var(--chip-selected-icon, #dbdbdb); + } + } + + &:hover { + background: var(--chip-selected-hover-bg, #6f6f6f); + } + } +`; + +const Chip = ({ children, selected, onClick, size, multiple, ...restProps }) => { + return ( + + {children} {multiple ? selected ? : : null} + + ); +}; + +return { Chip }; diff --git a/apps/core/widget/components/ui/container.jsx b/apps/core/widget/components/ui/container.jsx new file mode 100644 index 0000000..de091a8 --- /dev/null +++ b/apps/core/widget/components/ui/container.jsx @@ -0,0 +1,13 @@ +const Container = styled.div` + padding: 32px 40px; + background: var(--bg, #fff); + color: var(--color, #0d0d0d); + height: 100%; + flex-grow: 1; + + @media (max-width: 768px) { + padding: 24px 16px; + } +`; + +return { Container }; diff --git a/apps/core/widget/components/ui/library.jsx b/apps/core/widget/components/ui/library.jsx new file mode 100644 index 0000000..14982d0 --- /dev/null +++ b/apps/core/widget/components/ui/library.jsx @@ -0,0 +1,248 @@ +const { Avatar, AvatarGroup, Button, Badge, Container } = VM.require( + "${config_account}/widget/components" +) || { + Avatar: () => <>, + AvatarGroup: () => <>, + Button: () => <>, + Badge: () => <>, + Container: () => <>, +}; + +const badgeSizes = ["xx-small", "x-small", "small", "medium"]; +const badgeStyles = ["alpha", "solid"]; +const badgeColors = ["black", "blue", "green", "yellow", "red"]; + +const avatarIds = [ + "itexpert120-contra.near", + "kwok0997.near", + "itexpert120-contra.near", + "itexpert120-contra.near", + "itexpert120-contra.near", + "itexpert120-contra.near", + "itexpert120-contra.near", + "itexpert120-contra.near", +]; + +const [selected, setSelected] = useState(null); + +const badges = []; + +badgeSizes.forEach((size) => { + badgeStyles.forEach((style) => { + badgeColors.forEach((color) => { + badges.push({ size, style, color }); + }); + }); +}); + +return ( +
+

UI Library

+

Button

+
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + +
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+ + + +
+
+

Badge

+
+ {badges.map((badge, index) => ( + + 1 + + ))} +
+

Chips

+

Single

+ setSelected(selected), + }} + /> +

Multiple

+ setSelected(selected), + multiple: true, + }} + /> +

Avatar

+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+); diff --git a/apps/core/widget/components/ui/logo.jsx b/apps/core/widget/components/ui/logo.jsx new file mode 100644 index 0000000..cafe3f3 --- /dev/null +++ b/apps/core/widget/components/ui/logo.jsx @@ -0,0 +1,41 @@ +const { Everything } = VM.require("${config_account}/widget/icons") || { + Everything: () => <>, +}; + +const LogoText = styled.div` + span { + color: var(--color, #0d0d0d); + font-size: 18px; + font-style: normal; + font-weight: 600; + line-height: 100%; /* 18px */ + text-transform: lowercase; + margin-left: 12px; + } + + circle { + fill: var(--color, #0d0d0d); + } + @media (max-width: 768px) { + span { + font-size: 15px; + margin-left: 10px; + } + + svg { + width: 20px; + height: 20px; + } + } +`; + +const Logo = () => { + return ( + + + everything + + ); +}; + +return { Logo }; diff --git a/apps/core/widget/components/ui/tag.jsx b/apps/core/widget/components/ui/tag.jsx new file mode 100644 index 0000000..9633b98 --- /dev/null +++ b/apps/core/widget/components/ui/tag.jsx @@ -0,0 +1,24 @@ +const { X } = VM.require("${config_account}/widget/icons") || { + X: () => <>, +}; + +const { Badge } = VM.require("${config_account}/widget/components") || { + Badge: () => <>, +}; + +const Tag = ({ children, size, variant, color, ...restProps }) => { + return ( + + {children} + + + ); +}; + +return { Tag }; diff --git a/apps/core/widget/icons.jsx b/apps/core/widget/icons.jsx new file mode 100644 index 0000000..b2ae1eb --- /dev/null +++ b/apps/core/widget/icons.jsx @@ -0,0 +1,53 @@ +const { Bell } = VM.require("${config_account}/widget/icons.bell"); +const { Check } = VM.require("${config_account}/widget/icons.check"); +const { ChevronDown } = VM.require("${config_account}/widget/icons.chevron-down"); +const { ChevronUp } = VM.require("${config_account}/widget/icons.chevron-up"); +const { Code } = VM.require("${config_account}/widget/icons.code"); +const { Download } = VM.require("${config_account}/widget/icons.download"); +const { Everything } = VM.require("${config_account}/widget/icons.everything"); +const { FileCode } = VM.require("${config_account}/widget/icons.file-code"); +const { GitFork } = VM.require("${config_account}/widget/icons.git-fork"); +const { Grip } = VM.require("${config_account}/widget/icons.grip"); +const { History } = VM.require("${config_account}/widget/icons.history"); +const { LayoutTemplate } = VM.require("${config_account}/widget/icons.layout-template"); +const { LogOut } = VM.require("${config_account}/widget/icons.log-out"); +const { Menu } = VM.require("${config_account}/widget/icons.menu"); +const { Moon } = VM.require("${config_account}/widget/icons.moon"); +const { PaintRoller } = VM.require("${config_account}/widget/icons.paint-roller"); +const { PartyPopper } = VM.require("${config_account}/widget/icons.party-popper"); +const { Plus } = VM.require("${config_account}/widget/icons.plus"); +const { QRCode } = VM.require("${config_account}/widget/icons.qr-code"); +const { ShoppingCart } = VM.require("${config_account}/widget/icons.shopping-cart"); +const { Sun } = VM.require("${config_account}/widget/icons.sun"); +const { UserCircle } = VM.require("${config_account}/widget/icons.user-circle"); +const { User } = VM.require("${config_account}/widget/icons.user"); +const { Video } = VM.require("${config_account}/widget/icons.video"); +const { X } = VM.require("${config_account}/widget/icons.x"); + +return { + Bell, + Check, + ChevronDown, + ChevronUp, + Code, + Download, + Everything, + FileCode, + GitFork, + Grip, + History, + LayoutTemplate, + LogOut, + Menu, + Moon, + PaintRoller, + PartyPopper, + Plus, + QRCode, + ShoppingCart, + Sun, + UserCircle, + User, + Video, + X, +}; diff --git a/apps/core/widget/icons/bell.jsx b/apps/core/widget/icons/bell.jsx new file mode 100644 index 0000000..a35d906 --- /dev/null +++ b/apps/core/widget/icons/bell.jsx @@ -0,0 +1,15 @@ +const Bell = () => { + return ( + + + + ); +}; + +return { Bell }; diff --git a/apps/core/widget/icons/check.jsx b/apps/core/widget/icons/check.jsx new file mode 100644 index 0000000..22d8706 --- /dev/null +++ b/apps/core/widget/icons/check.jsx @@ -0,0 +1,15 @@ +const Check = () => { + return ( + + + + ); +}; + +return { Check }; diff --git a/apps/core/widget/icons/chevron-down.jsx b/apps/core/widget/icons/chevron-down.jsx new file mode 100644 index 0000000..3d99753 --- /dev/null +++ b/apps/core/widget/icons/chevron-down.jsx @@ -0,0 +1,15 @@ +const ChevronDown = () => { + return ( + + + + ); +}; + +return { ChevronDown }; diff --git a/apps/core/widget/icons/chevron-up.jsx b/apps/core/widget/icons/chevron-up.jsx new file mode 100644 index 0000000..ee6c78f --- /dev/null +++ b/apps/core/widget/icons/chevron-up.jsx @@ -0,0 +1,15 @@ +const ChevronUp = () => { + return ( + + + + ); +}; + +return { ChevronUp }; diff --git a/apps/core/widget/icons/code.jsx b/apps/core/widget/icons/code.jsx new file mode 100644 index 0000000..6f691b4 --- /dev/null +++ b/apps/core/widget/icons/code.jsx @@ -0,0 +1,15 @@ +const Code = () => { + return ( + + + + ); +}; + +return { Code }; diff --git a/apps/core/widget/icons/download.jsx b/apps/core/widget/icons/download.jsx new file mode 100644 index 0000000..3d9a37c --- /dev/null +++ b/apps/core/widget/icons/download.jsx @@ -0,0 +1,15 @@ +const Download = () => { + return ( + + + + ); +}; + +return { Download }; diff --git a/apps/core/widget/icons/everything.jsx b/apps/core/widget/icons/everything.jsx new file mode 100644 index 0000000..4ed9d81 --- /dev/null +++ b/apps/core/widget/icons/everything.jsx @@ -0,0 +1,9 @@ +const Everything = () => { + return ( + + + + ); +}; + +return { Everything }; diff --git a/apps/core/widget/icons/file-code.jsx b/apps/core/widget/icons/file-code.jsx new file mode 100644 index 0000000..82630fa --- /dev/null +++ b/apps/core/widget/icons/file-code.jsx @@ -0,0 +1,15 @@ +const FileCode = () => { + return ( + + + + ); +}; + +return { FileCode }; diff --git a/apps/core/widget/icons/git-fork.jsx b/apps/core/widget/icons/git-fork.jsx new file mode 100644 index 0000000..8c85141 --- /dev/null +++ b/apps/core/widget/icons/git-fork.jsx @@ -0,0 +1,15 @@ +const GitFork = () => { + return ( + + + + ); +}; + +return { GitFork }; diff --git a/apps/core/widget/icons/grip.jsx b/apps/core/widget/icons/grip.jsx new file mode 100644 index 0000000..96086c5 --- /dev/null +++ b/apps/core/widget/icons/grip.jsx @@ -0,0 +1,107 @@ +const Grip = () => { + return ( + + + + + + + + + + + + + + + + + + + + + ); +}; + +return { Grip }; diff --git a/apps/core/widget/icons/history.jsx b/apps/core/widget/icons/history.jsx new file mode 100644 index 0000000..332b1e3 --- /dev/null +++ b/apps/core/widget/icons/history.jsx @@ -0,0 +1,15 @@ +const History = () => { + return ( + + + + ); +}; + +return { History }; diff --git a/apps/core/widget/icons/layout-template.jsx b/apps/core/widget/icons/layout-template.jsx new file mode 100644 index 0000000..2104df2 --- /dev/null +++ b/apps/core/widget/icons/layout-template.jsx @@ -0,0 +1,29 @@ +const LayoutTemplate = () => { + return ( + + + + + + ); +}; + +return { LayoutTemplate }; diff --git a/apps/core/widget/icons/log-out.jsx b/apps/core/widget/icons/log-out.jsx new file mode 100644 index 0000000..6088729 --- /dev/null +++ b/apps/core/widget/icons/log-out.jsx @@ -0,0 +1,22 @@ +const LogOut = () => { + return ( + + + + + + ); +}; + +return { LogOut }; diff --git a/apps/core/widget/icons/menu.jsx b/apps/core/widget/icons/menu.jsx new file mode 100644 index 0000000..4561459 --- /dev/null +++ b/apps/core/widget/icons/menu.jsx @@ -0,0 +1,15 @@ +const Menu = () => { + return ( + + + + ); +}; + +return { Menu }; diff --git a/apps/core/widget/icons/moon.jsx b/apps/core/widget/icons/moon.jsx new file mode 100644 index 0000000..717353e --- /dev/null +++ b/apps/core/widget/icons/moon.jsx @@ -0,0 +1,15 @@ +const Moon = () => { + return ( + + + + ); +}; + +return { Moon }; diff --git a/apps/core/widget/icons/paint-roller.jsx b/apps/core/widget/icons/paint-roller.jsx new file mode 100644 index 0000000..2d555f8 --- /dev/null +++ b/apps/core/widget/icons/paint-roller.jsx @@ -0,0 +1,22 @@ +const PaintRoller = () => { + return ( + + + + + + + + + + + ); +}; + +return { PaintRoller }; diff --git a/apps/core/widget/icons/party-popper.jsx b/apps/core/widget/icons/party-popper.jsx new file mode 100644 index 0000000..9d1f922 --- /dev/null +++ b/apps/core/widget/icons/party-popper.jsx @@ -0,0 +1,22 @@ +const PartyPopper = () => { + return ( + + + + + + + + + + + ); +}; + +return { PartyPopper }; diff --git a/apps/core/widget/icons/plus.jsx b/apps/core/widget/icons/plus.jsx new file mode 100644 index 0000000..06ba3c1 --- /dev/null +++ b/apps/core/widget/icons/plus.jsx @@ -0,0 +1,12 @@ +const Plus = () => { + return ( + + + + ); +}; + +return { Plus }; diff --git a/apps/core/widget/icons/qr-code.jsx b/apps/core/widget/icons/qr-code.jsx new file mode 100644 index 0000000..801c3a5 --- /dev/null +++ b/apps/core/widget/icons/qr-code.jsx @@ -0,0 +1,15 @@ +const QRCode = () => { + return ( + + + + ); +}; + +return { QRCode }; diff --git a/apps/core/widget/icons/shopping-cart.jsx b/apps/core/widget/icons/shopping-cart.jsx new file mode 100644 index 0000000..1487b63 --- /dev/null +++ b/apps/core/widget/icons/shopping-cart.jsx @@ -0,0 +1,22 @@ +const ShoppingCart = () => { + return ( + + + + + + + + + + + ); +}; + +return { ShoppingCart }; diff --git a/apps/core/widget/icons/sun.jsx b/apps/core/widget/icons/sun.jsx new file mode 100644 index 0000000..66fa8eb --- /dev/null +++ b/apps/core/widget/icons/sun.jsx @@ -0,0 +1,22 @@ +const Sun = () => { + return ( + + + + + + + + + + + ); +}; + +return { Sun }; diff --git a/apps/core/widget/icons/user-circle.jsx b/apps/core/widget/icons/user-circle.jsx new file mode 100644 index 0000000..e64483e --- /dev/null +++ b/apps/core/widget/icons/user-circle.jsx @@ -0,0 +1,22 @@ +const UserCircle = () => { + return ( + + + + + + + + + + + ); +}; + +return { UserCircle }; diff --git a/apps/core/widget/icons/user.jsx b/apps/core/widget/icons/user.jsx new file mode 100644 index 0000000..f720b29 --- /dev/null +++ b/apps/core/widget/icons/user.jsx @@ -0,0 +1,21 @@ +const User = ({ width, height, color }) => { + return ( + + + + ); +}; + +return { User }; diff --git a/apps/core/widget/icons/video.jsx b/apps/core/widget/icons/video.jsx new file mode 100644 index 0000000..0fbc7e0 --- /dev/null +++ b/apps/core/widget/icons/video.jsx @@ -0,0 +1,22 @@ +const Video = () => { + return ( + + + + + ); +}; + +return { Video }; diff --git a/apps/core/widget/icons/x.jsx b/apps/core/widget/icons/x.jsx new file mode 100644 index 0000000..073ccbb --- /dev/null +++ b/apps/core/widget/icons/x.jsx @@ -0,0 +1,12 @@ +const X = () => { + return ( + + + + ); +}; + +return { X }; diff --git a/apps/every.near/widget/thing.jsx b/apps/core/widget/thing.jsx similarity index 100% rename from apps/every.near/widget/thing.jsx rename to apps/core/widget/thing.jsx diff --git a/apps/devs.near/bos.config.json b/apps/devs.near/bos.config.json deleted file mode 100644 index 25f7b18..0000000 --- a/apps/devs.near/bos.config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "appAccount": "devs.near" -} \ No newline at end of file diff --git a/apps/devs.near/widget/Community.jsx b/apps/devs.near/widget/Community.jsx deleted file mode 100644 index 3c4798d..0000000 --- a/apps/devs.near/widget/Community.jsx +++ /dev/null @@ -1,179 +0,0 @@ -const accountId = props.accountId ?? context.accountId; - -const creatorId = props.creatorId ?? "hack.near"; -const pageId = props.pageId ?? "community.page"; - -return ( - <> - - -); -ine-block; - background: #efa9ca; - border-radius: 20px; - position: relative; - padding: 0.1em 0.2em 0; - - svg { - position: absolute; - bottom: -8px; - right: -10px; - width: 24px; - } - } - - @media (max-width: 900px) { - font-size: 50px; - - span { - border-radius: 12px; - svg { - position: absolute; - bottom: -6px; - right: -7px; - width: 16px; - } - } - } -`; - -const Text = styled.p` - font-family: "FK Grotesk", sans-serif; - font-size: ${(p) => p.size ?? "18px"}; - line-height: ${(p) => p.lineHeight ?? "1.5"}; - font-weight: ${(p) => p.weight ?? "400"}; - color: ${(p) => p.color ?? "#000"}; - margin: 0; -`; - -const Flex = styled.div` - display: flex; - gap: ${(p) => p.gap}; - align-items: ${(p) => p.alignItems}; - justify-content: ${(p) => p.justifyContent}; - flex-direction: ${(p) => p.direction ?? "row"}; - flex-wrap: ${(p) => p.wrap ?? "nowrap"}; - - ${(p) => - p.mobileStack && - ` - @media (max-width: 900px) { - flex-direction: column; - gap: var(--section-gap); - } - `} -`; - -const Content = styled.div` - @media (max-width: 1200px) { - > div:first-child { - } - } -`; - -const Container = styled.div` - display: flex; - max-width: 1060px; - margin: 0 auto; - gap: ${(p) => p.gap ?? "var(--section-gap)"}; - flex-direction: column; - align-items: ${(p) => (p.center ? "center" : undefined)}; - justify-content: ${(p) => (p.center ? "center" : undefined)}; - text-align: ${(p) => (p.center ? "center" : undefined)}; - padding: var(--section-gap) 23px; -`; - -return ( - - {!isOwner && ( - - -

- - NDC{" "} - - - Work Groups -

-
-
- )} - - - {!isOwner ? ( - - {!accountId ? ( - - ) : ( - - )} - - ) : ( - - - - )} - - - - - Made Possible by{" "} - - NDC - - - - - -
-); diff --git a/apps/devs.near/widget/Compose.jsx b/apps/devs.near/widget/Compose.jsx deleted file mode 100644 index 203c52c..0000000 --- a/apps/devs.near/widget/Compose.jsx +++ /dev/null @@ -1,99 +0,0 @@ -if (!context.accountId) { - return ""; -} - -const index = props.index || { - post: JSON.stringify({ - key: "main", - value: { - type: "md", - }, - }), -}; - -const composeData = () => { - if (props.appendHashtags) { - state.content.text = props.appendHashtags(state.content.text); - } - const data = { - post: { - main: JSON.stringify(state.content), - }, - index, - }; - - const item = { - type: "social", - path: `${context.accountId}/post/main`, - }; - - const notifications = state.extractMentionNotifications( - state.content.text, - item - ); - - if (notifications.length) { - data.index.notify = JSON.stringify( - notifications.length > 1 ? notifications : notifications[0] - ); - } - - const hashtags = state.extractHashtags(state.content.text); - - if (hashtags.length) { - data.index.hashtag = JSON.stringify( - hashtags.map((hashtag) => ({ - key: hashtag, - value: item, - })) - ); - } - - return data; -}; - -State.init({ - onChange: ({ content }) => { - State.update({ content }); - }, -}); - -return ( - <> -
- { - State.update({ extractMentionNotifications, extractHashtags }); - }, - composeButton: (onCompose) => ( - { - onCompose(); - }} - > - Post - - ), - }} - /> -
- {state.content && ( - - )} - -); diff --git a/apps/devs.near/widget/ContextMenu.jsx b/apps/devs.near/widget/ContextMenu.jsx deleted file mode 100644 index f8c426b..0000000 --- a/apps/devs.near/widget/ContextMenu.jsx +++ /dev/null @@ -1,66 +0,0 @@ -const Wrapper = styled.div` - padding: 6px; - min-width: 200px; - width: 200px; - border-radius: 6px; - box-shadow: 0 3px 15px -3px rgba(13, 20, 33, 0.13); - display: flex; - flex-direction: column; - border: 1px solid #e8e8eb; - background-color: #fff; - gap: 1px; - - .menu__item { - padding: 3px; - display: flex; - color: #000; - border-radius: 6px; - cursor: pointer; - - &:hover { - background-color: #eff2f5; - } - } - .menu__item__icon { - font-size: 14px; - border-radius: 5px; - box-shadow: 0 0 0 1px rgba(201, 201, 204, 0.48); - background: #fff; - color: #000; - height: 26px; - width: 26px; - display: flex; - margin-right: 10px; - justify-content: center; - align-items: center; - } -`; - -function ContextMenu({ Item, passProps, handlers, items }) { - return ( - - -
- -
-
- - - {handlers && - Object.keys(handlers).map((key) => { - return ( - handlers[key](passProps[key])} - > - {items[key]()} - - ); - })} - - -
- ); -} - -return { ContextMenu }; \ No newline at end of file diff --git a/apps/devs.near/widget/Feed.jsx b/apps/devs.near/widget/Feed.jsx deleted file mode 100644 index a4db46d..0000000 --- a/apps/devs.near/widget/Feed.jsx +++ /dev/null @@ -1,89 +0,0 @@ -const Feed = ({ index, typeWhitelist, Item, Layout, showCompose }) => { - Item = Item || ((props) =>
{JSON.stringify(props)}
); - Layout = Layout || (({ children }) => children); - - const renderItem = (a, i) => { - if (typeWhitelist && !typeWhitelist.includes(a.value.type)) { - return false; - } - return ( -
- -
- ); - }; - - const composeIndex = () => { - const arr = Array.isArray(index) ? index : [index]; - - const grouped = arr.reduce((acc, i) => { - if (i.action !== "repost") { - if (!acc[i.action]) { - acc[i.action] = []; - } - acc[i.action].push({ key: i.key, value: { type: "md" } }); - } - return acc; - }, {}); - - Object.keys(grouped).forEach((action) => { - if (grouped[action].length === 1) { - grouped[action] = grouped[action][0]; - } - grouped[action] = JSON.stringify(grouped[action]); - }); - - return grouped; - }; - - const appendHashtags = (v) => { - const arr = Array.isArray(index) ? index : [index]; - const hashtags = arr - .filter((i) => i.action === "hashtag") - .map((i) => i.key); - - hashtags.forEach((hashtag) => { - if (v.toLowerCase().includes(`#${hashtag.toLowerCase()}`)) return; - else v += ` #${hashtag}`; - }); - - return v; - }; - - return ( - <> - {showCompose && ( - - )} - {Array.isArray(index) ? ( - {children}, - }} - /> - ) : ( - {children}, - }} - /> - )} - - ); -}; - -return { Feed }; diff --git a/apps/devs.near/widget/GitBos/info.jsx b/apps/devs.near/widget/GitBos/info.jsx deleted file mode 100644 index e9fc7ee..0000000 --- a/apps/devs.near/widget/GitBos/info.jsx +++ /dev/null @@ -1,76 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const creatorId = props.creatorId ?? "devs.near"; -const groupId = props.groupId ?? "builders"; - -const joined = Social.keys(`${creatorId}/graph/${groupId}/${accountId}/**`); - -const requested = Social.keys(`${accountId}/graph/${groupId}/${accountId}/**`); -const numRequested = requested ? Object.keys(requested || {}).length : null; - -const isMember = numRequested > 0; - -const handleJoin = () => { - Social.set({ - graph: { [groupId]: { [accountId]: "" } }, - index: { - graph: JSON.stringify({ - key: groupId, - value: { - accountId, - }, - }), - notify: JSON.stringify({ - key: creatorId, - value: { - accountId, - message: "membership request", - }, - }), - }, - }); -}; - -return ( -
-
- - - Learn More - -
- -
-); diff --git a/apps/devs.near/widget/GitBos/kit.jsx b/apps/devs.near/widget/GitBos/kit.jsx deleted file mode 100644 index 557d466..0000000 --- a/apps/devs.near/widget/GitBos/kit.jsx +++ /dev/null @@ -1,59 +0,0 @@ -const kit = context.accountId - ? Social.get(`${context.accountId}/settings/near.builders/kit`) - : undefined; - -if (kit === null) { - return ""; -} - -const defaultWidgets = [ - { - src: "devs.near/widget/GitBos.info", - }, - { - src: "devs.near/widget/dev.collab", - }, -]; - -const widgets = (kit && JSON.parse(kit)) ?? defaultWidgets; - -const Div = styled.div` - position: relative; - @media (hover: hover) { - > .edit-link { - display: none; - } - } - &:hover { - > .edit-link { - display: inline; - } - } -`; - -return ( -
-
-
Welcome Builders!
- {context.accountId && ( - - Customize - - )} -
-
- {widgets.map( - ({ src, requiresLogin }, i) => - (!requiresLogin || context.accountId) && ( -
- -
- ) - )} -
-
-); diff --git a/apps/devs.near/widget/GitBos/kit/editor.jsx b/apps/devs.near/widget/GitBos/kit/editor.jsx deleted file mode 100644 index a6b31ed..0000000 --- a/apps/devs.near/widget/GitBos/kit/editor.jsx +++ /dev/null @@ -1,144 +0,0 @@ -const accountId = context.accountId; - -const kit = context.accountId - ? Social.get(`${context.accountId}/settings/near.builders/kit`) - : undefined; - -if (kit === null) { - return ""; -} - -const defaultWidgets = [ - { - src: "devs.near/widget/GitBos.info", - }, - { - src: "devs.near/widget/dev.collab", - }, -]; - -const settingWidgets = kit && JSON.parse(kit); - -if (state.widgets === undefined) { - const widgets = settingWidgets ?? defaultWidgets; - State.update({ widgets }); -} - -const move = (fromIndex, toIndex) => { - const widget = state.widgets.splice(fromIndex, 1)[0]; - if (toIndex !== undefined) { - state.widgets.splice(toIndex, 0, widget); - } - State.update(); -}; - -const renderMenu = (src, requireLogin, index) => { - return ( -
-
{src}
- - - - - -
- ); -}; - -const openButton = ({ widgetPath: src, onHide }) => { - return ( - - ); -}; - -return ( - <> -

GitBos Kit

-
- -
-
- - Update - - {settingWidgets && - JSON.stringify(state.widgets) !== JSON.stringify(settingWidgets) && ( - - )} - {JSON.stringify(state.widgets) !== JSON.stringify(defaultWidgets) && ( - - )} -
-
- {state.widgets.map(({ src, requiresLogin }, i) => ( -
- {renderMenu(src, requireLogin, i)} -
- -
-
- ))} - -); diff --git a/apps/devs.near/widget/GithubForkButton.jsx b/apps/devs.near/widget/GithubForkButton.jsx deleted file mode 100644 index 32857da..0000000 --- a/apps/devs.near/widget/GithubForkButton.jsx +++ /dev/null @@ -1,19 +0,0 @@ -const username = props.username ?? "near-everything"; -const repository = props.repository ?? "bos-workspace"; - -const GithubForkButton = styled.a` - cursor: pointer; - text-decoration: none; -`; - -const Button = styled.button``; - -return ( - - - -); diff --git a/apps/devs.near/widget/Library.jsx b/apps/devs.near/widget/Library.jsx deleted file mode 100644 index c164e5b..0000000 --- a/apps/devs.near/widget/Library.jsx +++ /dev/null @@ -1,270 +0,0 @@ -/** - * This is just a direct copy of mob.near/widget/N.Library - */ -const accountId = context.accountId || "root.near"; -const authorId = "mob.near"; - -const itemDescription = - 'The identifier item. It will be used as a unique identifier of the entity that receives the action. It\'s also used as a key of the action in the index.\nThe item should be an object with the following keys: `type`, `path` and optional `blockHeight`.\n- `type`: If the data is stored in the social DB, then the type is likely `"social"`, other types can be defined in the standards.\n- `path`: The path to the item. For a `"social"` type, it\'s absolute path within SocialDB, e.g. `alice.near/post/main`.\n- `blockHeight`: An optional paremeter to indicate the block when the data was stored. Since SocialDB data can be overwritten to save storage, the exact data should be referenced by the block height (e.g. for a given post). But if the latest data should be used, then `blockHeight` should be ommited.\n\nExamples of `item`:\n- `{type: "social", path: "mob.near/widget/N.Library"}`\n- `{type: "social", path: "mob.near/post/main", blockHeight: 81101335}`\n'; - -const components = [ - { - title: "Feed", - // category: "Profile", - widgetName: "Feed", - description: - "", - // demoProps: { accountId }, - // requiredProps: { - // accountId: "The account ID of the profile", - // }, - // optionalProps: { - // profile: "Object that holds profile information to display", - // fast: "Render profile picture faster using external cache, default true if the `props.profile` is not provided", - // hideDescription: "Don't show description, default false", - // }, - }, - { - title: "Context Menu", - // category: "Profile", - widgetName: "ContextMenu", - description: - "", - // demoProps: { accountId, tooltip: true }, - // requiredProps: { - // accountId: "The account ID of the profile", - // }, - // optionalProps: { - // profile: "Object that holds profile information to display", - // fast: "Render profile picture faster using external cache, default true if the `props.profile` is not provided", - // tooltip: - // "Display overlay tooltip when you hover over the profile, default false", - // }, - }, - { - title: "Router", - // category: "Profile", - widgetName: "Router", - description: - "", - // demoProps: { accountId, tooltip: true }, - // requiredProps: { - // accountId: "The account ID of the profile", - // }, - // optionalProps: { - // link: "Whether to make profile clickable with a link to the profile page, default true.", - // hideAccountId: "Don't show account ID, default false", - // hideName: "Don't show profile name, default false", - // hideImage: "Don't show profile picture, default false", - // hideCheckmark: "Don't show premium checkmark, default false", - // profile: "Object that holds profile information to display", - // fast: "Render profile picture faster using external cache, default true if the `props.profile` is not provided", - // title: - // 'Optional title when you hover over the profile. Default `"${name} ${accountId}"`', - // tooltip: - // "Display overlay tooltip or title when you hover over the profile, default false. Will display a custom title if tooltip is given. If tooltip is true, the full tooltip is displayed. Default false", - // }, - }, -]; - -const renderProps = (props, optional) => { - return Object.entries(props || {}).map(([key, desc]) => { - return ( - - - - {key} - - - - - - - ); - }); -}; - -const renderComponent = (c, i) => { - const widgetSrc = `${authorId}/widget/${c.widgetName}`; - const embedCode = ` ` ${s}`) - .join("\n")}}}\n/>\n`; - const id = c.title.toLowerCase().replaceAll(" ", "-"); - return ( -
-
- -

{c.title}

-
-

{c.description}

- -
- -
- -
-
- -
- -
- - - - - - - - - - {renderProps(c.requiredProps)} - {renderProps(c.optionalProps, true)} - -
KeyDescription
- -
- -
- -
-
-
- ); -}; - -const renderMenuItem = (c, i) => { - const prev = i ? components[i - 1] : null; - const res = []; - if (!prev || prev.category !== c.category) { - res.push( -
- {c.category} -
- ); - } - const id = c.title.toLowerCase().replaceAll(" ", "-"); - res.push( -
- {c.title} -
- ); - return res; -}; - -const Wrapper = styled.div` -@media(min-width: 992px) { - .b-s { - border-left: 1px solid #eee; - } - .b-e { - border-right: 1px solid #eee; - } -} -.category:not(:first-child) { - margin-top: 1em; -} -.component { - padding: 0.5em 12px; - padding-bottom: 0; - margin-bottom: 3em; - margin: 0 -12px 3em; - position: relative; - - &:hover { - background: rgba(0, 0, 0, 0.03); - } - - .anchor { - position: absolute; - top: -70px; - } - - table { - background: white; - } - - label { - font-size: 20px; - } - - .code { - display: inline-flex; - line-height: normal; - border-radius: 0.3em; - padding: 0 4px; - border: 1px solid #ddd; - background: rgba(0, 0, 0, 0.03); - font-family: var(--bs-font-monospace); - } - .path { - - } - .preview { - background-color: white; - padding: 12px; - border: 1px solid #eee; - border-radius: 12px; - pre { - margin-bottom: 0; - } - } - .props { - .prop-key { - font-weight: 600; - &.optional { - font-weight: normal; - } - } - .prop-desc { - p { - margin-bottom: 0; - } - } - } - .embed-code { - position: relative; - - .embed-copy { - position: absolute; - top: 18px; - right: 10px; - } - } -} -`; - -return ( - -

Social Components Library

-
- This library contains common social components used by near.social -
-
-
{components.map(renderMenuItem)}
-
{components.map(renderComponent)}
-
-
-); \ No newline at end of file diff --git a/apps/devs.near/widget/Livepeer/Creator.jsx b/apps/devs.near/widget/Livepeer/Creator.jsx deleted file mode 100644 index dde309e..0000000 --- a/apps/devs.near/widget/Livepeer/Creator.jsx +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Livepeer Creator - * - * Widget for uploading a video to Livepeer - * (https://docs.livepeer.org/reference/livepeer-js/asset/useCreateAsset) - * - * Props: - * @prop {File} video - the video file to upload - * @prop {Object} metadata - the metadata for the video - * @prop {Function} handleStatus - a callback for status updates - * @prop {Function} handleProgress - a callback for progress updates - * @prop {Function} handleError - a callback for error updates - * @prop {Function} handleAssets - a callback for asset updates - * @prop {Function} Button - a component to render the button - * @prop {Boolean} debug - whether to log debug messages - */ - -function handleStatus(status) { - if (props.debug) { - console.log("status", status); - } - if (props.handleStatus) { - props.handleStatus(status); - } -} - -function handleProgress(progress) { - if (props.debug) { - console.log("progress", progress); - } - if (props.handleProgress) { - props.handleProgress(progress); - } -} - -function handleAssets(assets) { - if (props.debug) { - console.log("assets", assets); - } - if (props.handleAssets) { - props.handleAssets(assets); - } -} - -function handleError(error) { - if (props.debug) { - console.log("error", error); - } - if (props.handleError) { - props.handleError(error); - } -} - -function Button({ disabled, onClick }) { - // TODO : Livepeer branded button - return ( - - ); -} - -return ( - -); diff --git a/apps/devs.near/widget/MetadataEditor.jsx b/apps/devs.near/widget/MetadataEditor.jsx deleted file mode 100644 index 9bc3fa0..0000000 --- a/apps/devs.near/widget/MetadataEditor.jsx +++ /dev/null @@ -1,125 +0,0 @@ -const initialMetadata = props.initialMetadata ?? {}; -const onChange = props.onChange; -const options = props.options; - -State.init({ - initialMetadata, - metadata: initialMetadata, - reportedMetadata: initialMetadata, - linktree: initialMetadata.linktree ?? {}, - image: initialMetadata.image, - backgroundImage: initialMetadata.backgroundImage, - screenshots: initialMetadata.screenshots ?? {}, -}); - -const metadata = { - name: options.name ? state.metadata.name : undefined, - description: options.name ? state.metadata.description : undefined, - linktree: - options.linktree && Object.keys(state.linktree).length > 0 - ? state.linktree - : undefined, - image: - options.image && state.image && Object.keys(state.image).length > 0 - ? state.image - : undefined, - backgroundImage: - options.backgroundImage && - state.backgroundImage && - Object.keys(state.backgroundImage).length > 0 - ? state.backgroundImage - : undefined, - tags: options.tags ? state.metadata.tags : undefined, - screenshots: options.screenshots ? state.metadata.screenshots : undefined, -}; - -if ( - onChange && - JSON.stringify(state.reportedMetadata) !== JSON.stringify(metadata) -) { - State.update({ - reportedMetadata: metadata, - }); - onChange(metadata); -} - -return ( - <> - {options.name && ( -
- {options.name.label ?? "Name"} - -
- )} - {options.image && ( -
- {options.image.label ?? "Image"} - State.update({ image }), - }} - /> -
- )} - {options.backgroundImage && ( -
- {options.backgroundImage.label ?? "Background image"} - State.update({ backgroundImage }), - }} - /> -
- )} - {options.description && ( -
- {options.description.label ?? "Description"} - (supports markdown) - - {state.progress ? ( - - - - ) : ( - - )} - -
- -
- -

-
-

- -

-

- Spending account ID:

{state.accountId}
-

-

Spending account secret key: {secretKeyToggle}

- -); diff --git a/apps/devs.near/widget/adapter/sputnik-dao.jsx b/apps/devs.near/widget/adapter/sputnik-dao.jsx deleted file mode 100644 index 2008547..0000000 --- a/apps/devs.near/widget/adapter/sputnik-dao.jsx +++ /dev/null @@ -1,85 +0,0 @@ -const call = ({ daoId, methodName, args, deposit }) => { - Near.call([ - { - contractName: daoId, - methodName, - args, - deposit: deposit, - gas: "219000000000000", - }, - ]); -}; - -const addProposal = ({ daoId, proposal }) => { - const policy = Near.view(daoId, "get_policy"); - - if (policy === null) { - return "Loading..."; // lol what does this do... - } - - const deposit = policy.proposal_bond; - - call({ - daoId, - methodName: "add_proposal", - args: { - proposal, - }, - deposit, - }); -}; - -const createFunctionCallProposal = ({ - daoId, - receiver_id, - method_name, - args, -}) => { - const proposal_args = Buffer.from(JSON.stringify(args), "utf-8").toString("base64"); - addProposal({ - daoId, - proposal: { - description: `call ${method_name} to ${receiver_id}`, - kind: { - FunctionCall: { - receiver_id, - actions: [ - { - method_name, - args: proposal_args, - deposit: "100000000000000000000000", - gas: "219000000000000", - }, - ], - }, - }, - }, - }); -}; - -const create = (v) => { - createFunctionCallProposal({ - daoId: "build.sputnik-dao.near", - receiver_id: "social.near", - method_name: "set", - args: { - data: { - "build.sputnik-dao.near": { - post: { - main: JSON.stringify(v), - }, - index: { - post: JSON.stringify({ - key: "main", - value: { - type: "md", - }, - }), - }, - }, - }, - }, - }) -}; - -return { createFunctionCallProposal, create }; diff --git a/apps/devs.near/widget/app.jsx b/apps/devs.near/widget/app.jsx deleted file mode 100644 index 13751c8..0000000 --- a/apps/devs.near/widget/app.jsx +++ /dev/null @@ -1,258 +0,0 @@ -const Container = styled.div` - display: flex; - height: 100vh; - width: 100%; -`; - -const Panel = styled.div` - flex: 1; - border: 1px solid black; - overflow: hidden; -`; - -const Wrapper = styled.div` - display: flex; - align-items: stretch; - height: 100%; -`; - -const Header = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - padding: 10px; - border-bottom: 1px solid black; -`; - -const Select = styled.select``; - -const Option = styled.option``; - -const Button = styled.button``; - -const Label = styled.label` - margin-right: 10px; -`; - -const types = [ - { - value: "devs.near/widget/markdown.edit", - label: "Markdown", - }, - { value: "devs.near/widget/code.edit", label: "Code" }, - { value: "devs.near/widget/canvas.edit", label: "Canvas" }, -]; - -const adapters = [ - { - value: null, - label: "Social DB", - }, - { - value: "devs.near/widget/adapter.sputnik-dao", - label: "Sputnik DAO", - }, -]; - -// const { Modal } = VM.require("buildhub.near/widget/components.Modal") || { -// Modal: () => <>hello, -// }; - -function PanelHeader({ - types, - handleTypeChange, - handleAdapterChange, - adapter, - value, -}) { - return ( -
-
- - -
- - {/*
- - - - -
*/} -
- ); -} - -const [editorValue, setEditorValue] = useState(""); -const [activeTab, setActiveTab] = useState("editor"); - -const [editorSrc, setEditorSrc] = useState( - "devs.near/widget/markdown.edit" -); -const [viewerSrc, setViewerSrc] = useState( - "devs.near/widget/markdown.view" -); - -const socialDbAdapter = { - get: (path, blockHeight) => { - if (!path) console.log("path not provided") && null; - if (!blockHeight) blockHeight = "final"; - return Social.get(path, blockHeight); - }, - create: (v) => { - const id = "routes"; - const parts = path.split("/"); - Social.set({ - [parts[1]]: { - [parts[2]]: { - "": code, - }, - }, - }); - return Social.set( - { - thing: { - [id]: { - "": v, - metadata: { - type: "app", - }, - }, - }, - }, - { - force: "true", - onCommit: (v) => { - console.log(v); - }, - onCancel: (v) => { - console.log(v); - }, - } - ); - }, -}; - -const [selectedItem, setSelectedItem] = useState("efiz.near/thing/routes"); -const [adapter, setAdapter] = useState(socialDbAdapter); - -function handleTypeChange(value) { - setEditorSrc(value); -} - -function handleViewerSrcChange(value) { - setViewerSrc(value); -} - -const handleTabClick = (tab) => { - setActiveTab(tab); -}; - -function handleAdapterChange(value) { - const adapter = value ? VM.require(value) : socialDbAdapter; - setAdapter(adapter); -} - -function Editor({ value, setEditorValue }) { - return ( - , - }} - /> - ); -} - -function Viewer({ value }) { - return ; -} - -function Sidebar() { - return ( - setSelectedItem(v) }} - /> - ); -} - -return ( - - {/* - - - - */} - - - - - -); diff --git a/apps/devs.near/widget/bos/Hashtag/Feed.jsx b/apps/devs.near/widget/bos/Hashtag/Feed.jsx deleted file mode 100644 index 169d80d..0000000 --- a/apps/devs.near/widget/bos/Hashtag/Feed.jsx +++ /dev/null @@ -1 +0,0 @@ -const hashtag = props.hashtag ?? "bos"; return (); \ No newline at end of file diff --git a/apps/devs.near/widget/canvas/edit.jsx b/apps/devs.near/widget/canvas/edit.jsx deleted file mode 100644 index 499c3fd..0000000 --- a/apps/devs.near/widget/canvas/edit.jsx +++ /dev/null @@ -1,23 +0,0 @@ -const { value, onChange, onSubmit, onCancel } = props; - -let initialShapes = {}; - -if (typeof value === "string") { - // I want to turn my string value into valid tldraw text -} - -function handleSave(v) { - console.log(v); -} - -return ( -
-
- -
-
-); diff --git a/apps/devs.near/widget/canvas/view.jsx b/apps/devs.near/widget/canvas/view.jsx deleted file mode 100644 index 35f623c..0000000 --- a/apps/devs.near/widget/canvas/view.jsx +++ /dev/null @@ -1,65 +0,0 @@ -const { value } = props; - -const [storeEvents, setStoreEvents] = useState([]); -const [uiEvents, setUiEvents] = useState([]); -const [viewMode, setViewMode] = useState("ui"); - -function handleChangeEvent(event) { - function logChangeEvent(eventName) { - setStoreEvents((events) => [...events, eventName]); - } - - // Process added records - for (const record of Object.values(event.changes.added)) { - logChangeEvent( - `Added: ${record.typeName} (ID: ${record.id}, X: ${record.x}, Y: ${record.y})` - ); - } - - // Process updated records - for (const [from, to] of Object.values(event.changes.updated)) { - logChangeEvent( - `Updated: ${from.typeName} (ID: ${from.id}, X: ${from.x} -> ${to.x}, Y: ${from.y} -> ${to.y})` - ); - } - - // Process removed records - for (const record of Object.values(event.changes.removed)) { - logChangeEvent( - `Removed: ${record.typeName} (ID: ${record.id}, X: ${record.x}, Y: ${record.y})` - ); - } -} - -function handleUiEvent(name, data) { - setUiEvents((events) => [...events, `${name} ${JSON.stringify(data)}`]); -} - -function EventLog({ changeEvents, uiEvents }) { - let eventsToShow = []; - if (viewMode === "ui") { - eventsToShow = uiEvents; - } else if (viewMode === "change") { - eventsToShow = changeEvents; - } - - return ( -
-
    - {eventsToShow.map((eventName, index) => ( -
  • {eventName}
  • - ))} -
-
- ); -} - -console.log("props", props); - -return ( -
-
- -
-
-); diff --git a/apps/devs.near/widget/code/edit.jsx b/apps/devs.near/widget/code/edit.jsx deleted file mode 100644 index 5ed6ab0..0000000 --- a/apps/devs.near/widget/code/edit.jsx +++ /dev/null @@ -1,51 +0,0 @@ -const { value, onChange, onSubmit, onCancel } = props; - -const Container = styled.div` - display: flex; - flex-direction: column; - height: 100%; - width: 100%; -`; - -const Header = styled.div` - width: 100%; - background-color: #f0f0f0; -`; - -const EditorContainer = styled.div` - flex-grow: 1; - width: 100%; -`; - -const Footer = styled.div` - height: 120px; - width: 100%; - background-color: #f0f0f0; -`; - -const defaultValue = value; -const language = "json"; -const [path, setPath] = useState(props.path || ""); - -const [code, setCode] = useState(defaultValue); - -useEffect(() => { - onChange && onChange(code); -}, [code]); - -return ( - - - - - -); diff --git a/apps/devs.near/widget/code/view.jsx b/apps/devs.near/widget/code/view.jsx deleted file mode 100644 index 738da9b..0000000 --- a/apps/devs.near/widget/code/view.jsx +++ /dev/null @@ -1,3 +0,0 @@ -const { value } = props; - -return ; diff --git a/apps/devs.near/widget/community/Banner.jsx b/apps/devs.near/widget/community/Banner.jsx deleted file mode 100644 index 7f3e863..0000000 --- a/apps/devs.near/widget/community/Banner.jsx +++ /dev/null @@ -1,69 +0,0 @@ -const Banner = styled.div` - { - height: 62px; - background: #181818; - padding: 16px 20px; - - img { - height: 30px; - } - - margin-bottom: 25px; - } -`; - -return ( - <> - - - - - - - -); diff --git a/apps/devs.near/widget/community/Featured.jsx b/apps/devs.near/widget/community/Featured.jsx deleted file mode 100644 index 6b33707..0000000 --- a/apps/devs.near/widget/community/Featured.jsx +++ /dev/null @@ -1,20 +0,0 @@ -const Hover = styled.div` - &:hover { - box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1), - 0px 1px 2px rgba(16, 24, 40, 0.06); - } -`; - -return ( - - - -
{props.title}
-
{props.desc}
-
-
-); diff --git a/apps/devs.near/widget/community/Groups.jsx b/apps/devs.near/widget/community/Groups.jsx deleted file mode 100644 index c12b3d6..0000000 --- a/apps/devs.near/widget/community/Groups.jsx +++ /dev/null @@ -1,121 +0,0 @@ -const Cover = styled.img` - border-radius: 8px; - width: 150px; - object-fit: cover; -`; - -const ActionButton = styled.a` - border-radius: 5px; - width: auto; - text-transform: uppercase; - padding: 8px 14px; - background: #888; - color: #fff; - cursor: pointer; - font-weight: 600; - :hover { - opacity: 0.8; - text-decoration: none; - background: #333; - color: #fff; - } -`; - -const Card = styled.div` - border-radius: 8px; - color: #0c0c0c; - align-items: center; - justify-content: center; - max-width: 210px; - padding: 25px 32px; - display: flex; - flex-direction: column; -`; - -const CardList = styled.div` - display: grid; - justify-items: center; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - grid-template-rows: repeat(200px, 1fr); - gap: 0.5rem; -`; - -const GroupCard = (props) => { - const { title, coverSrc, actionButtons } = props; - - return ( - - -
-
- {actionButtons.map((button, index) => ( - handleButtonClick(button.url)} - href={button.url} - target="_blank" - rel="noopener noreferrer" - > - {button.label} - - ))} -
-
- ); -}; - -const Images = [ - { - title: "DeFi", - url: "https://ipfs.near.social/ipfs/bafkreifikdi444catqds54ulo3kwujvetmng7pwmr2tmg7hadtxmfguyeu", - }, - { - title: "NFTs", - url: "https://ipfs.near.social/ipfs/bafkreib56aciji2mgnwhqt3nkmutxqfednxqllgzvd5gm6d4mcjbumnxzm", - }, - { - title: "Gaming", - url: "https://ipfs.near.social/ipfs/bafkreifzp5dafotrrzitwrp2op6shyavpad4nx6rxl2wk2xf343a6vtgqa", - }, - { - title: "Amplify", - url: "https://ipfs.near.social/ipfs/bafkreigqamafvyfqcwsp4gl4nyh4wof7ldrz7oloj5fb22lqbu77fz7pda", - }, -]; - -const Links = [ - { title: "DeFi", url: "https://t.me/+50ySHiGjLn04M2Rh" }, - { title: "NFTs", url: "https://t.me/+i3GC2WYx5b5hMThh" }, - { title: "Gaming", url: "https://t.me/+QM6OtCRhcUdiYjhh" }, - { title: "Amplify", url: "https://t.me/+KCCfcYe-IKI2ZjEx" }, -]; - -return ( -
- - {Images.map((image, i) => ( - - ))} - -
-); diff --git a/apps/devs.near/widget/community/Hashtag/Feed.jsx b/apps/devs.near/widget/community/Hashtag/Feed.jsx deleted file mode 100644 index f1e0e1c..0000000 --- a/apps/devs.near/widget/community/Hashtag/Feed.jsx +++ /dev/null @@ -1 +0,0 @@ -const hashtag = props.hashtag ?? "community"; return (); \ No newline at end of file diff --git a/apps/devs.near/widget/community/Header.jsx b/apps/devs.near/widget/community/Header.jsx deleted file mode 100644 index 8de4eed..0000000 --- a/apps/devs.near/widget/community/Header.jsx +++ /dev/null @@ -1,118 +0,0 @@ -const Header = styled.div` - { - height: 204px; - overflow: hidden; - background: #f3f3f3; - padding: 10px 0; - margin-top: -25px; - margin-bottom: 25px; - padding-left: 32px; - } -`; - -const NavUnderline = styled.ul` - a { - color: #3252a6; - text-decoration: none; - } - - a.active { - font-weight: bold; - border-bottom: 2px solid #0c7283; - } -`; - -const BreadcrumbLink = styled.a` - { - color: #3252a6; - text-decoration: none; - } -`; -const BreadcrumbBold = styled.b` - { - color: #3252a6; - } -`; - -return ( - <> -
-
- -
-
- -
-
{props.title}
-
{props.desc}
-
-
- -
- -); diff --git a/apps/devs.near/widget/community/Layout.jsx b/apps/devs.near/widget/community/Layout.jsx deleted file mode 100644 index 81e4975..0000000 --- a/apps/devs.near/widget/community/Layout.jsx +++ /dev/null @@ -1,52 +0,0 @@ -const label = props.label ?? "regional"; - -const communities = { - regional: { - icon: "https://ipfs.near.social/ipfs/bafkreiajwq6ep3n7veddozji2djv5vviyisabhycbweslvpwhsoyuzcwi4", - cover: - "https://ipfs.near.social/ipfs/bafkreihgxg5kwts2juldaeasveyuddkm6tcabmrat2aaq5u6uyljtyt7lu", - title: "Regional", - }, - defi: { - icon: "https://ipfs.near.social/ipfs/bafkreidpitdafcnhkp4uyomacypdgqvxr35jtfnbxa5s6crby7qjk2nv5a", - cover: - "https://ipfs.near.social/ipfs/bafkreicg4svzfz5nvllomsahndgm7u62za4sib4mmbygxzhpcl4htqwr4a", - title: "DeFi", - }, - nft: { - icon: "https://ipfs.near.social/ipfs/bafkreie2eaj5czmpfe6pe53kojzcspgozebdsonffwvbxtpuipnwahybvi", - cover: - "https://ipfs.near.social/ipfs/bafkreiehzr7z2fhoqqmkt3z667wubccbch6sqtsnvd6msodyzpnf72cszy", - title: "NFTs", - }, - gaming: { - icon: "https://ipfs.near.social/ipfs/bafkreiepgdnu7soc6xgbyd4adicbf3eyxiiwqawn6tguaix6aklfpir634", - cover: - "https://ipfs.near.social/ipfs/bafkreiaowjqxds24fwcliyriintjd4ucciprii2rdxjmxgi7f5dmzuscey", - title: "Gaming", - }, -}; - -const Content = styled.div` - { - padding: 0 32px; - } -`; - -const community = communities[label]; - -return ( - <> - - - {props.children} - -); diff --git a/apps/devs.near/widget/community/Overview.jsx b/apps/devs.near/widget/community/Overview.jsx deleted file mode 100644 index 8050c39..0000000 --- a/apps/devs.near/widget/community/Overview.jsx +++ /dev/null @@ -1,70 +0,0 @@ -const label = props.label ?? "regional"; - -const communities = { - regional: { - overviewId: 397, - icon: "https://ipfs.near.social/ipfs/bafkreiajwq6ep3n7veddozji2djv5vviyisabhycbweslvpwhsoyuzcwi4", - cover: - "https://ipfs.near.social/ipfs/bafkreihgxg5kwts2juldaeasveyuddkm6tcabmrat2aaq5u6uyljtyt7lu", - title: "Regional", - }, - defi: { - overviewId: 412, - icon: "https://ipfs.near.social/ipfs/bafkreidpitdafcnhkp4uyomacypdgqvxr35jtfnbxa5s6crby7qjk2nv5a", - cover: - "https://ipfs.near.social/ipfs/bafkreicg4svzfz5nvllomsahndgm7u62za4sib4mmbygxzhpcl4htqwr4a", - title: "DeFi", - }, - nft: { - overviewId: 416, - icon: "https://ipfs.near.social/ipfs/bafkreie2eaj5czmpfe6pe53kojzcspgozebdsonffwvbxtpuipnwahybvi", - cover: - "https://ipfs.near.social/ipfs/bafkreiehzr7z2fhoqqmkt3z667wubccbch6sqtsnvd6msodyzpnf72cszy", - title: "NFTs", - }, - gaming: { - overviewId: 414, - icon: "https://ipfs.near.social/ipfs/bafkreiepgdnu7soc6xgbyd4adicbf3eyxiiwqawn6tguaix6aklfpir634", - cover: - "https://ipfs.near.social/ipfs/bafkreiaowjqxds24fwcliyriintjd4ucciprii2rdxjmxgi7f5dmzuscey", - title: "Gaming", - }, -}; - -const community = communities[props.label]; - -const onMention = (accountId) => ( - - - -); - -const Overview = ( -
- -
-); - -return ( - <> - - -); diff --git a/apps/devs.near/widget/community/Page.jsx b/apps/devs.near/widget/community/Page.jsx deleted file mode 100644 index 71b2379..0000000 --- a/apps/devs.near/widget/community/Page.jsx +++ /dev/null @@ -1,85 +0,0 @@ -const communities = { - regional: { - overviewId: 397, - icon: "https://ipfs.near.social/ipfs/bafkreiajwq6ep3n7veddozji2djv5vviyisabhycbweslvpwhsoyuzcwi4", - cover: - "https://ipfs.near.social/ipfs/bafkreihgxg5kwts2juldaeasveyuddkm6tcabmrat2aaq5u6uyljtyt7lu", - title: "Regional", - }, - defi: { - overviewId: 412, - icon: "https://ipfs.near.social/ipfs/bafkreidpitdafcnhkp4uyomacypdgqvxr35jtfnbxa5s6crby7qjk2nv5a", - cover: - "https://ipfs.near.social/ipfs/bafkreicg4svzfz5nvllomsahndgm7u62za4sib4mmbygxzhpcl4htqwr4a", - title: "DeFi", - }, - nft: { - overviewId: 416, - icon: "https://ipfs.near.social/ipfs/bafkreie2eaj5czmpfe6pe53kojzcspgozebdsonffwvbxtpuipnwahybvi", - cover: - "https://ipfs.near.social/ipfs/bafkreiehzr7z2fhoqqmkt3z667wubccbch6sqtsnvd6msodyzpnf72cszy", - title: "NFTs", - }, - gaming: { - overviewId: 414, - icon: "https://ipfs.near.social/ipfs/bafkreiepgdnu7soc6xgbyd4adicbf3eyxiiwqawn6tguaix6aklfpir634", - cover: - "https://ipfs.near.social/ipfs/bafkreiaowjqxds24fwcliyriintjd4ucciprii2rdxjmxgi7f5dmzuscey", - title: "Gaming", - }, -}; - -const Gradient = styled.div` - { - width: 100%; - margin-top: -25px; - margin-bottom: 25px; - height: 250px; - text-align: center; - background: #000; - - font-family: Arial, sans-serif; - } - - .subtitle-above { - font-size: 18px; - letter-spacing: 1px; - font-family: Courier, monospace; - } - - .subtitle-below { - font-size: 16px; - font-family: Courier, monospace; - - } - - .slogan { - font-weight: 600; - font-size: 60px; - font-family: Courier, monospace; - - } -`; - -return ( -
- -

- NEAR Work Groups -

-
- Share ideas, connect with people, and get involved! -
-
-
Featured Communities
-
- {Object.entries(communities).map(([label, community]) => { - return ( -
- -
- ); - })} -
-
-); diff --git a/apps/devs.near/widget/community/Rank.jsx b/apps/devs.near/widget/community/Rank.jsx deleted file mode 100644 index 4698fce..0000000 --- a/apps/devs.near/widget/community/Rank.jsx +++ /dev/null @@ -1,78 +0,0 @@ -const accountId = props.accountId ?? "academy.near"; -const accountFollowerCount = []; - -let accounts = Social.keys(`${accountId}/graph/follow/*`, "final", { - return_type: "BlockHeight", - values_only: true, -}); - -if (accounts === null) { - return "Loading..."; -} - -accounts = Object.entries(accounts[accountId].graph.follow || {}); -accounts.sort((a, b) => b[1] - a[1]); - -for (let i = 0; i < accounts.length; ++i) { - let accountId = accounts[i][0]; - let followers = Social.keys(`*/graph/follow/${accountId}`, "final", { - return_type: "BlockHeight", - values_only: true, - }); - if (followers) { - accountFollowerCount.push({ - accountId: accountId, - count: Object.keys(followers).length, - }); - } -} -const accountFollowerSort = accountFollowerCount.sort( - (a, b) => b.count - a.count -); -const numAccounts = accountFollowerSort.length; -accountFollowerSort = accountFollowerSort.slice(0, limit); -console.log(accountFollowerSort); - -return ( - <> -

Communities

- {accountFollowerSort.map((rank, index) => { - let accountId = rank.accountId; - return ( -
-
- -
-
-
- Rank: - - {index + 1} - -
-
- Followers:{" "} - - {rank.count} - -
-
-
- -
-
- ); - })} - -); diff --git a/apps/devs.near/widget/community/cta.jsx b/apps/devs.near/widget/community/cta.jsx deleted file mode 100644 index e2529d4..0000000 --- a/apps/devs.near/widget/community/cta.jsx +++ /dev/null @@ -1,113 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const daoId = props.daoId ?? "build.sputnik-dao.near"; - -let isBuilder = false; -let widgets = Social.get(`${accountId}/widget/*`, "final", { - return_type: "BlockHeight", - values_only: true, -}); -let widgetCount = 0; -if (widgets) { - widgetCount = Object.keys(widgets).length; -} -if (widgetCount > 0) { - isBuilder = true; -} - -const Text = styled.p` - font-family: "FK Grotesk", sans-serif; - font-size: ${(p) => p.size ?? "18px"}; - line-height: ${(p) => p.lineHeight ?? "1.5"}; - font-weight: ${(p) => p.weight ?? "400"}; - color: ${(p) => p.color ?? "#000"}; - margin-botton: 8px; -`; - -const FlexContainer = styled.div` - display: flex; - gap: 8px; - align-items: center; - flex-direction: row; - justify-content: center; - flex-wrap: wrap; - - @media (max-width: 998px) { - flex-direction: column; - gap: var(--section-gap); - } -`; - -const Flex = styled.div` - display: flex; - gap: 8px; - align-items: center; - flex-direction: column; - flex-wrap: "nowrap"; - - @media (max-width: 998px) { - flex-direction: column; - gap: var(--section-gap); - } -`; - -const Container = styled.div` - display: flex; - max-width: 1080px; - margin: 0 auto; - gap: var(--section-gap); - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - padding: var(--section-gap) 24px; -`; - -return ( - - {isBuilder ? ( -
- - Your Adventure Has Begun - - -
- -
-
-
- ) : ( - - - Begin a New Adventure - - -
- -
-
-
- )} -
-); diff --git a/apps/devs.near/widget/community/view.jsx b/apps/devs.near/widget/community/view.jsx deleted file mode 100644 index e607bb8..0000000 --- a/apps/devs.near/widget/community/view.jsx +++ /dev/null @@ -1,236 +0,0 @@ -const data = props.data; - -State.init({ - selectedTab: data.featuredTab || 0, -}); - -const Wrapper = styled.div` - --section-gap: 23px; - padding-top: 42px; - - @media (max-width: 1155px) { - .line-rounded-corners { - display: none !important; - } - } - - @media (max-width: 998px) { - padding-top: 0; - } -`; - -const H1 = styled.h1` - font-family: "FK Grotesk", sans-serif; - font-style: normal; - font-weight: 500; - font-size: 90px; - line-height: 1; - text-align: center; - letter-spacing: -0.03em; - color: #000; - margin: 0; - max-width: 700px; - - span { - display: inline-block; - background: ${data.title.highlightColor}; - border-radius: 20px; - position: relative; - padding: 0.1em 0.2em 0; - - svg { - position: absolute; - bottom: -8px; - right: -10px; - width: 24px; - } - } - - @media (max-width: 900px) { - font-size: 50px; - - span { - border-radius: 12px; - svg { - position: absolute; - bottom: -6px; - right: -7px; - width: 16px; - } - } - } -`; - -const Text = styled.p` - font-family: "FK Grotesk", sans-serif; - font-size: ${(p) => p.size ?? "18px"}; - line-height: ${(p) => p.lineHeight ?? "1.5"}; - font-weight: ${(p) => p.weight ?? "400"}; - color: ${(p) => p.color ?? "#000"}; - margin-botton: 8px; -`; - -const Flex = styled.div` - display: flex; - gap: 8px; - align-items: center; - flex-direction: column; - flex-wrap: "nowrap"; - - @media (max-width: 998px) { - flex-direction: column; - gap: var(--section-gap); - } -`; - -const Container = styled.div` - display: flex; - max-width: 1080px; - margin: 0 auto; - gap: var(--section-gap); - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - padding: var(--section-gap) 24px; -`; - -const Tabs = styled.div` - display: flex; - height: 48px; - border-bottom: 1px solid #eceef0; - margin-bottom: 4px; - overflow: auto; - scroll-behavior: smooth; - justify-content: center; - - @media (max-width: 1200px) { - background: #f8f9fa; - border-top: 1px solid #eceef0; - margin: 0 -12px 48px; - - > * { - flex: 1; - } - } -`; - -const TabsButton = styled.a` - display: inline-flex; - align-items: center; - justify-content: center; - height: 100%; - font-weight: 600; - font-size: 23px; - padding: 0 12px; - position: relative; - color: ${(p) => (p.selected ? "#11181C" : "#687076")}; - background: none; - border: none; - outline: none; - text-align: center; - text-decoration: none !important; - - &:hover { - color: #11181c; - cursor: pointer; - } - - &::after { - content: ""; - display: ${(p) => (p.selected ? "block" : "none")}; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 3px; - background: #59e692; - } -`; - -const handleTabClick = (tab) => { - State.update({ - selectedTab: tab, - }); -}; - -function Content() { - return ( - - ); -} - -return ( - - - -

- {data.title.highlightPosition === "left" ? ( - <> - - {data.title.highlighted}{" "} - - - {data.title.default} - - ) : ( - <> - {data.title.default}{" "} - - {data.title.highlighted} - - - - )} -

-
- {data.description} -
-
-
- -
- - {data.views?.map((it, index) => { - return ( - State.update({ selectedTab: index })} - selected={state.selectedTab === index} - > - {it.name} - - ); - })} - - -
-
- - - Made Possible by Collaboration - - - -
-); diff --git a/apps/devs.near/widget/component/card.jsx b/apps/devs.near/widget/component/card.jsx deleted file mode 100644 index 51e9423..0000000 --- a/apps/devs.near/widget/component/card.jsx +++ /dev/null @@ -1,221 +0,0 @@ -const [accountId, widget, widgetName] = props.src.split("/"); -const metadata = Social.get( - `${accountId}/widget/${widgetName}/metadata/**`, - "final" -); -const tags = Object.keys(metadata.tags || {}); -const detailsUrl = `#/near/widget/ComponentDetailsPage?src=${accountId}/widget/${widgetName}`; -const appUrl = `#/${accountId}/widget/${widgetName}`; -const accountUrl = `#/near/widget/ProfilePage?accountId=${accountId}`; - -const Card = styled.div` - position: relative; - width: 100%; - border-radius: 12px; - background: #fff; - border: 1px solid #eceef0; - box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1), - 0px 1px 2px rgba(16, 24, 40, 0.06); - overflow: hidden; -`; - -const CardBody = styled.div` - padding: 16px; - display: flex; - gap: 16px; - align-items: center; - - > * { - min-width: 0; - } -`; - -const CardContent = styled.div` - width: 100%; -`; - -const CardFooter = styled.div` - display: grid; - grid-template-columns: 1fr 1fr; - gap: 16px; - padding: 16px; - border-top: 1px solid #eceef0; -`; - -const StarButton = styled.div` - display: grid; - grid-template-columns: 1fr 1fr; - gap: 16px; - padding: 16px; -`; - -const CardTag = styled.p` - margin: 0; - font-size: 9px; - line-height: 14px; - background: #eceef0; - color: #687076; - font-weight: 400; - white-space: nowrap; - position: absolute; - top: 0; - right: 0; - border-bottom-left-radius: 3px; - padding: 0 4px; - - i { - margin-right: 3px; - } -`; - -const TextLink = styled.a` - display: block; - margin: 0; - font-size: 14px; - line-height: 18px; - color: ${(p) => (p.bold ? "#11181C !important" : "#687076 !important")}; - font-weight: ${(p) => (p.bold ? "600" : "400")}; - font-size: ${(p) => (p.small ? "12px" : "14px")}; - overflow: ${(p) => (p.ellipsis ? "hidden" : "visible")}; - text-overflow: ${(p) => (p.ellipsis ? "ellipsis" : "unset")}; - white-space: nowrap; - outline: none; - - &:focus, - &:hover { - text-decoration: underline; - } -`; - -const Text = styled.p` - margin: 0; - font-size: 14px; - line-height: 20px; - color: ${(p) => (p.bold ? "#11181C" : "#687076")}; - font-weight: ${(p) => (p.bold ? "600" : "400")}; - font-size: ${(p) => (p.small ? "12px" : "14px")}; - overflow: ${(p) => (p.ellipsis ? "hidden" : "")}; - text-overflow: ${(p) => (p.ellipsis ? "ellipsis" : "")}; - white-space: nowrap; - - i { - margin-right: 3px; - } -`; - -const Thumbnail = styled.a` - display: block; - width: 60px; - height: 60px; - flex-shrink: 0; - border: 1px solid #eceef0; - border-radius: 8px; - overflow: hidden; - outline: none; - transition: border-color 200ms; - - &:focus, - &:hover { - border-color: #d0d5dd; - } - - img { - object-fit: cover; - width: 100%; - height: 100%; - } -`; - -const TagsWrapper = styled.div` - position: relative; - margin-top: 4px; -`; - -const ButtonLink = styled.a` - padding: 8px; - height: 32px; - border: 1px solid #d7dbdf; - border-radius: 100px; - font-weight: 600; - font-size: 12px; - line-height: 15px; - text-align: center; - cursor: pointer; - color: ${(p) => (p.primary ? "#006ADC" : "#11181C")} !important; - background: #fbfcfd; - white-space: nowrap; - - &:hover, - &:focus { - background: #ecedee; - text-decoration: none; - outline: none; - } -`; - -return ( - - { - - {" "} - {" "} - ago - - } - - - - - - - - - {metadata.name || widgetName} - - - - @{accountId} - - - {tags.length > 0 && ( - - - - )} - - - - - - - - View Details - - Open - - - -); diff --git a/apps/devs.near/widget/components.jsx b/apps/devs.near/widget/components.jsx deleted file mode 100644 index 8c2665d..0000000 --- a/apps/devs.near/widget/components.jsx +++ /dev/null @@ -1,301 +0,0 @@ -const limitPerPage = 21; -let components = []; -let totalApps = 0; -let totalComponents = 0; -const componentsUrl = "#/near/widget/ComponentsPage"; -const searchRequiredTag = state.selectedTab === "apps" ? "app" : null; -const searchPlaceholder = - state.selectedTab === "apps" ? "Search Apps" : "Search Components"; - -State.init({ - currentPage: 0, - selectedTab: props.tab || "all", -}); - -if (props.tab && props.tab !== state.selectedTab) { - State.update({ - selectedTab: props.tab, - }); -} - -const tagsData = Social.get("*/widget/*/metadata/tags/*", "final"); - -const data = Social.keys("*/widget/*", "final", { - return_type: "BlockHeight", -}); - -if (data) { - const result = []; - - Object.keys(data).forEach((accountId) => { - return Object.keys(data[accountId].widget).forEach((widgetName) => { - totalComponents++; - - if (state.selectedTab === "apps") { - const hasAppTag = - tagsData[accountId].widget[widgetName]?.metadata?.tags["app"] === ""; - if (!hasAppTag) return; - totalApps++; - } - - result.push({ - accountId, - widgetName, - blockHeight: data[accountId].widget[widgetName], - }); - }); - }); - - result.sort((a, b) => b.blockHeight - a.blockHeight); - components = result.slice(0, state.currentPage * limitPerPage + limitPerPage); -} - -function onSearchChange({ result, term }) { - if (term.trim()) { - State.update({ searchResults: result || [] }); - } else { - State.update({ searchResults: null }); - } -} - -const items = state.searchResults || components; - -const Wrapper = styled.div` - display: flex; - flex-direction: column; - gap: 48px; - padding-bottom: 48px; - padding-top: 48px; -`; - -const Header = styled.div` - display: flex; - flex-direction: column; - gap: 12px; -`; - -const Search = styled.div` - width: 246px; - - @media (max-width: 500px) { - width: 100%; - } -`; - -const H1 = styled.h1` - font-weight: 600; - font-size: 32px; - line-height: 39px; - color: #11181c; - margin: 0; -`; - -const H2 = styled.h2` - font-weight: 400; - font-size: 20px; - line-height: 24px; - color: #687076; - margin: 0; -`; - -const Text = styled.p` - margin: 0; - line-height: 1.5rem; - color: ${(p) => (p.bold ? "#11181C" : "#687076")} !important; - font-weight: ${(p) => (p.bold ? "600" : "400")}; - font-size: ${(p) => (p.small ? "12px" : "14px")}; - overflow: ${(p) => (p.ellipsis ? "hidden" : "")}; - text-overflow: ${(p) => (p.ellipsis ? "ellipsis" : "")}; - white-space: ${(p) => (p.ellipsis ? "nowrap" : "")}; - overflow-wrap: anywhere; - - b { - font-weight: 600; - color: #11181c; - } - - &[href] { - display: inline-flex; - gap: 0.25rem; - - &:hover, - &:focus { - text-decoration: underline; - } - } -`; - -const Items = styled.div` - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 24px; - - @media (max-width: 1200px) { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - @media (max-width: 800px) { - grid-template-columns: minmax(0, 1fr); - } -`; - -const Item = styled.div``; - -const Button = styled.button` - display: block; - width: 100%; - padding: 8px; - height: 32px; - background: #fbfcfd; - border: 1px solid #d7dbdf; - border-radius: 50px; - font-weight: 600; - font-size: 12px; - line-height: 15px; - text-align: center; - cursor: pointer; - color: #11181c !important; - margin: 0; - - &:hover, - &:focus { - background: #ecedee; - text-decoration: none; - outline: none; - } - - span { - color: #687076 !important; - } -`; - -const Tabs = styled.div` - display: flex; - height: 48px; - border-bottom: 1px solid #eceef0; - margin-bottom: -24px; - overflow: auto; - scroll-behavior: smooth; - - @media (max-width: 1200px) { - background: #f8f9fa; - border-top: 1px solid #eceef0; - margin-left: -12px; - margin-right: -12px; - - > * { - flex: 1; - } - } -`; - -const TabsButton = styled.a` - display: inline-flex; - align-items: center; - justify-content: center; - height: 100%; - font-weight: 600; - font-size: 12px; - padding: 0 12px; - position: relative; - color: ${(p) => (p.selected ? "#11181C" : "#687076")}; - background: none; - border: none; - outline: none; - text-align: center; - text-decoration: none !important; - - &:hover { - color: #11181c; - } - - &::after { - content: ""; - display: ${(p) => (p.selected ? "block" : "none")}; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 3px; - background: #59e692; - } -`; - -return ( - -
- {state.selectedTab === "apps" && ( - <> -

{totalApps} Apps

-

Discover the latest apps from the NEAR community.

- - )} - - {state.selectedTab !== "apps" && ( - <> -

{totalComponents} Components

-

Discover the latest components from the NEAR community.

- - )} -
- - - - - - {!state.searchResults && ( - - - All - - - - Apps - - - )} - - {state.searchResults?.length === 0 && ( - No components matched your search. - )} - - {items.length > 0 && ( - - {items.map((component, i) => ( - - - - ))} - - )} - - {!state.searchResults && ( - - )} -
-); diff --git a/apps/devs.near/widget/create/posts.jsx b/apps/devs.near/widget/create/posts.jsx deleted file mode 100644 index 8740c58..0000000 --- a/apps/devs.near/widget/create/posts.jsx +++ /dev/null @@ -1,487 +0,0 @@ -const accountId = context.accountId; - -if (!accountId) { - return ""; -} - -const domains = props.domains; - -State.init({ - image: {}, - text: "", - showPreview: false, -}); - -const profile = Social.getr(`${context.accountId}/profile`); -const autocompleteEnabled = true; - -const content = { - type: "md", - image: state.image.cid ? { ipfs_cid: state.image.cid } : undefined, - text: state.text, -}; - -function extractMentions(text) { - const mentionRegex = - /@((?:(?:[a-z\d]+[-_])*[a-z\d]+\.)*(?:[a-z\d]+[-_])*[a-z\d]+)/gi; - mentionRegex.lastIndex = 0; - const accountIds = new Set(); - for (const match of text.matchAll(mentionRegex)) { - if ( - !/[\w`]/.test(match.input.charAt(match.index - 1)) && - !/[/\w`]/.test(match.input.charAt(match.index + match[0].length)) && - match[1].length >= 2 && - match[1].length <= 64 - ) { - accountIds.add(match[1].toLowerCase()); - } - } - return [...accountIds]; -} - -function extractTagNotifications(text, item) { - return extractMentions(text || "") - .filter((accountId) => accountId !== context.accountId) - .map((accountId) => ({ - key: accountId, - value: { - type: "mention", - item, - }, - })); -} - -const extractHashtags = (text) => { - const hashtagRegex = /#(\w+)/gi; - hashtagRegex.lastIndex = 0; - const hashtags = new Set(); - for (const match of text.matchAll(hashtagRegex)) { - if ( - !/[\w`]/.test(match.input.charAt(match.index - 1)) && - !/[/\w`]/.test(match.input.charAt(match.index + match[0].length)) - ) { - hashtags.add(match[1].toLowerCase()); - } - } - return [...hashtags]; -}; - -function composeData() { - const data = { - post: { - main: JSON.stringify(content), - }, - index: {}, - }; - - const hashtags = extractHashtags(content.text); - /** - * If domains have been provided, then we create an index under that "domain" - * Otherwise, we post to the catch-all "post" domain - */ - if (state.choose && state.choose.length > 0) { - state.choose.map((it) => { - data.index[it] = JSON.stringify({ - key: "main", - value: { - type: "md", - }, - }); - if (hashtags.length) { - data.index.hashtag = JSON.stringify( - hashtags.map((hashtag) => ({ - key: hashtag, - value: { - type: "social", - path: `${context.accountId}/${it}/main`, - }, - })) - ); - } - }); - } else { - data.index.post = JSON.stringify({ - key: "main", - value: { - type: "md", - }, - }); - if (hashtags.length) { - data.index.hashtag = JSON.stringify( - hashtags.map((hashtag) => ({ - key: hashtag, - value: { - type: "social", - path: `${context.accountId}/post/main`, - }, - })) - ); - } - } - - const notifications = extractTagNotifications(state.text, { - type: "social", - path: `${context.accountId}/post/main`, - }); - - if (notifications.length) { - data.index.notify = JSON.stringify( - notifications.length > 1 ? notifications : notifications[0] - ); - } - - return data; -} - -function onCommit() { - State.update({ - image: {}, - text: "", - }); -} - -function textareaInputHandler(value) { - const showAccountAutocomplete = /@[\w][^\s]*$/.test(value); - State.update({ text: value, showAccountAutocomplete }); -} - -function autoCompleteAccountId(id) { - let text = state.text.replace(/[\s]{0,1}@[^\s]*$/, ""); - text = `${text} @${id}`.trim() + " "; - State.update({ text, showAccountAutocomplete: false }); -} - -const Wrapper = styled.div` - --padding: 24px; - position: relative; - - @media (max-width: 1200px) { - --padding: 12px; - } -`; - -const Avatar = styled.div` - width: 40px; - height: 40px; - pointer-events: none; - position: absolute; - top: var(--padding); - left: var(--padding); - - img { - object-fit: cover; - border-radius: 40px; - width: 100%; - height: 100%; - } - - @media (max-width: 992px) { - display: none; - } -`; - -const Textarea = styled.div` - display: grid; - vertical-align: top; - align-items: center; - position: relative; - align-items: stretch; - - &::after, - textarea { - width: 100%; - min-width: 1em; - height: unset; - min-height: 164px; - font: inherit; - padding: var(--padding) var(--padding) calc(40px + (var(--padding) * 2)) - calc(40px + (var(--padding) * 2)); - margin: 0; - resize: none; - background: none; - appearance: none; - border: none; - grid-area: 1 / 1; - overflow: hidden; - outline: none; - - @media (max-width: 1200px) { - min-height: 124px; - } - - @media (max-width: 992px) { - padding-left: var(--padding); - } - } - - &::after { - content: attr(data-value) " "; - visibility: hidden; - white-space: pre-wrap; - } - - textarea { - transition: all 200ms; - - &::placeholder { - opacity: 1; - color: #687076; - } - - &:empty + p { - display: block; - } - - &:focus { - box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.05); - } - } -`; - -const TextareaDescription = styled.p` - position: absolute; - top: calc(var(--padding) + 24px); - left: calc(42px + (var(--padding) * 2)); - right: var(--padding); - font-size: 10px; - line-height: 18px; - font-weight: 400; - color: #687076; - pointer-events: none; - display: none; - - a { - color: #000; - outline: none; - font-weight: 600; - pointer-events: auto; - - &:hover, - &:focus { - color: #000; - text-decoration: underline; - } - } - - @media (max-width: 992px) { - left: var(--padding); - } -`; - -const Actions = styled.div` - display: inline-flex; - gap: 12px; - position: absolute; - bottom: var(--padding); - right: var(--padding); - - .commit-post-button, - .preview-post-button { - background: #59e692; - color: #09342e; - border-radius: 40px; - height: 40px; - padding: 0 35px; - font-weight: 600; - font-size: 14px; - border: none; - cursor: pointer; - transition: background 200ms, opacity 200ms; - - &:hover, - &:focus { - background: rgb(112 242 164); - outline: none; - } - - &:disabled { - opacity: 0.5; - pointer-events: none; - } - } - - .preview-post-button { - color: #11181c; - background: #f1f3f5; - padding: 0; - width: 40px; - - &:hover, - &:focus { - background: #d7dbde; - outline: none; - } - } - - .upload-image-button { - display: flex; - align-items: center; - justify-content: center; - background: #f1f3f5; - color: #11181c; - border-radius: 40px; - height: 40px; - min-width: 40px; - font-size: 0; - border: none; - cursor: pointer; - transition: background 200ms, opacity 200ms; - - &::before { - font-size: 16px; - } - - &:hover, - &:focus { - background: #d7dbde; - outline: none; - } - - &:disabled { - opacity: 0.5; - pointer-events: none; - } - - span { - margin-left: 12px; - } - } - - .d-inline-block { - display: flex !important; - gap: 12px; - margin: 0 !important; - - .overflow-hidden { - width: 40px !important; - height: 40px !important; - } - } -`; - -const PreviewWrapper = styled.div` - position: relative; - padding: var(--padding); - padding-bottom: calc(40px + (var(--padding) * 2)); -`; - -const AutoComplete = styled.div` - position: absolute; - z-index: 5; - bottom: 0; - left: 0; - right: 0; - - > div > div { - padding: calc(var(--padding) / 2); - } -`; - -return ( - - {state.showPreview ? ( - - - - ) : ( - <> - - - - - - - )} - - {autocompleteEnabled && state.showAccountAutocomplete && ( - - State.update({ showAccountAutocomplete: false }), - }} - /> - - )} - - - {!state.showPreview && ( - - )} - - - {domains && ( - { - State.update({ choose: value }); - }} - placeholder="domains" - /> - )} - - publish - - - -); diff --git a/apps/devs.near/widget/dao/connect.jsx b/apps/devs.near/widget/dao/connect.jsx deleted file mode 100644 index cb3ffae..0000000 --- a/apps/devs.near/widget/dao/connect.jsx +++ /dev/null @@ -1,97 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const daoId = props.daoId ?? "multi.sputnik-dao.near"; - -const policy = Near.view(daoId, "get_policy"); - -if (policy === null) { - return ""; -} - -const deposit = policy.proposal_bond; - -const followEdge = Social.keys( - `${accountId}/graph/follow/${daoId}`, - undefined, - { - values_only: true, - } -); - -const inverseEdge = Social.keys( - `${daoId}/graph/follow/${accountId}`, - undefined, - { - values_only: true, - } -); - -const loading = followEdge === null || inverseEdge === null; -const isFollowing = Object.keys(followEdge || {}).length > 0; -const isInverse = Object.keys(inverseEdge || {}).length > 0; - -const type = follow ? "unfollow" : "follow"; - -const follow_args = JSON.stringify({ - data: { - [daoId]: { - graph: { - follow: { - [accountId]: "", - }, - }, - index: { - graph: { - key: follow, - value: { - type: follow, - accountId: [accountId], - }, - }, - notify: { - key: [accountId], - value: { - type: follow, - }, - }, - }, - }, - }, -}); - -const proposal_args = Buffer.from(follow_args, "utf-8").toString("base64"); - -const handleProposal = () => { - Near.call([ - { - contractName: daoId, - methodName: "add_proposal", - args: { - proposal: { - description: "connection request", - kind: { - FunctionCall: { - receiver_id: "social.near", - actions: [ - { - method_name: "set", - args: proposal_args, - deposit: "80000000000000000000000", - gas: "219000000000000", - }, - ], - }, - }, - }, - }, - deposit: deposit, - gas: "219000000000000", - }, - ]); -}; - -return ( - -); diff --git a/apps/devs.near/widget/dbos.jsx b/apps/devs.near/widget/dbos.jsx deleted file mode 100644 index 0bc1dde..0000000 --- a/apps/devs.near/widget/dbos.jsx +++ /dev/null @@ -1,130 +0,0 @@ -const curatorId = props.accountId ?? context.accountId ?? "hack.near"; -const curationId = props.curationId ?? "dbos"; -const curationType = props.curationType ?? "projects"; - -const path = `${curatorId}/curation/${curationId}/${curationType}`; -const init = Social.get(path, "optimistic", { - subscribe: true, -}); - -State.init({ - curatorId, - curationId, - curationType, - things: JSON.parse(init) ?? [], - newThing: "", -}); - -const isCurator = state.curatorId === context.accountId; - -function addThing(newThing) { - state.things.push(newThing); - - State.update({ - things: state.things, - }); -} - -function removeThing(thingKey) { - const updatedThings = state.things.filter((thing) => thing !== thingKey); - - State.update({ - things: updatedThings, - }); -} - -const handleSave = () => { - const data = { - curation: { - [state.curationId]: { - [state.curationType]: state.things, - }, - }, - }; - - Social.set(data, { - onCommit: () => {}, - onCancel: () => {}, - }); -}; - -const items = things ? JSON.parse(things) : []; - -return ( -
-

Curation

-

{state.curationId}

- State.update({ curationId: e.target.value })} - /> -

- Who: {state.curatorId} -

- State.update({ curatorId: e.target.value })} - /> -

- What: {state.curationType} -

- State.update({ curatorType: e.target.value })} - /> -
-
- {isCurator ? ( -

update list

- ) : ( -

propose changes

- )} - State.update({ newThing: e.target.value })} - /> -
- - {Object.keys(state.things).length > 0 && ( -
- {JSON.stringify(things) !== JSON.stringify(state.things) && ( - - )} -
- )} -
-
-
- {state.things.length ? ( -
- {state.things.map((thing, i) => { - const [creatorId, type, thingId] = thing.split("/"); - return ( -
-

{thing}

-
- -
- ); - })} -
- ) : ( -
- nothing found -
- )} -
-
-); diff --git a/apps/devs.near/widget/dev/Rank.jsx b/apps/devs.near/widget/dev/Rank.jsx deleted file mode 100644 index 6ffdfec..0000000 --- a/apps/devs.near/widget/dev/Rank.jsx +++ /dev/null @@ -1,85 +0,0 @@ -const ownerId = props.ownerId ?? "devs.near"; -const accountWidgetCount = []; - -let accounts = Social.keys(`${ownerId}/graph/follow/*`, "final", { - return_type: "BlockHeight", - values_only: true, -}); - -if (accounts === null) { - return "Loading..."; -} - -accounts = Object.entries(accounts[ownerId].graph.follow || {}); -accounts.sort((a, b) => b[1] - a[1]); - -for (let i = 0; i < accounts.length; ++i) { - let accountId = accounts[i][0]; - let widgets = Social.get(`${accountId}/widget/*`, "final", { - return_type: "BlockHeight", - values_only: true, - }); - let widgetCount = 0; - if (widgets) { - widgetCount = Object.keys(widgets).length; - } - accountWidgetCount.push({ - accountId: accountId, - count: widgetCount, - }); -} - -const accountWidgetSort = accountWidgetCount.sort((a, b) => b.count - a.count); -const numAccounts = accountWidgetSort.length; -accountWidgetSort = accountWidgetSort.slice(0, limit); -console.log(accountWidgetSort); - -const totalWidgetCount = accountWidgetCount.reduce( - (sum, account) => sum + account.count, - 0 -); - -return ( - <> -

Builders

-
Total Widgets: {totalWidgetCount}
{" "} - {accountWidgetCount.map((rank, index) => { - let accountId = rank.accountId; - return ( -
-
- -
-
-
- Rank: - - {index + 1} - -
-
- Widgets:{" "} - - {rank.count} - -
-
-
- -
-
- ); - })} - -); diff --git a/apps/devs.near/widget/dev/collab.jsx b/apps/devs.near/widget/dev/collab.jsx deleted file mode 100644 index 2db6659..0000000 --- a/apps/devs.near/widget/dev/collab.jsx +++ /dev/null @@ -1,74 +0,0 @@ -const accountId = "devs.near"; - -let following = Social.keys(`${accountId}/graph/follow/*`, "final", { - return_type: "BlockHeight", - values_only: true, -}); - -if (following === null) { - return "Loading"; -} - -following = Object.entries(following[accountId].graph.follow || {}); -following.sort((a, b) => b[1] - a[1]); - -return ( -
-
Connect
-
- State.update({ profiles: result }), - }} - /> -
- {state.profiles && state.profiles.length > 0 && ( -
- {state.profiles.map(({ accountId }, i) => ( -
-
- - - -
-
- -
-
- ))} -
-
- )} - {following.map(([accountId], i) => ( - - - - ))} -
-); diff --git a/apps/devs.near/widget/dev/community.jsx b/apps/devs.near/widget/dev/community.jsx deleted file mode 100644 index e427cc0..0000000 --- a/apps/devs.near/widget/dev/community.jsx +++ /dev/null @@ -1,239 +0,0 @@ -const ownerId = props.ownerId ?? "devs.near"; -const accountId = props.accountId ?? context.accountId; -const daoId = props.daoId ?? "build.sputnik-dao.near"; -const role = props.role ?? "community"; - -let isBuilder = false; -let widgets = Social.get(`${accountId}/widget/*`, "final", { - return_type: "BlockHeight", - values_only: true, -}); -let widgetCount = 0; -if (widgets) { - widgetCount = Object.keys(widgets).length; -} -if (widgetCount > 0) { - isBuilder = true; -} - -const handleJoin = () => { - const gas = 200000000000000; - const deposit = 100000000000000000000000; - Near.call([ - { - contractName: daoId, - methodName: "add_proposal", - args: { - proposal: { - description: "potential member", - kind: { - AddMemberToRole: { - member_id: accountId, - role: role, - }, - }, - }, - }, - gas: gas, - deposit: deposit, - }, - ]); -}; - -const Wrapper = styled.div` - --section-gap: 23px; - padding-top: 42px; - - @media (max-width: 1155px) { - .line-rounded-corners { - display: none !important; - } - } - - @media (max-width: 998px) { - padding-top: 0; - } -`; - -const H1 = styled.h1` - font-family: "FK Grotesk", sans-serif; - font-style: normal; - font-weight: 500; - font-size: 90px; - line-height: 1; - text-align: center; - letter-spacing: -0.03em; - color: #000; - margin: 0; - max-width: 700px; - - span { - display: inline-block; - background: #6ce89f; - border-radius: 20px; - position: relative; - padding: 0.1em 0.2em 0; - - svg { - position: absolute; - bottom: -8px; - right: -10px; - width: 24px; - } - } - - @media (max-width: 900px) { - font-size: 50px; - - span { - border-radius: 12px; - svg { - position: absolute; - bottom: -6px; - right: -7px; - width: 16px; - } - } - } -`; - -const Text = styled.p` - font-family: "FK Grotesk", sans-serif; - font-size: ${(p) => p.size ?? "18px"}; - line-height: ${(p) => p.lineHeight ?? "1.5"}; - font-weight: ${(p) => p.weight ?? "400"}; - color: ${(p) => p.color ?? "#000"}; - margin-botton: 8px; -`; - -const Flex = styled.div` - display: flex; - gap: 8px; - align-items: center; - flex-direction: column; - flex-wrap: "nowrap"; - - @media (max-width: 998px) { - flex-direction: column; - gap: var(--section-gap); - } -`; - -const FlexContainer = styled.div` - display: flex; - gap: 8px; - align-items: center; - flex-direction: row; - justify-content: center; - flex-wrap: wrap; - - @media (max-width: 998px) { - flex-direction: column; - gap: var(--section-gap); - } -`; - -const Container = styled.div` - display: flex; - max-width: 1080px; - margin: 0 auto; - gap: var(--section-gap); - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - padding: var(--section-gap) 24px; -`; - -return ( - - - -

- - BOS{" "} - - - Builders -

-
- - Did you know? The - - blockchain operating system - - (BOS) makes it fun and easy to create anything! Join groups, - discover projects, and collaborate out loud. Everyone is building a - more open web that is greater than the sum of its components. - -
-
- {isBuilder ? ( -
- - Your Adventure Has Begun - - -
- -
-
-
- ) : ( - - - Begin a New Adventure - - -
- -
-
-
- )} -
-
- - -
-
- - - Made Possible by Collaboration - - - -
-); diff --git a/apps/devs.near/widget/dev/config.jsx b/apps/devs.near/widget/dev/config.jsx deleted file mode 100644 index 8780b8e..0000000 --- a/apps/devs.near/widget/dev/config.jsx +++ /dev/null @@ -1,287 +0,0 @@ -const path = - props.path || `${props.accountId || context.accountId}/settings/**`; -const blockHeight = props.blockHeight || "final"; - -if (accountId === null) { - return

Please connect a NEAR account...

; -} - -const settings = Social.get(path, blockHeight); - -if (!settings) { - return

Loading...

; -} - -const FormContainer = styled.div` - width: 500px; - margin: 0 auto; -`; - -const SectionTitle = styled.h2` - font-size: 24px; - margin-top: 20px; -`; - -const SectionContainer = styled.div` - border: 1px solid #ccc; - padding: 10px; - margin-bottom: 20px; -`; - -const FormGroup = styled.div` - margin-bottom: 10px; -`; - -const Label = styled.label` - display: block; - margin-bottom: 5px; - font-size: 18px; -`; - -const InputContainer = styled.div` - display: flex; - align-items: center; -`; - -const Input = styled.input` - width: 100%; - padding: 8px; -`; - -const Button = styled.button` - margin-left: 5px; -`; - -State.init({ - formData: settings, - modifiedInputs: {}, -}); - -function composeData(section) { - const modifiedData = Object.entries(state.modifiedInputs).reduce( - (result, [key, value]) => { - const [currentSection, currentKey] = key.split("/"); - if (currentSection === section && value) { - const [_, index] = currentKey.split("/"); - const parsedIndex = parseInt(index, 10); - if (Number.isInteger(parsedIndex)) { - if (!result[currentSection]) { - result[currentSection] = {}; - } - if (!result[currentSection][currentKey]) { - result[currentSection][currentKey] = []; - } - result[currentSection][currentKey][parsedIndex] = - state.formData[currentSection][currentKey][parsedIndex]; - } else { - if (!result[currentSection]) { - result[currentSection] = {}; - } - result[currentSection][currentKey] = - state.formData[currentSection][currentKey]; - } - } - return result; - }, - {} - ); - return modifiedData; -} - -const handleInputChange = (section, key, index, value) => { - const updatedData = { ...state.formData }; - const modifiedInputs = { ...state.modifiedInputs }; - - if (Array.isArray(JSON.parse(updatedData[section][key]))) { - try { - const inputs = JSON.parse(updatedData[section][key]); - const originalValue = JSON.parse(settings[section][key]); - - inputs[index].src = value; - updatedData[section][key] = JSON.stringify(inputs); - - modifiedInputs[`${section}/${key}/${index}`] = - inputs[index].src !== originalValue[index].src; - - State.update({ formData: updatedData, modifiedInputs }); - } catch (error) { - console.log( - `Error updating input value for ${section}/${key}/${index}:`, - error - ); - } - } else { - const originalValue = settings[section][key]; - updatedData[section][key] = value; - - modifiedInputs[`${section}/${key}/0`] = - updatedData[section][key] !== originalValue; - - State.update({ formData: updatedData, modifiedInputs }); - } -}; -const moveInputUp = (section, key, index) => { - const updatedData = { ...state.formData }; - const modifiedInputs = { ...state.modifiedInputs }; - - try { - const inputs = JSON.parse(updatedData[section][key]); - - if (index > 0) { - const temp = inputs[index]; - inputs[index] = inputs[index - 1]; - inputs[index - 1] = temp; - - const currentModifiedKey = `${section}/${key}/${index}`; - const previousModifiedKey = `${section}/${key}/${index - 1}`; - - // Check if the current input value matches the original value - const originalValue = JSON.parse(settings[section][key]); - const isCurrentInputModified = - inputs[index].src !== originalValue[index].src; - const isPreviousInputModified = - inputs[index - 1].src !== originalValue[index - 1].src; - - modifiedInputs[currentModifiedKey] = isCurrentInputModified; - modifiedInputs[previousModifiedKey] = isPreviousInputModified; - - // Remove modified flag if the inputs match the original values - if (!isCurrentInputModified) { - delete modifiedInputs[currentModifiedKey]; - } - if (!isPreviousInputModified) { - delete modifiedInputs[previousModifiedKey]; - } - - updatedData[section][key] = JSON.stringify(inputs); - - State.update({ formData: updatedData, modifiedInputs }); - } - } catch (error) { - console.log(`Error moving input up for ${section}/${key}/${index}:`, error); - } -}; - -const moveInputDown = (section, key, index) => { - const updatedData = { ...state.formData }; - const modifiedInputs = { ...state.modifiedInputs }; - - try { - const inputs = JSON.parse(updatedData[section][key]); - - if (index < inputs.length - 1) { - const temp = inputs[index]; - inputs[index] = inputs[index + 1]; - inputs[index + 1] = temp; - - const currentModifiedKey = `${section}/${key}/${index}`; - const nextModifiedKey = `${section}/${key}/${index + 1}`; - - // Check if the current input value matches the original value - const originalValue = JSON.parse(settings[section][key]); - const isCurrentInputModified = - inputs[index].src !== originalValue[index].src; - const isNextInputModified = - inputs[index + 1].src !== originalValue[index + 1].src; - - modifiedInputs[currentModifiedKey] = isCurrentInputModified; - modifiedInputs[nextModifiedKey] = isNextInputModified; - - // Remove modified flag if the inputs match the original values - if (!isCurrentInputModified) { - delete modifiedInputs[currentModifiedKey]; - } - if (!isNextInputModified) { - delete modifiedInputs[nextModifiedKey]; - } - - updatedData[section][key] = JSON.stringify(inputs); - - State.update({ formData: updatedData, modifiedInputs }); - } - } catch (error) { - console.log( - `Error moving input down for ${section}/${key}/${index}:`, - error - ); - } -}; - -return ( - -

settings

- {Object.entries(state.formData).map(([section, values]) => ( - - {section} - {Object.entries(values).map(([key, input]) => { - let parsedInput = JSON.parse(input); - if (parsedInput === null) { - parsedInput = input; - } - return ( - - - {Array.isArray(parsedInput) ? ( - parsedInput.map((item, index) => { - return ( - - - handleInputChange(section, key, index, e.target.value) - } - /> - - - - ); - }) - ) : ( - - - handleInputChange(section, key, 0, e.target.value) - } - /> - - )} - - ); - })} - composeData(section)} - disabled={!Object.keys(composeData(section)).length} - className="styless" - > - save - - - ))} -
-); diff --git a/apps/devs.near/widget/dev/feed.jsx b/apps/devs.near/widget/dev/feed.jsx deleted file mode 100644 index 9fd165a..0000000 --- a/apps/devs.near/widget/dev/feed.jsx +++ /dev/null @@ -1,134 +0,0 @@ -const accountId = props.accountId; -const tag = props.tag; - -const makeLink = (accountId, tag) => { - const args = []; - if (accountId) { - args.push(`accountId=${accountId}`); - } - if (tag) { - args.push(`tag=${tag}`); - } - return `#/mob.near/widget/LastWidgets${args.length > 0 ? "?" : ""}${args.join( - "&" - )}`; -}; - -const render = (content) => { - return ( -
-

Latest Widgets

- {(accountId || tag) && ( -
- Filter: - {accountId && ( - - - - - )} - {tag && ( - - #{tag} - - - )} -
- )} - {content} -
- ); -}; - -let keys = `${accountId ?? "*"}/widget/*`; - -if (tag) { - const taggedWidgets = Social.keys( - `${accountId ?? "*"}/widget/*/metadata/tags/${tag}`, - "final" - ); - - if (taggedWidgets === null) { - return render("Loading tags..."); - } - - keys = Object.entries(taggedWidgets) - .map((kv) => Object.keys(kv[1].widget).map((w) => `${kv[0]}/widget/${w}`)) - .flat(); - - if (!keys.length) { - return render(`No widgets found by tag #${tag}`); - } -} - -const data = Social.keys(keys, "final", { - return_type: "BlockHeight", -}); - -if (data === null) { - return render("Loading..."); -} - -const processData = (data) => { - const accounts = Object.entries(data); - - const allItems = accounts - .map((account) => { - const accountId = account[0]; - return Object.entries(account[1].widget).map((kv) => ({ - accountId, - widgetName: kv[0], - blockHeight: kv[1], - })); - }) - .flat(); - - allItems.sort((a, b) => b.blockHeight - a.blockHeight); - return allItems; -}; - -const renderTag = (tag, tagBadge) => ( - {tagBadge} -); - -const renderItem = (a) => { - return ( -
- -
- ); -}; - -console.log(data); - -if (JSON.stringify(data) !== JSON.stringify(state.data || {})) { - State.update({ - data, - allItems: processData(data), - }); -} - -return render( - -); diff --git a/apps/devs.near/widget/dev/info.jsx b/apps/devs.near/widget/dev/info.jsx deleted file mode 100644 index 21d9494..0000000 --- a/apps/devs.near/widget/dev/info.jsx +++ /dev/null @@ -1,93 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const daoId = props.daoId ?? "build.sputnik-dao.near"; -const role = props.role ?? "community"; - -let isBuilder = false; -let widgets = Social.get(`${accountId}/widget/*`, "final", { - return_type: "BlockHeight", - values_only: true, -}); -let widgetCount = 0; -if (widgets) { - widgetCount = Object.keys(widgets).length; -} -if (widgetCount > 0) { - isBuilder = true; -} - -const policy = Near.view(daoId, "get_policy"); - -if (policy === null) { - return ""; -} - -const groups = policy.roles - .filter((role) => role.name === "community") - .map((role) => { - const group = role.kind.Group; - - return group; - }); - -const isMember = groups.map((group) => { - return !group - ? false - : group.filter((address) => address === accountId).length > 0; -})?.[0]; - -return ( - -); diff --git a/apps/devs.near/widget/dev/library.jsx b/apps/devs.near/widget/dev/library.jsx deleted file mode 100644 index e42cbdb..0000000 --- a/apps/devs.near/widget/dev/library.jsx +++ /dev/null @@ -1,284 +0,0 @@ -const ownerId = "hack.near"; -const curatedComps = [ - { - category: "Learn", - id: "concepts", - icon: "bi-mortarboard-fill", - components: [ - { - accountId: "hack.near", - widgetName: "edu.library", - }, - ], - }, - { - category: "Quickstart", - icon: "bi-rocket-takeoff-fill", - id: "quickstart", - components: [ - { - accountId: "gagdiez.near", - widgetName: "Greeter", - }, - ], - }, - { - category: "Discover", - icon: "bi-stars", - id: "social", - components: [ - { - accountId: "mob.near", - widgetName: "Explorer", - }, - { - accountId: "efiz.near", - widgetName: "Tree", - }, - { - accountId: "every.near", - widgetName: "browser", - }, - ], - }, - { - category: "Examples", - id: "examples", - icon: "bi-map-fill", - components: [ - { - accountId: "gagdiez.near", - widgetName: "HelloNear", - }, - { - accountId: "ostolex.near", - widgetName: "DiceWidgetDemo", - }, - { - accountId: "dorgon108.near", - widgetName: "TypeAheadExample", - }, - { - accountId: "mob.near", - widgetName: "MarkdownEditorIframe", - }, - ], - }, - { - category: "Tools", - id: "tools", - icon: "bi-tools", - components: [ - { accountId: "hack.near", widgetName: "docs.cli" }, - { accountId: "mob.near", widgetName: "Explorer" }, - { accountId: "dataplatform.near", widgetName: "QueryApi.App" }, - { accountId: "bozon.near", widgetName: "WidgetHistory" }, - { accountId: "hack.near", widgetName: "GitBos" }, - { accountId: "azbang.near", widgetName: "CallbackEditor" }, - ], - }, - { - category: "Standards", - id: "standards", - icon: "bi-rulers", - components: [ - { - accountId: "mob.near", - widgetName: "MetadataEditor", - }, - { - accountId: "efiz.near", - widgetName: "every.post", - }, - { - accountId: "efiz.near", - widgetName: "every.post.view", - }, - { - accountId: "near", - widgetName: "FollowButton", - }, - { - accountId: "mob.near", - widgetName: "Welcome.RHS.Editor", - }, - { - accountId: "mob.near", - widgetName: "WidgetSource", - }, - { - accountId: "mob.near", - widgetName: "IndexFeed", - }, - { - accountId: "mob.near", - widgetName: "Image", - }, - { - accountId: "manzanal.near", - widgetName: "Badge", - }, - ], - }, -]; -const filterTag = props.commonComponentTag ?? "edu"; -const debug = props.debug ?? false; - -const searchComponents = () => { - return ( -
-
- { - State.update({ apps: result }); - }, - }} - /> -
- {state.apps && ( -
- {state.apps.map((app, i) => ( -
- State.update({ apps: null }), - extraButtons: ({ widgetPath }) => ( - - Source - - ), - }} - /> -
- ))} -
- )} -
- ); -}; - -const renderCategory = (categoryId) => { - if (!categoryId || categoryId === "") return <>; - const item = curatedComps.find((i) => i.id == categoryId); - return ( -
-
- {item.category} -
-
-
-
- {item.components.map((comp, i) => ( -
- -
- ))} -
-
-
- ); -}; -State.init({ - tab: "home", - id: "", -}); - -const renderHome = () => { - return ( - <> - {searchComponents()} - -
-

Resources

-
- {curatedComps && ( -
- {curatedComps.map((cat, i) => renderCategory(cat.id))} -
- )} -
-
- - ); -}; - -const onSelect = (selection) => { - State.update({ tab: selection.tab, id: selection.id ? selection.id : "" }); -}; - -const renderContent = { - home: renderHome(), - searchComponents: searchComponents(), - category: renderCategory(state.id), -}[state.tab]; - -return ( - <> -
-
- ({ - category: i.category, - icon: i.icon, - id: i.id, - })), - }} - /> -
- -
-
-
-
-

- #docs -

-
-
- - - -
-
-

- Everyone can build the blockchain operating system together! -

- {renderContent} -
-
- -); diff --git a/apps/devs.near/widget/dev/main.jsx b/apps/devs.near/widget/dev/main.jsx deleted file mode 100644 index c1bd9e1..0000000 --- a/apps/devs.near/widget/dev/main.jsx +++ /dev/null @@ -1,62 +0,0 @@ -const hashtag = props.hashtag ?? "dev"; - -const defaultWidgets = [ - { - src: "devs.near/widget/dev.menu", - }, - { - src: "devs.near/widget/dev.search", - }, - { - src: "devs.near/widget/explore.posts", - }, -]; - -const widgets = (main && JSON.parse(main)) ?? defaultWidgets; - -const Div = styled.div` - position: relative; - @media (hover: hover) { - > .edit-link { - display: none; - } - } - &:hover { - > .edit-link { - display: inline; - } - } -`; - -return ( -
-
- - {context.accountId && ( - - Edit Page - - )} -
-
- {widgets.map( - ({ src, requiresLogin }, i) => - (!requiresLogin || context.accountId) && ( -
- -
- ) - )} -
-
-); diff --git a/apps/devs.near/widget/dev/main/config.jsx b/apps/devs.near/widget/dev/main/config.jsx deleted file mode 100644 index b745ff0..0000000 --- a/apps/devs.near/widget/dev/main/config.jsx +++ /dev/null @@ -1,147 +0,0 @@ -const accountId = context.accountId; - -const main = context.accountId - ? Social.get(`${context.accountId}/settings/dev/main`) - : undefined; - -if (main === null) { - return ""; -} - -const defaultWidgets = [ - { - src: "devs.near/widget/dev.menu", - }, - { - src: "devs.near/widget/dev.search", - }, - { - src: "devs.near/widget/explore.posts", - }, -]; - -const settingWidgets = main && JSON.parse(main); - -if (state.widgets === undefined) { - const widgets = settingWidgets ?? defaultWidgets; - State.update({ widgets }); -} - -const move = (fromIndex, toIndex) => { - const widget = state.widgets.splice(fromIndex, 1)[0]; - if (toIndex !== undefined) { - state.widgets.splice(toIndex, 0, widget); - } - State.update(); -}; - -const renderPage = (src, requireLogin, index) => { - return ( -
-
{src}
- - - - - -
- ); -}; - -const openButton = ({ widgetPath: src, onHide }) => { - return ( - - ); -}; - -return ( - <> -

Main Page Editor

-
- -
-
- - Save Changes - - {settingWidgets && - JSON.stringify(state.widgets) !== JSON.stringify(settingWidgets) && ( - - )} - {JSON.stringify(state.widgets) !== JSON.stringify(defaultWidgets) && ( - - )} -
-
- {state.widgets.map(({ src, requiresLogin }, i) => ( -
- {renderPage(src, requireLogin, i)} -
- -
-
- ))} - -); diff --git a/apps/devs.near/widget/dev/menu.jsx b/apps/devs.near/widget/dev/menu.jsx deleted file mode 100644 index 81c10d4..0000000 --- a/apps/devs.near/widget/dev/menu.jsx +++ /dev/null @@ -1,49 +0,0 @@ -return ( -
- -
-); diff --git a/apps/devs.near/widget/dev/posts.jsx b/apps/devs.near/widget/dev/posts.jsx deleted file mode 100644 index 4935d9a..0000000 --- a/apps/devs.near/widget/dev/posts.jsx +++ /dev/null @@ -1,54 +0,0 @@ -const accountId = context.accountId; -const daoId = "build.sputnik-dao.near"; -const groupId = props.groupId ?? "community"; - -const policy = Near.view(daoId, "get_policy"); - -if (policy === null) { - return ""; -} - -const groups = policy.roles - .filter((role) => role.name === groupId) - .map((role) => { - const group = role.kind.Group; - - return group; - }); - -const isMember = groups.map((group) => { - return !group - ? false - : group.filter((address) => address === accountId).length > 0; -})?.[1]; - -const hashtags = [ - { name: "dev", required: true }, - { name: "bos", required: true }, -]; -return ( - <> -

{group}

- - - -); diff --git a/apps/devs.near/widget/dev/profile.jsx b/apps/devs.near/widget/dev/profile.jsx deleted file mode 100644 index 8737428..0000000 --- a/apps/devs.near/widget/dev/profile.jsx +++ /dev/null @@ -1,44 +0,0 @@ -const accountId = props.accountId ?? context.accountId ?? "devs.near"; - -const profile = props.profile ?? Social.getr(`${accountId}/profile`); - -const name = profile.name; -const description = profile.description; -const tags = Object.keys(profile.tags ?? {}); - -return ( -
- -
-
- {name}{" "} - - @{accountId} - -
-
- {tags.length > 0 && ( - <> - {tags.map((tag, i) => ( - - #{tag} - - ))} - - )} -
-
-
-); diff --git a/apps/devs.near/widget/dev/search.jsx b/apps/devs.near/widget/dev/search.jsx deleted file mode 100644 index 5665d17..0000000 --- a/apps/devs.near/widget/dev/search.jsx +++ /dev/null @@ -1,49 +0,0 @@ -return ( -
-

apps

-
- { - State.update({ apps: result }); - }, - }} - /> -
- {state.apps && ( -
- {state.apps.map((app, i) => ( -
- State.update({ apps: null }), - extraButtons: ({ widgetPath }) => ( - - Source - - ), - }} - /> -
- ))} -
- )} - - -
-); diff --git a/apps/devs.near/widget/dev/side.jsx b/apps/devs.near/widget/dev/side.jsx deleted file mode 100644 index 8732446..0000000 --- a/apps/devs.near/widget/dev/side.jsx +++ /dev/null @@ -1,62 +0,0 @@ -const side = context.accountId - ? Social.get(`${context.accountId}/settings/dev/side`) - : undefined; - -if (side === null) { - return ""; -} - -const defaultWidgets = [ - { - src: "devs.near/widget/dev.info", - }, - { - src: "devs.near/widget/dev.profile", - }, - { - src: "devs.near/widget/dev.collab", - }, -]; - -const widgets = (side && JSON.parse(side)) ?? defaultWidgets; - -const Div = styled.div` - position: relative; - @media (hover: hover) { - > .edit-link { - display: none; - } - } - &:hover { - > .edit-link { - display: inline; - } - } -`; - -return ( -
-
-
Welcome!
- {context.accountId && ( - - Customize - - )} -
-
- {widgets.map( - ({ src, requiresLogin }, i) => - (!requiresLogin || context.accountId) && ( -
- -
- ) - )} -
-
-); diff --git a/apps/devs.near/widget/dev/side/config.jsx b/apps/devs.near/widget/dev/side/config.jsx deleted file mode 100644 index 5202a36..0000000 --- a/apps/devs.near/widget/dev/side/config.jsx +++ /dev/null @@ -1,147 +0,0 @@ -const accountId = context.accountId; - -const side = context.accountId - ? Social.get(`${context.accountId}/settings/dev/side`) - : undefined; - -if (side === null) { - return ""; -} - -const defaultWidgets = [ - { - src: "devs.near/widget/dev.info", - }, - { - src: "devs.near/widget/dev.profile", - }, - { - src: "devs.near/widget/dev.collab", - }, -]; - -const settingWidgets = side && JSON.parse(side); - -if (state.widgets === undefined) { - const widgets = settingWidgets ?? defaultWidgets; - State.update({ widgets }); -} - -const move = (fromIndex, toIndex) => { - const widget = state.widgets.splice(fromIndex, 1)[0]; - if (toIndex !== undefined) { - state.widgets.splice(toIndex, 0, widget); - } - State.update(); -}; - -const renderMenu = (src, requireLogin, index) => { - return ( -
-
{src}
- - - - - -
- ); -}; - -const openButton = ({ widgetPath: src, onHide }) => { - return ( - - ); -}; - -return ( - <> -

Dev Sidebar Editor

-
- -
-
- - Save Changes - - {settingWidgets && - JSON.stringify(state.widgets) !== JSON.stringify(settingWidgets) && ( - - )} - {JSON.stringify(state.widgets) !== JSON.stringify(defaultWidgets) && ( - - )} -
-
- {state.widgets.map(({ src, requiresLogin }, i) => ( -
- {renderMenu(src, requireLogin, i)} -
- -
-
- ))} - -); diff --git a/apps/devs.near/widget/dev/social.jsx b/apps/devs.near/widget/dev/social.jsx deleted file mode 100644 index e0d64da..0000000 --- a/apps/devs.near/widget/dev/social.jsx +++ /dev/null @@ -1,63 +0,0 @@ -const hashtags = [ - { name: "dev", required: true }, - { name: "bos", required: true }, -]; - -return ( - -); - - -
  • - -
  • - -
    -
    - -
    -
    - -
    -
    - -); diff --git a/apps/devs.near/widget/dev/tabs.jsx b/apps/devs.near/widget/dev/tabs.jsx deleted file mode 100644 index 4b1c940..0000000 --- a/apps/devs.near/widget/dev/tabs.jsx +++ /dev/null @@ -1,138 +0,0 @@ -State.init({ - selectedTab: props.tab || "leaderboard", -}); - -const accountId = props.accountId ?? context.accountId; -const daoId = props.daoId ?? "build.sputnik-dao.near"; - -if (props.tab && props.tab !== state.selectedTab) { - State.update({ - selectedTab: props.tab, - }); -} - -const accountUrl = `devs.near/widget/dev.community`; - -const Wrapper = styled.div` - padding-bottom: 48px; -`; - -const Title = styled.h1` - font-weight: 600; - font-size: ${(p) => p.size || "25px"}; - line-height: 1.2em; - color: #11181c; - margin: ${(p) => (p.margin ? "0 0 24px" : "0")}; - overflow-wrap: anywhere; -`; - -const Tabs = styled.div` - display: flex; - height: 48px; - border-bottom: 1px solid #eceef0; - margin-bottom: 72px; - overflow: auto; - scroll-behavior: smooth; - justify-content: center; - - @media (max-width: 1200px) { - background: #f8f9fa; - border-top: 1px solid #eceef0; - margin: 0 -12px 48px; - - > * { - flex: 1; - } - } -`; - -const TabsButton = styled.a` - display: inline-flex; - align-items: center; - justify-content: center; - height: 100%; - font-weight: 600; - font-size: 23px; - padding: 0 12px; - position: relative; - color: ${(p) => (p.selected ? "#11181C" : "#687076")}; - background: none; - border: none; - outline: none; - text-align: center; - text-decoration: none !important; - - &:hover { - color: #11181c; - cursor: pointer; - } - - &::after { - content: ""; - display: ${(p) => (p.selected ? "block" : "none")}; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 3px; - background: #59e692; - } -`; - -const handleTabClick = (tab) => { - State.update({ - selectedTab: tab, - }); -}; - -return ( - - - handleTabClick("leaderboard")} - selected={state.selectedTab === "leaderboard"} - > - Leaderboard - - - handleTabClick("questions")} - selected={state.selectedTab === "questions"} - > - Questions - - - handleTabClick("members")} - selected={state.selectedTab === "members"} - > - Members - - - handleTabClick("tasks")} - selected={state.selectedTab === "tasks"} - > - Tasks - - - - {state.selectedTab === "leaderboard" && ( - <> - - - )} - - {state.selectedTab === "questions" && ( - - )} - - {state.selectedTab === "members" && ( - - )} - - {state.selectedTab === "tasks" && ( - - )} - -); diff --git a/apps/devs.near/widget/devs/Rank.jsx b/apps/devs.near/widget/devs/Rank.jsx deleted file mode 100644 index de0a474..0000000 --- a/apps/devs.near/widget/devs/Rank.jsx +++ /dev/null @@ -1,69 +0,0 @@ -const accountWidgetCount = []; -const data = Social.keys("*/profile", "final"); -if (!data) { - return "Loading..."; -} -let accounts = Object.entries(data); -const limit = 888; - -for (let i = 0; i < accounts.length; ++i) { - let accountId = accounts[i][0]; - let widgets = Social.get(`${accountId}/widget/*`, "final", { - return_type: "BlockHeight", - values_only: true, - }); - if (widgets) { - accountWidgetCount.push({ - accountId: accountId, - count: Object.keys(widgets).length, - }); - } -} -const accountWidgetSort = accountWidgetCount.sort((a, b) => b.count - a.count); -const numAccounts = accountWidgetSort.length; -accountWidgetSort = accountWidgetSort.slice(0, limit); -console.log(accountWidgetSort); - -return ( - <> -

    Top Widget Builders

    - {accountWidgetSort.map((rank, index) => { - let accountId = rank.accountId; - return ( -
    -
    - -
    -
    -
    - Rank: - - {index + 1} - -
    -
    - Widgets:{" "} - - {rank.count} - -
    -
    -
    - -
    -
    - ); - })} - -); diff --git a/apps/devs.near/widget/docs/view.jsx b/apps/devs.near/widget/docs/view.jsx deleted file mode 100644 index 5fd3a76..0000000 --- a/apps/devs.near/widget/docs/view.jsx +++ /dev/null @@ -1,18 +0,0 @@ -const content = fetch( - `https://raw.githubusercontent.com/${ - props.path ?? - "near-everything/bos-workspace/teleport/docs/teleport/README.md" - }` -); -if (content === null) return ""; - -return ( -
    - -
    -); diff --git a/apps/devs.near/widget/every/feed/view.jsx b/apps/devs.near/widget/every/feed/view.jsx deleted file mode 100644 index bc470bb..0000000 --- a/apps/devs.near/widget/every/feed/view.jsx +++ /dev/null @@ -1,52 +0,0 @@ -const data = props.data; -const typeWhitelist = JSON.stringify(data.typeWhitelist); -const key = data.key; -const domain = data.domain; -const hashtagFilter = JSON.stringify(data.hashtagFilter); -const daoId = data.daoId; - -// Since we know the typeWhitelist, we could prefetch widgets -// and maybe write out a switch case? -// -// Or match with the name pattern? every.thing - -if ( - typeWhitelist === JSON.stringify(["md", "social", "every.near/type/markdown"]) -) { - return ( - <> - -

    {daoId}

    - - - ); -} else { - return ( - <> - - - - ); -} diff --git a/apps/devs.near/widget/every/group.jsx b/apps/devs.near/widget/every/group.jsx deleted file mode 100644 index 2364507..0000000 --- a/apps/devs.near/widget/every/group.jsx +++ /dev/null @@ -1,228 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const groupId = props.groupId ?? "f8ad9d1a76259lmdpjnd74e69162a0a014"; -const creatorId = props.creatorId ?? "hack.near"; - -const widgets = { - group: "devs.near/widget/group.card", - create: "devs.near/widget/group.create", - edit: "devs.near/widget/group.edit", -}; - -// We get all of the groups that have been indexed -const groups = Social.index("every", "group", { limit: 10 }); - -// TODO: We can put an infinite scroll for groups -// And then we could do a Social.get([...groups]) constructed from each index - -if (!groups) { - return ""; -} - -// we check if they are a member ? Do we need this here? -// Ohhhh you join everyone -const isMember = Social.keys( - `${accountId}/graph/${groupId}/${accountId}`, - undefined, - { - values_only: true, - } -); - -const type = join ? "leave" : "join"; - -const handleJoin = () => { - Social.set({ - graph: { [groupId]: { [accountId]: "" } }, - index: { - graph: JSON.stringify({ - key: groupId, - value: { - type, - accountId, - }, - }), - notify: JSON.stringify({ - key: creatorId, // in that case, who should the creator be? - value: { - type, - accountId, - message: "everyone is growing!", - }, - }), - }, - }); -}; - -const Container = styled.div` - padding: 23px 0; - margin: 0; - - .top-right { - display: flex; - align-items: center; - justify-content: flex-end; - } - - .bell-icon { - font-size: 23px; - color: #fff; - margin-left: 5px; - text-decoration: none; - transition: color 0.3s ease-in-out; - } - - .bell-icon:hover { - color: #fff; - } - - .bell-icon .bi-bell { - display: inline; - } - - .bell-icon .bi-bell-fill { - display: none; - } - - .bell-icon:hover .bi-bell { - display: none; - } - - .bell-icon:hover .bi-bell-fill { - display: inline; - } -`; - -const Header = styled.div` - background: black; - - .large-text { - font-size: 19px; - font-weight: 555; - } -`; - -const Navbar = styled.div` - margin-left: 20px; - @media only screen and (max-width: 1061px) { - margin: 10px 0 0 0; - } -`; - -const Center = styled.div` - display: flex; - justify-content: space-between; - gap: 20px; - align-items: flex-start; -`; - -const GroupCard = styled.div` - flex-basis: calc(33.33% - 20px); - margin: 0; -`; - -const Grid = styled.div` - display: grid; - grid-template-columns: repeat(3, 1fr); - grid-gap: 10px; - - @media (hover: none) { - grid-template-columns: repeat(1, 1fr); - } -`; - -const { Feed } = VM.require("efiz.near/widget/Module.Feed"); -Feed = Feed || (() => <>); - -return ( - <> - -
    - - - -
    - -
    - - {/* What's the purpose of this? */} - {true ? ( - - ) : ( - - )} - -
    -
    -

    Discover Groups

    -
    - { - return - }} - Layout={Grid} - /> -
    -
    -
    - {state.showModal && ( - State.update({ showModal: false }), - }} - /> - )} - {state.showModalEdit && ( - State.update({ showModalEdit: false }), - }} - /> - )} - -); diff --git a/apps/devs.near/widget/everything/sdk.jsx b/apps/devs.near/widget/everything/sdk.jsx deleted file mode 100644 index 5dac94d..0000000 --- a/apps/devs.near/widget/everything/sdk.jsx +++ /dev/null @@ -1,239 +0,0 @@ -const isPrimitiveType = (type) => - ["string", "number", "boolean", "date", "md"].includes(type); - -const isComplexType = (type) => - Array.isArray(type) - ? "typesArray" // I don't know if we still need to handle this - : type === "array" - ? "array" - : typeof type === "object" - ? "object" - : typeof type === "string" && !isPrimitiveType(type) - ? "custom" - : null; - -const getDefaultForPrimitive = (type, defaultValue) => { - if (defaultValue !== undefined) { - return defaultValue; - } - switch (type) { - case "string": - return ""; - case "number": - return null; // should this be 0? - case "boolean": - return null; // do we want this to be false? - case "date": - return null; // do we want this to be today? - case "md": - return null; - } -}; - -const typeToEmptyData = (typeDef) => { - const obj = {}; - - Object.keys(typeDef.properties).forEach((key) => { - const fieldSchema = typeDef.properties[key]; - const type = fieldSchema.type; - - if (isPrimitiveType(type)) { - obj[key] = getDefaultForPrimitive(type, fieldSchema.defaultValue); - } else if (isComplexType(type) === "array") { - obj[key] = fieldSchema.defaultValue ? [...fieldSchema.defaultValue] : []; - } else if (isComplexType(type) === "object") { - obj[key] = typeToEmptyData({ properties: type.properties }); - } else { - console.log("edge case not handled for type: " + type); - obj[key] = fieldSchema.defaultValue ?? null; - } - }); - - return obj; -}; - -function checkProps(props, typeDef, prefix) { - if (!prefix) { - prefix = ""; - } - const missingProps = []; - - for (const [key, value] of Object.entries(typeDef.properties)) { - const fullKey = prefix ? `${prefix}.${key}` : key; - - if (!props.hasOwnProperty(key)) { - missingProps.push(`${fullKey}`); - continue; - } - - const propValue = props[key]; - - if (value.type === "object" && value.properties) { - missingProps.push(...checkProps(propValue, value, fullKey)); - } - - if (value.validation && value.validation.required && propValue == null) { - missingProps.push(`${fullKey} (required)`); - } - } - - return missingProps; -} - -function MissingPropsWarning({ props, typeDef, WarningElement }) { - const missingProps = checkProps(props, typeDef); - return ( - missingProps.length > 0 && ( - <> - {WarningElement ? ( - - ) : ( -
    -
    -

    Attention!

    -
    -
    -

    - {`There ${missingProps.length === 1 ? "is" : "are"} ${ - missingProps.length - } missing or invalid prop${ - missingProps.length === 1 ? "" : "s" - }:`} -

    -
      - {missingProps.map((prop) => ( -
    • -
      {prop}
      -
    • - ))} -
    -
    -
    - )} - - ) - ); -} - -/*__@import:everything/utils/UUID__*/ - -function filterByType(data, targetType) { - return Object.keys(data || {}).reduce((result, key) => { - if (data[key].metadata?.type === targetType) { - result[key] = data[key]; - } - return result; - }, {}); -} - -function deepMerge(obj1, obj2) { - return Object.keys({ ...obj1, ...obj2 }).reduce((acc, key) => { - if ( - obj1[key] && - obj2[key] && - typeof obj1[key] === "object" && - typeof obj2[key] === "object" - ) { - acc[key] = deepMerge(obj1[key], obj2[key]); - } else { - acc[key] = obj2[key] !== undefined ? obj2[key] : obj1[key]; - } - return acc; - }, {}); -} - -/** - * Gets all things of a given type, optionally filtered by accounts and blockHeight - * @param {string} type - type of thing to filter by - * @param {Array} [accounts] - Optional list of accounts to filter by - * @param {string|number} blockHeight - Optional blockHeight to use; defaults to "final" - * @returns {object} - all things of the given type - */ -function getAllThings(type, accounts, blockHeight) { - let paths; - if (!blockHeight) { - blockHeight = "final"; - } - - if (Array.isArray(accounts) && accounts.length) { - // We could change this to get all metadata, metadata includes type - // and then we have all we need in order to show on screens. Anything else can be fetched separately. - paths = accounts.map((account) => `${account}/thing/*/metadata/*`); - } else { - paths = ["*/thing/*/metadata/*"]; - } - const things = Social.get(paths, blockHeight); - return filterByType(things, type) ?? {}; -} - -/** - * Gets the thing matching id, optionally filtered by accounts and blockHeight - * @param {string} id - thing id - * @param {Array} [accountIds] - Optional list of accounts to filter by. If not provided, defaults to any account. - * @param {string|number} blockHeight - Optional blockHeight to use; defaults to "final" - * @returns {object|null} - the thing, multiple things if matches id across accounts, or null if not found - */ -function getThing(id, accountIds, blockHeight) { - let paths; - if (!blockHeight) { - blockHeight = "final"; - } - - if (Array.isArray(accountIds) && accountIds.length) { - paths = accountIds.map((accountId) => `${accountId}/thing/${id}/**`); - } else { - paths = [`*/thing/${id}/**`]; - } - - const thing = Social.get(paths, blockHeight) || {}; - - return thing; -} - -function deleteThing(id) { - Social.set({ - thing: { - [id]: null, - }, - }); -} - -/** - * Creates a thing with the given type, data, and metadata - * Subsequently calls onCommit or onCancel - * @param {string} type - type of thing to create - * @param {object} data - data to store - * @param {object} metadata - metadata to store - */ -function createThing(type, data, metadata) { - // Temporary small id - const id = UUID.generate("xxxxxxx"); - return { - [id]: { - // I think there may be some value in stringify-ing the data and storing in empty key, but I'm not sure - // Maybe it's for published data? Data that has no relations? - // It's more space efficient for the social contract if we limit the number of keys - "": JSON.stringify(data), - data, // so I'm just gonna do both for right now :) - metadata: { ...metadata, type }, - }, - }; -} - -return { - filterByType, - getThing, - getAllThings, - deepMerge, - deleteThing, - createThing, - isPrimitiveType, - isComplexType, - getDefaultForPrimative, - typeToEmptyData, - checkProps, - MissingPropsWarning, -}; diff --git a/apps/devs.near/widget/explore/posts.jsx b/apps/devs.near/widget/explore/posts.jsx deleted file mode 100644 index 0013bac..0000000 --- a/apps/devs.near/widget/explore/posts.jsx +++ /dev/null @@ -1,191 +0,0 @@ -State.init({ - selectedTab: Storage.privateGet("selectedTab") || "all", -}); - -const domains = ["dev", "gov", "edu", "art", "fun"]; - -const hashtags = ["near", "bos"]; - -const previousSelectedTab = Storage.privateGet("selectedTab"); - -if (previousSelectedTab && previousSelectedTab !== state.selectedTab) { - State.update({ - selectedTab: previousSelectedTab, - }); -} - -let accounts = undefined; - -if (state.selectedTab === "following" && context.accountId) { - const graph = Social.keys(`${context.accountId}/graph/follow/*`, "final"); - if (graph !== null) { - accounts = Object.keys(graph[context.accountId].graph.follow || {}); - accounts.push(context.accountId); - } else { - accounts = []; - } -} else { - accounts = undefined; -} - -function selectTab(selectedTab) { - Storage.privateSet("selectedTab", selectedTab); - State.update({ selectedTab }); -} - -const H2 = styled.h2` - font-size: 19px; - line-height: 22px; - color: #11181c; - margin: 0 0 24px; - padding: 0 24px; - - @media (max-width: 1200px) { - display: none; - } -`; - -const Content = styled.div` - @media (max-width: 1200px) { - > div:first-child { - border-top: none; - } - } -`; - -const ComposeWrapper = styled.div` - border-top: 1px solid #eceef0; -`; - -const FilterWrapper = styled.div` - border-top: 1px solid #eceef0; - padding: 24px 24px 0; - display: flex; - flex-direction: row; - justify-content: space-between; - - @media (max-width: 1200px) { - padding: 12px; - } -`; - -const PillSelect = styled.div` - display: inline-flex; - align-items: center; - - @media (max-width: 600px) { - width: 100%; - - button { - flex: 1; - } - } -`; - -const PillSelectButton = styled.button` - display: block; - position: relative; - border: 1px solid #e6e8eb; - border-right: none; - padding: 3px 24px; - border-radius: 0; - font-size: 12px; - line-height: 18px; - color: ${(p) => (p.selected ? "#fff" : "#687076")}; - background: ${(p) => (p.selected ? "#006ADC !important" : "#FBFCFD")}; - font-weight: 600; - transition: all 200ms; - - &:hover { - background: #ecedee; - text-decoration: none; - } - - &:focus { - outline: none; - border-color: #006adc !important; - box-shadow: 0 0 0 1px #006adc; - z-index: 5; - } - - &:first-child { - border-radius: 6px 0 0 6px; - } - &:last-child { - border-radius: 0 6px 6px 0; - border-right: 1px solid #e6e8eb; - } -`; - -const FeedWrapper = styled.div` - .post { - padding-left: 24px; - padding-right: 24px; - - @media (max-width: 1200px) { - padding-left: 12px; - padding-right: 12px; - } - } -`; - -return ( - <> - -

    create

    - {context.accountId && ( - <> - - - -

    explore

    - - - - selectTab("all")} - selected={state.selectedTab === "all"} - > - all - - - selectTab("following")} - selected={state.selectedTab === "following"} - > - following - - -
    - { - State.update({ hashtags: value }); - }} - placeholder="hashtag filter" - /> - { - State.update({ choose: value }); - }} - placeholder="domain filter" - /> -
    -
    - - )} - - - - -
    - -); diff --git a/apps/devs.near/widget/group.jsx b/apps/devs.near/widget/group.jsx deleted file mode 100644 index 24f4cf2..0000000 --- a/apps/devs.near/widget/group.jsx +++ /dev/null @@ -1,29 +0,0 @@ -const groupId = props.groupId ?? "526fb256e74eelmf0nw3n5909bc189c13d"; -const creatorId = props.creatorId ?? "*"; - -const group = - props.group ?? Social.get(`${creatorId}/*/${groupId}/**`, "final"); - -if (!group) { - return ""; -} - -const Container = styled.div` - background: #fbfbfb; - padding: 23px; -`; - -return ( - -
    -
    -
    -

    Members

    - -
    -
    -
    -); \ No newline at end of file diff --git a/apps/devs.near/widget/group/card.jsx b/apps/devs.near/widget/group/card.jsx deleted file mode 100644 index 30d7079..0000000 --- a/apps/devs.near/widget/group/card.jsx +++ /dev/null @@ -1,148 +0,0 @@ -const creatorId = props.creatorId; -const groupId = props.groupId; - -const groupInfo = Social.get( - `${creatorId}/thing/${groupId}/metadata/**`, - "final" -); - -if (!groupInfo) { - return "group details not found"; -} - -const canJoin = props.canJoin ?? true; - -const Card = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - gap: 16px; - width: 100%; - border-radius: 12px; - background: #fff; - border: 1px solid #eceef0; - box-shadow: - 0px 1px 3px rgba(16, 24, 40, 0.1), - 0px 1px 2px rgba(16, 24, 40, 0.06); - overflow: hidden; - padding: 16px; -`; - -const Bell = styled.div` - .bell { - display: flex; - align-items: center; - justify-content: flex-end; - } - - .bell-icon { - font-size: 23px; - color: #000; - margin-left: 5px; - text-decoration: none; - transition: color 0.3s ease-in-out; - } - - .bell-icon:hover { - color: #000; - } - - .bell-icon .bi-bell { - display: inline; - } - - .bell-icon .bi-bell-fill { - display: none; - } - - .bell-icon:hover .bi-bell { - display: none; - } - - .bell-icon:hover .bi-bell-fill { - display: inline; - } -`; - -const CardLeft = styled.div` - display: flex; - gap: 16px; - align-items: center; - width: 100%; - min-width: 0; - - > div { - display: flex; - flex-direction: column; - width: 100%; - min-width: 0; - } -`; - -const TextLink = styled.a` - display: block; - margin: 0; - font-size: 14px; - line-height: 18px; - color: ${(p) => (p.bold ? "#11181C !important" : "#687076 !important")}; - font-weight: ${(p) => (p.bold ? "600" : "400")}; - font-size: ${(p) => (p.small ? "12px" : "14px")}; - overflow: ${(p) => (p.ellipsis ? "hidden" : "visible")}; - text-overflow: ${(p) => (p.ellipsis ? "ellipsis" : "unset")}; - white-space: nowrap; - outline: none; - - &:focus, - &:hover { - text-decoration: underline; - } -`; - -const TagsWrapper = styled.div` - padding-top: 4px; -`; - -return ( - - - - - - - -
    - -
    -
    - {canJoin && context.accountId && ( - <> - {groupKey === context.accountId && ( - - edit - - )} - - - )} -
    -); diff --git a/apps/devs.near/widget/group/create.jsx b/apps/devs.near/widget/group/create.jsx deleted file mode 100644 index 77be826..0000000 --- a/apps/devs.near/widget/group/create.jsx +++ /dev/null @@ -1,310 +0,0 @@ -const creatorId = props.creatorId ?? context.accountId; - -const { handleClose } = props; - -function generateUID() { - return ( - Math.random().toString(16).slice(2) + - Date.now().toString(36) + - Math.random().toString(16).slice(2) - ); -} - -const groupId = props.groupId ?? generateUID(); - -State.init({ - group, - members: { [creatorId]: "" }, - newMember: "", - isDao: false, -}); - -function addMember(newMember) { - State.update({ - members: { ...state.members, [newMember]: "" }, - }); -} - -function removeMember(memberKey) { - const updatedMembers = { ...state.members }; - delete updatedMembers[memberKey]; - - State.update({ - members: updatedMembers, - }); -} - -function isNearAddress(address) { - if (typeof address !== "string") { - return false; - } - if (!address.endsWith(".near")) { - return false; - } - const parts = address.split("."); - if (parts.length !== 2) { - return false; - } - if (parts[0].length < 2 || parts[0].length > 32) { - return false; - } - if (!/^[a-z0-9_-]+$/i.test(parts[0])) { - return false; - } - return true; -} - -const memberId = props.memberId ?? state.newMember; - -const isValid = isNearAddress(memberId); - -const CardStyled = styled.div` - width: 100%; - height: 100%; - background: #f8f8f9; - gap: 10px; - padding: 25px; - margin: 0 auto; - border-radius: 10px; - overflow-y: scroll; -`; - -const CardForm = styled.div` - display: flex; - flex-direction: column; - width: 100%; - height: auto; -`; - -const H1 = styled.h1` - margin-bottom: 10px; - font-style: normal; - font-weight: 555; - font-size: 23px; -`; - -const Submitcontainer = styled.div` - display: flex; - justify-content: flex-end; - align-items: center; - gap: 8px; - margin-bottom: 16px; - @media only screen and (max-width: 480px) { - margin-top: 10px; - } -`; - -const Modal = styled.div` - position: fixed; - z-index: 1; - left: 0; - top: 0; - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; - background: rgba(0, 0, 0, 0.7); -`; - -const ComponentWrapper = styled.div` - display: flex; - width: 80%; - height: 80%; - flex-direction: column; - align-items: flex-start; - border-radius: 10px; - background: #fff; - border: 1px solid transparent; - margin: 140px auto auto auto; - @media only screen and (max-width: 480px) { - width: 90%; - } -`; - -const Hr = styled.div` - height: 1px; - margin: 15px 0; - width: 100%; - background: rgba(208, 214, 217, 0.4); -`; - -const Section = styled.div` - margin: 12px 0; -`; - -const handleCreate = () => { - const data = { - thing: { - [groupId]: { - "": JSON.stringify(state.group), - metadata: { - ...state.group, - type: { - group: { - src: "every.near/type/group", - blockHeight: "final", - }, - }, - }, - }, - }, - graph: { - [groupId]: { - ...state.members, - }, - }, - index: { - every: JSON.stringify({ - key: "group", - value: { - id: groupId, - }, - }), - graph: JSON.stringify( - Object.keys(state.members).map((account) => ({ - key: groupId, - value: { - type: "add", - accountId: account, - }, - })) - ), - }, - }; - const notify = Object.keys(state.members).filter( - (it) => it !== context.accountId - ); - if (notify.length > 0) { - data.index.notify = JSON.stringify( - notify.map((account) => ({ - key: account, - value: { - type: "add", - }, - })) - ); - } - Social.set(data); -}; - -return ( - - - -
    - -
    -

    New Group

    - - - - -
    -
    -
    -
    -
    Details
    -
    - State.update({ group }), - options: { - name: { label: "Name" }, - image: { label: "Logo" }, - backgroundImage: { label: "Background" }, - description: { label: "About" }, - tags: { - label: "Tags", - tagsPattern: `*/${groupId}/tags/*`, - placeholder: - "art, gov, edu, dev, com, nft, ai, social", - }, - linktree: { - links: [ - { - label: "Twitter", - prefix: "https://twitter.com/", - name: "twitter", - }, - { - label: "Github", - prefix: "https://github.com/", - name: "github", - }, - { - label: "Telegram", - prefix: "https://t.me/", - name: "telegram", - }, - { - label: "Website", - prefix: "https://", - name: "website", - }, - ], - }, - }, - }} - /> -
    -
    -
    -
    Members
    -
    - Account ID - - State.update({ newMember: e.target.value }) - } - /> -
    - -
    -
    -
    -
    -
    Preview
    - {Object.keys(state.members).map((a) => { - return ( -
    -
    - -
    - -
    - ); - })} -
    -
    -
    -
    -
    -
    -
    -
    -); diff --git a/apps/devs.near/widget/group/edit.jsx b/apps/devs.near/widget/group/edit.jsx deleted file mode 100644 index 45adfbf..0000000 --- a/apps/devs.near/widget/group/edit.jsx +++ /dev/null @@ -1,228 +0,0 @@ -const { handleClose } = props; - -const creatorId = props.creatorId ?? context.accountId; - -if (!creatorId) { - return "Please connect your NEAR account :)"; -} - -const groupId = props.groupId ?? "526fb256e74eelmf0nw3n5909bc189c13d"; - -const groupData = - props.group ?? Social.get(`${creatorId}/thing/${groupId}/**`, "final"); - -if (!groupData) { - return ""; -} - -const groupKey = Object.keys(groupData)[0]; - -const initMembers = - props.members ?? Social.get(`${creatorId}/graph/${groupId}/**`, "final"); - -if (!initMembers) { - return ""; -} - -State.init({ - group: groupData, - members: initMembers, - newMember: "", - isDao: false, -}); - -function addMember(newMember) { - State.update({ - members: { ...state.members, [newMember]: "" }, - }); -} - -function removeMember(memberKey) { - const updatedMembers = { ...state.members }; - delete updatedMembers[memberKey]; - - State.update({ - members: updatedMembers, - }); -} - -function isNearAddress(address) { - if (typeof address !== "string") { - return false; - } - if (!address.endsWith(".near")) { - return false; - } - const parts = address.split("."); - if (parts.length !== 2) { - return false; - } - if (parts[0].length < 2 || parts[0].length > 32) { - return false; - } - if (!/^[a-z0-9_-]+$/i.test(parts[0])) { - return false; - } - return true; -} - -const memberId = props.memberId ?? state.newMember; - -const isValid = isNearAddress(memberId); - -const handleSave = () => { - Social.set({ - thing: { - [groupId]: { - "": JSON.stringify(state.group), - metadata: { - ...state.group, - type: { - group: { - src: "every.near/type/group", - blockHeight: "final", - }, - }, - }, - }, - }, - - graph: { - [groupId]: { - ...state.members, - }, - }, - index: { - every: JSON.stringify({ - key: "group", - value: { - id: groupId, - }, - }), - graph: JSON.stringify( - Object.keys(state.members).map((account) => ({ - key: groupId, - value: { - type: "add", - accountId: account, - }, - })) - ), - notify: JSON.stringify( - Object.keys(state.members) - .filter((it) => initMembers.includes(it)) - .map((account) => ({ - key: account, - value: { - type: "add", - }, - })) - ), - }, - }); -}; - -return ( - <> -

    {JSON.stringify(group)}

    - {groupData && ( -
    -
    -
    Details
    - -
    - State.update({ group }), - options: { - name: { - label: "Name", - placeholder: `${group[groupKey].thing[groupId].metadata.name}`, - }, - image: { label: "Logo" }, - description: { label: "About" }, - tags: { - label: "Tags", - tagsPattern: `*/${groupId}/tags/*`, - placeholder: "art, gov, edu, dev, com, nft, ai, social", - }, - linktree: { - links: [ - { - label: "Twitter", - prefix: "https://twitter.com/", - name: "twitter", - }, - { - label: "Github", - prefix: "https://github.com/", - name: "github", - }, - { - label: "Telegram", - prefix: "https://t.me/", - name: "telegram", - }, - { - label: "Website", - prefix: "https://", - name: "website", - }, - ], - }, - }, - }} - /> -
    -
    -
    -
    Members
    -
    - Account ID - State.update({ newMember: e.target.value })} - /> -
    - - -
    -
    -
    - {Object.keys(state.members).map((a) => { - return ( -
    -
    - -
    - -
    - ); - })} -
    -
    -
    - )} - -); diff --git a/apps/devs.near/widget/group/image.jsx b/apps/devs.near/widget/group/image.jsx deleted file mode 100644 index 7c375a5..0000000 --- a/apps/devs.near/widget/group/image.jsx +++ /dev/null @@ -1,45 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const groupId = props.groupId ?? "526fb256e74eelmf0nw3n5909bc189c13d"; - -const className = props.className ?? "group-image d-inline-block"; -const style = props.style ?? { width: "3em", height: "3em" }; -const imageStyle = props.imageStyle ?? { objectFit: "cover" }; -const imageClassName = props.imageClassName ?? "rounded w-100 h-100"; -const thumbnail = props.thumbnail ?? "thumbnail"; - -const group = props.group; - -const name = group.name || "No-name group"; -const image = group.image; -const title = props.title ?? `${name} @${accountId}`; -const tooltip = - props.tooltip && (props.tooltip === true ? title : props.tooltip); -const fallbackUrl = - "https://ipfs.near.social/ipfs/bafkreibmiy4ozblcgv3fm3gc6q62s55em33vconbavfd2ekkuliznaq3zm"; - -const inner = ( -
    - -
    -); - -return props.tooltip ? ( - <> - - -) : ( - inner -); \ No newline at end of file diff --git a/apps/devs.near/widget/group/index.jsx b/apps/devs.near/widget/group/index.jsx deleted file mode 100644 index a15cd55..0000000 --- a/apps/devs.near/widget/group/index.jsx +++ /dev/null @@ -1,109 +0,0 @@ -const groupId = props.groupId ?? "526fb256e74eelmf0nw3n5909bc189c13d"; - -const updates = Social.index("graph", `${groupId}`, { - limit: 10, - order: "desc", - subscribe: true, -}); - -const index = { - action: "graph", - key: groupId, - options: { - limit: 10, - order: "desc", - }, -}; - -const ItemWrapper = styled.div` - margin-bottom: 12px; -`; - -State.init({ - showDetails: false, -}); - -const renderItem = (item) => { - function NotificationButton({ item }) { - switch (item.value.type) { - case "add": { - return ( -
    - {context.accountId === item.value.accountId && ( // Context check? - - )} -
    - ); - } - case "join": { - return ( -
    - {item.accountId !== context.accountId && ( - - )} -
    - ); - } - case "create": { - return ( -
    - -
    - ); - } - } - } - - return ( - -
    -
    -
    -
    - -
    -
    - {item.value.type === "add" && `added`} - -
    -
    - -
    -
    -
    - -
    -
    - ); -}; - -return ( -
    - -
    -); diff --git a/apps/devs.near/widget/group/info.jsx b/apps/devs.near/widget/group/info.jsx deleted file mode 100644 index 117ace5..0000000 --- a/apps/devs.near/widget/group/info.jsx +++ /dev/null @@ -1,38 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const groupId = props.groupId ?? "526fb256e74eelmf0nw3n5909bc189c13d"; -const creatorId = props.creatorId ?? "devs.near"; - -const groupData = - props.groupData ?? Social.get(`${accountId}/thing/${groupId}/metadata/**`); - -const groupName = groupData["name"]; -const image = group.image; - -return ( - -); \ No newline at end of file diff --git a/apps/devs.near/widget/group/inline.jsx b/apps/devs.near/widget/group/inline.jsx deleted file mode 100644 index 15f3b20..0000000 --- a/apps/devs.near/widget/group/inline.jsx +++ /dev/null @@ -1,61 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const groupId = props.groupId ?? "526fb256e74eelmf0nw3n5909bc189c13d"; - -const group = - props.group ?? Social.get(`${accountId}/thing/${groupId}/metadata/**`); - -const name = group.name; -const description = group.description; -const tags = Object.keys(group.tags ?? {}); - -const Tag = styled.a` - color: black; - text-decoration: none; - - &:hover { - color: blue; - text-decoration: none; - } -`; - - -return ( -
    - -
    -
    - - {group.name} - -
    -
    - {tags.length > 0 && ( - <> - {tags.map((tag, i) => ( - - - #{tag} - - - ))} - - )} -
    -
    -
    -); diff --git a/apps/devs.near/widget/group/join.jsx b/apps/devs.near/widget/group/join.jsx deleted file mode 100644 index d24325a..0000000 --- a/apps/devs.near/widget/group/join.jsx +++ /dev/null @@ -1,67 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const groupId = props.groupId ?? "f8ad9d1a76259lmdpjnd74e69162a0a014"; -const creatorId = props.creatorId ?? "hack.near"; - -if (!props.accountId && !context.accountId) { - return ""; -} - -const joinEdge = Social.keys( - `${context.accountId}/graph/${groupId}/${context.accountId}`, - undefined, - { - values_only: true, - } -); - -const memberEdge = Social.keys( - `${creatorId}/graph/${groupId}/${context.accountId}`, - undefined, - { - values_only: true, - } -); - -const loading = joinEdge === null || memberEdge === null; -const join = joinEdge && Object.keys(joinEdge).length; -const inverse = memberEdge && Object.keys(memberEdge).length; - -const type = join ? "leave" : "join"; - -const handleJoin = () => { - Social.set({ - graph: { [groupId]: { [accountId]: join ? null : "" } }, - index: { - graph: JSON.stringify({ - key: groupId, - value: { - type, - accountId, - }, - }), - notify: JSON.stringify([ - { - key: creatorId, - value: { - type, - accountId, - }, - }, - ]), - }, - }); -}; - -return ( - <> - - -); \ No newline at end of file diff --git a/apps/devs.near/widget/group/members.jsx b/apps/devs.near/widget/group/members.jsx deleted file mode 100644 index e36ed0b..0000000 --- a/apps/devs.near/widget/group/members.jsx +++ /dev/null @@ -1,27 +0,0 @@ -const groupId = props.groupId ?? "6fd36ddf4884flm20pbe91e7b208b88d16"; -const creatorId = props.creatorId ?? "*"; - -let members = Social.keys(`${creatorId}/graph/${groupId}/*`, "final", { - return_type: "BlockHeight", - values_only: true, -}); - -if (!members) { - return "Loading..."; -} - -const groupKey = Object.keys(members)[0]; - -members = Object.entries(members[groupKey]?.graph[groupId] || {}); -members.sort((a, b) => b[1] - a[1]); -return ( - <> - {members.map(([accountId], i) => ( -
    -
    - -
    -
    - ))} - -); \ No newline at end of file diff --git a/apps/devs.near/widget/group/overlay.jsx b/apps/devs.near/widget/group/overlay.jsx deleted file mode 100644 index cbecd65..0000000 --- a/apps/devs.near/widget/group/overlay.jsx +++ /dev/null @@ -1,57 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const groupId = props.groupId ?? "526fb256e74eelmf0nw3n5909bc189c13d"; -if (!groupId) { - return ""; -} - -const description = Social.get( - `${accountId}/thing/${groupId}/metadata/description` -); - -const Description = styled.div` - max-height: 8rem; - position: relative; - overflow: hidden; - h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 { - font-size: 1.2rem; - margin: 0 - } - p { - margin: 0 - } - :after { - content : ""; - position : absolute; - z-index : 1; - top : 4rem; - left : 0; - pointer-events : none; - background-image : linear-gradient(to bottom, - rgba(255,255,255, 0), - rgba(255,255,255, 1) 90%); - width : 100%; - height : 4rem; - } -`; - -return ( -
    - - - - - - -
    -
    - -
    -
    -
    - -
    -
    -); \ No newline at end of file diff --git a/apps/devs.near/widget/group/overlay/trigger.jsx b/apps/devs.near/widget/group/overlay/trigger.jsx deleted file mode 100644 index 1134ed2..0000000 --- a/apps/devs.near/widget/group/overlay/trigger.jsx +++ /dev/null @@ -1,15 +0,0 @@ -return ( - - ), - ...props, - }} - /> -); \ No newline at end of file diff --git a/apps/devs.near/widget/group/page.jsx b/apps/devs.near/widget/group/page.jsx deleted file mode 100644 index 80907da..0000000 --- a/apps/devs.near/widget/group/page.jsx +++ /dev/null @@ -1,231 +0,0 @@ -const creatorId = props.creatorId; -const groupId = props.groupId; - -const groupInfo = Social.get(`${creatorId}/thing/${groupId}/**`, "final"); - -if (!groupInfo) { - return "group details not found"; -} -const groupData = JSON.parse(groupInfo[""]); - -const NavUnderline = styled.ul` - border-bottom: 1px #eceef0 solid; - - a { - color: #687076; - text-decoration: none; - } - - a.active { - font-weight: bold; - color: #0c7283; - border-bottom: 4px solid #0c7283; - } -`; -/* END_INCLUDE: "core/lib/gui/navigation" */ - -const Button = styled.button` - height: 40px; - font-size: 14px; - border-color: #e3e3e0; - background-color: #ffffff; -`; - -const Banner = styled.div` - max-width: 100%; - min-height: 240px; - height: 240px; -`; - -const Content = styled.div` - display: flex; - flex-direction: column; - flex: 1; -`; - -const { Feed } = VM.require("efiz.near/widget/Module.Feed"); -Feed = Feed || (() => <>); - -const tabs = [ - { - defaultActive: true, - title: "Activity", - iconClass: "bi bi-house-door", - module: () => ( - <> - - ( - } - src="mob.near/widget/MainPage.N.Post" - props={{ accountId: p.accountId, blockHeight: p.blockHeight }} - /> - )} - /> - - ), - }, - { - iconClass: "bi bi-house-door", - title: "Members", - module: () => ( - <> -

    These are mutual members across all graphs

    - - - ), - }, - { - iconClass: "bi bi-house-door", - title: "Graphs", - module: () => ( - <> -

    - These are the users that have created their versions of this group. -

    - - - ), - }, - { - iconClass: "bi bi-gear", - title: "Settings", - module: () => ( - - ), - }, - ...(groupData.tabs || []), -]; - -State.init({ - selectedTab: tabs[0], -}); - -const { metadata } = groupInfo; -const { name, description, image, backgroundImage } = metadata; - -function Module({ module }) { - if (typeof module === "function") { - return module(); - } else { - return ; - } -} - -return ( -
    - - -
    -
    -
    -
    - Loading logo... -
    -
    - -
    - {name} - {description} -
    -
    - -
    - - -
    -
    - - - {tabs.map(({ iconClass, title }, index) => - title ? ( -
  • -
    State.update({ selectedTab: tabs[index] })} - > - - {title} -
    -
  • - ) : null - )} -
    - - - -
    -); diff --git a/apps/devs.near/widget/group/settings.jsx b/apps/devs.near/widget/group/settings.jsx deleted file mode 100644 index e8ca3ca..0000000 --- a/apps/devs.near/widget/group/settings.jsx +++ /dev/null @@ -1,80 +0,0 @@ -const { groupData, groupId } = props; -const initialTabs = groupData.tabs || []; -State.init({ - tabs: initialTabs, - src: "", - blockHeight: "", - iconClass: "", - title: "", - hasChanges: false, -}); - -const handleAddTab = () => { - const newTab = { - iconClass: iconClass, - title: title, - module: { - src: src, - blockHeight: blockHeight, - }, - }; - State.update({ tabs: [...tabs, newTab], hasChanges: true }); -}; - -const handleRemoveTab = (index) => { - const newTabs = [...tabs]; - newTabs.splice(index, 1); - State.update({ tabs: newTabs, hasChanges: true }); -}; - -const handleSave = () => { - Social.set({ - thing: { - [groupId]: { - "": JSON.stringify({ ...groupData, tabs }), - }, - }, - }); - setHasChanges(false); -}; - -return ( -
    -
    - State.update({ iconClass: e.target.value })} - /> - State.update({ title: e.target.value })} - /> - State.update({ src: e.target.value })} - /> - State.update({ blockHeight: e.target.value })} - /> - -
    -
      - {(tabs || []).map((tab, index) => ( -
    • - {tab.module.src} - {tab.module.blockHeight} - -
    • - ))} -
    -
    - -
    -
    -); diff --git a/apps/devs.near/widget/group/stats.jsx b/apps/devs.near/widget/group/stats.jsx deleted file mode 100644 index 76d2859..0000000 --- a/apps/devs.near/widget/group/stats.jsx +++ /dev/null @@ -1,55 +0,0 @@ -const accountId = props.accountId ?? context.accountId; -const groupId = props.groupId ?? "526fb256e74eelmf0nw3n5909bc189c13d"; -const creatorId = props.creatorId ?? "devs.near"; - -if (!accountId) { - return ""; -} - -const contributors = Social.keys(`${creatorId}/graph/${groupId}/*`, "final", { - return_type: "BlockHeight", - values_only: true, -}); - -const community = Social.keys(`*/graph/${groupId}/${accountId}`, "final", { - return_type: "BlockHeight", - values_only: true, -}); - -const numContributors = contributors - ? Object.keys(contributors[accountId].graph[groupId] || {}).length - : null; -const numCommunity = community ? Object.keys(community || {}).length : null; - -return ( - -); \ No newline at end of file diff --git a/apps/devs.near/widget/hyperfile.jsx b/apps/devs.near/widget/hyperfile.jsx deleted file mode 100644 index d18a792..0000000 --- a/apps/devs.near/widget/hyperfile.jsx +++ /dev/null @@ -1,120 +0,0 @@ -/** - * Modal can be moved to its own module - */ -const ModalBackdrop = styled.div` - position: fixed; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - background-color: rgba(0, 0, 0, 0.5); - display: flex; - justify-content: center; - align-items: center; - z-index: 1001; -`; - -const ModalBox = styled.div` - background-color: white; - min-width: 400px; - max-width: 600px; - padding: 20px; - border-radius: 8px; - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); - z-index: 1003; -`; - -const ModalHeader = styled.div` - display: flex; - justify-content: end; - align-items: center; -`; - -const CloseButton = styled.button` - background: #f44336; - color: white; - border: none; - border-radius: 5px; - padding: 10px 15px; - cursor: pointer; - float: right; -`; - -const ModalContent = styled.div` - display: flex; - flex-direction: column; - min-width: 300px; - padding: 10px; -`; - -function Modal({ onClose, children }) { - return ( - - - - Close - - {children} - - - ); -} - -const [isModalOpen, setModalOpen] = useState(props.isModalOpen); - -const toggleModal = (pluginId) => { - setModalOpen(!isModalOpen); -}; - -const Button = styled.button` - // this could take in theme - padding: 10px 20px; -`; - -const { path, data, type } = props; - -const parts = path.split("/"); -const creatorId = parts[0]; - -return ( - <> - { - State.update({ - ...state, - filtersOpen: open, - }); - }, - toggle: ( - - ), - content: ( -
    - - - -
    - ), - }} - /> - -); diff --git a/apps/devs.near/widget/hyperfile/create.jsx b/apps/devs.near/widget/hyperfile/create.jsx deleted file mode 100644 index a9e2950..0000000 --- a/apps/devs.near/widget/hyperfile/create.jsx +++ /dev/null @@ -1,292 +0,0 @@ -const Wrapper = styled.div` - max-width: 400px; - margin: 0 auto; -`; - -const TabContent = styled.div` - margin-top: 1rem; -`; - -const Form = styled.div` - display: flex; - flex-direction: column; - gap: 4px; - width: 100%; -`; - -const Label = styled.label` - font-weight: bold; -`; - -const Input = styled.input` - padding: 5px; -`; - -const Select = styled.select` - padding: 8px; -`; - -const FormGroup = styled.div` - display: flex; - flex-direction: column; -`; - -const adapters = [ - // these can come from the user (or app) settings - // { - // title: "Local Storage", - // value: "everycanvas.near/widget/adapter.local_storage", - // saveRef: false - // }, - // { - // title: "SocialDB", - // value: "everycanvas.near/widget/adapter.social", - // }, - { - title: "Social DB", - value: null, - }, - { - title: "IPFS", - value: "everycanvas.near/widget/adapter.ipfs", - }, - { - title: "Sputnik DAO", - value: "devs.near/widget/adapter.sputnik-dao", - }, - // { - // title: "GitHub", - // value: "hack.near/widget/adapter.github", - // }, - // { - // title: "Obsidian", - // value: "hack.near/widget/adapter.obsidian", - // }, - // { - // title: "Tldraw", - // value: "hack.near/widget/adapter.tldraw", - // }, -]; - -const defaultAdapter = adapters[0]; - -const { creatorId } = props; - -const [json, setJson] = useState(props.data ?? ""); -const [source, setSource] = useState(props.source ?? ""); -const [adapter, setAdapter] = useState(defaultAdapter.value ?? ""); -const [reference, setReference] = useState(undefined); -const [filename, setFilename] = useState(props.filename ?? ""); -const [activeTab, setActiveTab] = useState("data"); -const [name, setName] = useState(props.name ?? ""); -const [description, setDescription] = useState(props.description ?? ""); -const [path, setPath] = useState(props.path ?? ""); -const [type, setType] = useState(props.type ?? ""); - -const socialDbAdapter = { - get: (path, blockHeight) => { - if (!path) console.log("path not provided") && null; - if (!blockHeight) blockHeight = "final"; - return Social.get(path, blockHeight); - }, - create: (v) => { - const parts = path.split("/"); - return Social.set( - { - [parts[1]]: { - [parts[2]]: { - "": v, - metadata: { - type: type, - }, - }, - }, - }, - { - force: "true", - onCommit: (v) => { - console.log(v); - }, - onCancel: (v) => { - console.log(v); - }, - } - ); - }, -}; - -function generateUID() { - return ( - Math.random().toString(16).slice(2) + - Date.now().toString(36) + - Math.random().toString(16).slice(2) - ); -} - -const handleCreate = () => { - const isCreator = context.accountId === creatorId; - - // load in the state.adapter (modules for IPFS, Arweave, Ceramic, Verida, On Machina... ) - const { create } = adapter ? VM.require(adapter) : socialDbAdapter; - console.log("creating with", adapter); - // const { create } = VM.require(adapter) || (() => {}); - if (create) { - // store the data somewhere, based on the adapter - create(json) - // .then((reference) => { - // // now we have a reference to the data - // // we need to name it... are we the original creator or are we forking? We don't want to overwrite any of the users custom (or maybe we do!) - // const thingId = filename ?? generateUID(); - - // const hyperfile = { - // [props.type]: { - // // which we store in the social contract - // [thingId]: { - // "": JSON.stringify({ - // fileformat: `${props.type}.${source}`, - // source: source, - // adapter: adapter, - // reference: reference, - // }), - // metadata: { - // name: name, - // description: description, - // type: props.type, - // }, - // }, - // }, - // }; - - // if (creatorId !== context.accountId) { - // // handle request merge - // hyperfile.index = { - // notify: JSON.stringify({ - // key: creatorId, - // value: { - // type: "request", - // data: { - // type: "merge", - // upstream: `${creatorId}/${props.type}/${props.filename}`, - // origin: `${context.accountId}/${props.type}/${thingId}`, - // }, - // }, - // }), - // }; - // hyperfile[props.type][thingId].metadata = { - // ...hyperfile[props.type][thingId].metadata, - // upstream: `${creatorId}/${props.type}/${props.filename}`, - // }; - // // I want to make a request to merge - // // set upstream and downstream - // } - - // // sometimes we're not logged in, so it doesn't do anything! - // Social.set(hyperfile, { force: true }); - // }); - } -}; - -return ( - -

    {context.accountId === creatorId ? "create" : "request merge"}

    - - - - {activeTab === "data" && ( -
    - - - setPath(e.target.value)} - /> - - - - setType(e.target.value)} - /> - - - - onChangeSource(e.target.value)} - disabled={props.source} // disable if source is passed in - /> - - {/* */} -