├── .gitignore ├── .gitmodules ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .travis.yml ├── .vscode └── settings.json ├── README.md ├── firebase ├── .firebaserc ├── database.rules.json ├── firebase.json ├── firestore.indexes.json ├── firestore.rules ├── functions │ ├── .gitignore │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ └── index.ts │ ├── tsconfig.json │ └── yarn.lock └── storage.rules ├── frontend ├── .env.development ├── .env.staging ├── .eslintrc.js ├── .gitignore ├── .nvmrc ├── .storybook │ └── main.js ├── code-templates │ ├── storage-module.ts │ └── ui-element │ │ ├── index.tsx │ │ └── logic.ts ├── deploy-social-preview-functions.sh ├── dev-server │ ├── src │ │ └── main.ts │ └── tsconfig.json ├── fixtures │ ├── annotated-list-with-user-and-follows.yaml │ ├── annotated-list-with-user.yaml │ ├── annotation-coversation-with-user.yaml │ ├── cocurated-list.yaml │ ├── default-curator-with-public-profile.yaml │ ├── default-lists-with-user.yaml │ ├── discord-list-with-user.yaml │ ├── page-link-with-user.yaml │ ├── slack-list-with-user.yaml │ ├── with-annotated-list.yaml │ ├── with-annotation-conversations.yaml │ ├── with-cocurated-list.yaml │ ├── with-default-curator.yaml │ ├── with-default-shared-lists.yaml │ ├── with-default-user.yaml │ ├── with-discord-list.yaml │ ├── with-discord-user.yaml │ ├── with-joined-lists.yaml │ ├── with-list-follows.yaml │ ├── with-multiple-users.yaml │ ├── with-page-link.yaml │ ├── with-slack-list.yaml │ └── with-slack-user.yaml ├── ignore.loader.js ├── package.json ├── public │ ├── favicon.ico │ ├── fonts │ │ └── Satoshi │ │ │ ├── Satoshi-Black.ttf │ │ │ ├── Satoshi-Black.woff │ │ │ ├── Satoshi-BlackItalic.ttf │ │ │ ├── Satoshi-BlackItalic.woff │ │ │ ├── Satoshi-Bold.ttf │ │ │ ├── Satoshi-Bold.woff │ │ │ ├── Satoshi-BoldItalic.ttf │ │ │ ├── Satoshi-BoldItalic.woff │ │ │ ├── Satoshi-Italic.ttf │ │ │ ├── Satoshi-Italic.woff │ │ │ ├── Satoshi-Light.ttf │ │ │ ├── Satoshi-Light.woff │ │ │ ├── Satoshi-LightItalic.ttf │ │ │ ├── Satoshi-LightItalic.woff │ │ │ ├── Satoshi-Medium.ttf │ │ │ ├── Satoshi-Medium.woff │ │ │ ├── Satoshi-MediumItalic.ttf │ │ │ ├── Satoshi-MediumItalic.woff │ │ │ ├── Satoshi-Regular.ttf │ │ │ ├── Satoshi-Regular.woff │ │ │ ├── Satoshi-Variable.ttf │ │ │ ├── Satoshi-Variable.woff │ │ │ ├── Satoshi-VariableItalic.ttf │ │ │ ├── Satoshi-VariableItalic.woff │ │ │ ├── satoshi.css │ │ │ ├── satoshi.tsx │ │ │ └── style.css │ ├── manifest.json │ ├── reader-injection.js │ ├── reader-sw.js │ ├── webrecorder-custom.js │ └── webrecorder-sw.js ├── run-build.sh ├── scripts │ ├── generate-rules.ts │ ├── generate-types.ts │ └── tsconfig.json ├── src │ ├── assets │ │ └── img │ │ │ ├── 3dots.svg │ │ │ ├── addPeople.svg │ │ │ ├── alertRound.svg │ │ │ ├── appStore.png │ │ │ ├── apple_logo.svg │ │ │ ├── arrow-up.svg │ │ │ ├── arrowDown.svg │ │ │ ├── arrowLeft.svg │ │ │ ├── arrowRight.svg │ │ │ ├── arrowUp.svg │ │ │ ├── atSign.svg │ │ │ ├── atoms │ │ │ └── icons │ │ │ │ └── base │ │ │ │ └── finish.svg │ │ │ ├── backup.svg │ │ │ ├── bell.svg │ │ │ ├── block.svg │ │ │ ├── blueRoundCheck.svg │ │ │ ├── boldIcon.svg │ │ │ ├── bookmarkRibbon.svg │ │ │ ├── braveLogo.svg │ │ │ ├── bulletListIcon.svg │ │ │ ├── camera.svg │ │ │ ├── cameraIcon.svg │ │ │ ├── chatWithUs.svg │ │ │ ├── check.svg │ │ │ ├── checkRound.svg │ │ │ ├── checkedRound.svg │ │ │ ├── chrome.svg │ │ │ ├── chromeLogo.svg │ │ │ ├── clock.svg │ │ │ ├── close.svg │ │ │ ├── coil-icon.svg │ │ │ ├── collection.svg │ │ │ ├── collections_add.svg │ │ │ ├── collections_full.svg │ │ │ ├── command.svg │ │ │ ├── comment-empty.svg │ │ │ ├── comment-empty1.svg │ │ │ ├── comment.svg │ │ │ ├── comment1.svg │ │ │ ├── comment_add.svg │ │ │ ├── comment_edit.svg │ │ │ ├── comment_edit_full.svg │ │ │ ├── comment_empty.svg │ │ │ ├── comment_full.svg │ │ │ ├── compress-alt.svg │ │ │ ├── compress.svg │ │ │ ├── copy.svg │ │ │ ├── cursor.svg │ │ │ ├── date.svg │ │ │ ├── diigo.png │ │ │ ├── discord.svg │ │ │ ├── dollar-sign.svg │ │ │ ├── doubleArrow.svg │ │ │ ├── dropImage.svg │ │ │ ├── edit.svg │ │ │ ├── emptyCircle.svg │ │ │ ├── expand-alt.svg │ │ │ ├── expand.svg │ │ │ ├── feed.svg │ │ │ ├── file-pdf.svg │ │ │ ├── file.svg │ │ │ ├── fileFull.svg │ │ │ ├── filterIcon.svg │ │ │ ├── firefox.png │ │ │ ├── firefoxLogo.svg │ │ │ ├── folder.svg │ │ │ ├── followedSpace.svg │ │ │ ├── fullPageReading.svg │ │ │ ├── globe.svg │ │ │ ├── goTo.svg │ │ │ ├── google-drive.png │ │ │ ├── googleLogo.svg │ │ │ ├── googlePlay.png │ │ │ ├── h1Icon.svg │ │ │ ├── h2Icon.svg │ │ │ ├── hamburger.svg │ │ │ ├── headerBackground.svg │ │ │ ├── heart.svg │ │ │ ├── heart_empty.svg │ │ │ ├── heart_full.svg │ │ │ ├── help.svg │ │ │ ├── helpIcon.svg │ │ │ ├── highlightOff.svg │ │ │ ├── highlightOn.svg │ │ │ ├── highlights.svg │ │ │ ├── illustrations │ │ │ ├── browsingNotifications.svg │ │ │ └── sidebarAndHighlights.svg │ │ │ ├── imageIcon.svg │ │ │ ├── import.svg │ │ │ ├── inbox.svg │ │ │ ├── info.svg │ │ │ ├── infoIcon.svg │ │ │ ├── installBanner.svg │ │ │ ├── integrate.svg │ │ │ ├── invite.svg │ │ │ ├── italicIcon.svg │ │ │ ├── link.svg │ │ │ ├── linux_logo.svg │ │ │ ├── lock.svg │ │ │ ├── lockFine.svg │ │ │ ├── login.svg │ │ │ ├── logo-brave.svg │ │ │ ├── logo-chrome.svg │ │ │ ├── logo-firefox.svg │ │ │ ├── logout.svg │ │ │ ├── logseqLogo.svg │ │ │ ├── longArrowLeft.svg │ │ │ ├── longArrowRight.svg │ │ │ ├── longarrow.svg │ │ │ ├── macOption.svg │ │ │ ├── mail.svg │ │ │ ├── medium-logo.svg │ │ │ ├── memex-icon.svg │ │ │ ├── memex-logo-beta.svg │ │ │ ├── memex-logo-very-beta.svg │ │ │ ├── memex-logo.png │ │ │ ├── memex-logo.svg │ │ │ ├── memex-logo_old.svg │ │ │ ├── memexIconDarkMode.svg │ │ │ ├── memexIconLightMode.svg │ │ │ ├── memexLogo.svg │ │ │ ├── memexLogoGrey.svg │ │ │ ├── memexLogoHorizontal.png │ │ │ ├── memex_logo_black.svg │ │ │ ├── memex_text_logo.png │ │ │ ├── mobileHalf.svg │ │ │ ├── mobileIllustration.svg │ │ │ ├── mobilehalf.png │ │ │ ├── multiedit.svg │ │ │ ├── multy space.svg │ │ │ ├── new.svg │ │ │ ├── newFeed.svg │ │ │ ├── noNote.svg │ │ │ ├── numberedListIcon.svg │ │ │ ├── obsidianLogo.svg │ │ │ ├── onboarding │ │ │ ├── arrow2.svg │ │ │ ├── icon-externalLink.svg │ │ │ ├── memex_logo_black.svg │ │ │ └── tooltipIcon.svg │ │ │ ├── onlyIconLogo.svg │ │ │ ├── open.svg │ │ │ ├── openAI.svg │ │ │ ├── openSidebar.svg │ │ │ ├── pause.svg │ │ │ ├── pen.svg │ │ │ ├── people.svg │ │ │ ├── peopleFine.svg │ │ │ ├── peoplePlusFine.svg │ │ │ ├── person.svg │ │ │ ├── personFine.svg │ │ │ ├── phone.svg │ │ │ ├── pin.svg │ │ │ ├── play.svg │ │ │ ├── playFull.svg │ │ │ ├── plus.svg │ │ │ ├── plusIcon.svg │ │ │ ├── pocket.svg │ │ │ ├── quickActionRibbon.svg │ │ │ ├── raindrop.png │ │ │ ├── readwise.svg │ │ │ ├── rectangleDraw.svg │ │ │ ├── redo.svg │ │ │ ├── reload.svg │ │ │ ├── remove.svg │ │ │ ├── removeX.svg │ │ │ ├── reply.svg │ │ │ ├── ribbonOff.svg │ │ │ ├── ribbonOn.svg │ │ │ ├── sadFace.svg │ │ │ ├── saveIcon.svg │ │ │ ├── search.svg │ │ │ ├── settings.svg │ │ │ ├── share.svg │ │ │ ├── shareEmpty.svg │ │ │ ├── shareWhite.svg │ │ │ ├── shared.svg │ │ │ ├── sharedprotected.svg │ │ │ ├── shield.svg │ │ │ ├── sideBySide.svg │ │ │ ├── sidebarOn.svg │ │ │ ├── slack.svg │ │ │ ├── smileFace.svg │ │ │ ├── sort.svg │ │ │ ├── spaceEmpty.svg │ │ │ ├── spaceFull.svg │ │ │ ├── spotify-logo.svg │ │ │ ├── star_empty.svg │ │ │ ├── star_empty_grey.svg │ │ │ ├── star_full.svg │ │ │ ├── star_full_grey.svg │ │ │ ├── stars.svg │ │ │ ├── stop.svg │ │ │ ├── strikethroughIcon.svg │ │ │ ├── substack-logo.svg │ │ │ ├── sunrise.svg │ │ │ ├── tag_empty.svg │ │ │ ├── tag_full.svg │ │ │ ├── thread.svg │ │ │ ├── threads.svg │ │ │ ├── thumbtack.svg │ │ │ ├── timeStampIcon.svg │ │ │ ├── tooltipOff.svg │ │ │ ├── tooltipOn.svg │ │ │ ├── tooltip_full.svg │ │ │ ├── trash.svg │ │ │ ├── triangleSmall.svg │ │ │ ├── tutorialBlur.png │ │ │ ├── twitter-logo.svg │ │ │ ├── twitter.svg │ │ │ ├── twitterThin.svg │ │ │ ├── warning_red.svg │ │ │ ├── web-logo.svg │ │ │ ├── web-monetization-logo-confirmed.svg │ │ │ ├── web-monetization-logo.svg │ │ │ ├── welcomeScreenIllustration.svg │ │ │ ├── windows_logo.svg │ │ │ ├── worldbrain-logo-narrow-bw-16.png │ │ │ ├── worldbrain-logo-narrow-bw-48 copy.png │ │ │ ├── worldbrain-logo-narrow-bw-48.png │ │ │ ├── worldbrain-logo-narrow-bw.png │ │ │ └── youtube-logo.svg │ ├── comment-empty.svg │ ├── common-ui │ │ ├── components │ │ │ ├── PrimaryAction.tsx │ │ │ ├── SecondaryAction.tsx │ │ │ ├── button.tsx │ │ │ ├── creation-info.tsx │ │ │ ├── design-library │ │ │ │ ├── colors.ts │ │ │ │ └── typography.tsx │ │ │ ├── error-box.tsx │ │ │ ├── error-with-action.tsx │ │ │ ├── external-link.tsx │ │ │ ├── hoverbox.tsx │ │ │ ├── icon.tsx │ │ │ ├── item-box-bottom.tsx │ │ │ ├── item-box.tsx │ │ │ ├── loading-indicator.tsx │ │ │ ├── loading-screen.tsx │ │ │ ├── markdown.tsx │ │ │ ├── message-box.tsx │ │ │ ├── page-info-box.tsx │ │ │ ├── route-link.tsx │ │ │ ├── select.tsx │ │ │ ├── text-area.tsx │ │ │ ├── text-input.tsx │ │ │ └── user-avatar.tsx │ │ ├── layouts │ │ │ └── default-page-layout.tsx │ │ └── utils │ │ │ └── dom-events.tsx │ ├── constants.ts │ ├── features │ │ ├── activity-follows │ │ │ ├── storage │ │ │ │ ├── index.test.ts │ │ │ │ └── index.ts │ │ │ └── ui │ │ │ │ └── components │ │ │ │ └── follow-btn.tsx │ │ ├── activity-streams │ │ │ ├── storage │ │ │ │ └── index.ts │ │ │ └── ui │ │ │ │ ├── containers │ │ │ │ └── unseen-activity-indicator │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── logic.ts │ │ │ │ │ └── types.ts │ │ │ │ └── pages │ │ │ │ └── home-feed │ │ │ │ ├── index.tsx │ │ │ │ ├── logic.test.ts │ │ │ │ ├── logic.ts │ │ │ │ └── types.ts │ │ ├── annotations │ │ │ └── ui │ │ │ │ ├── components │ │ │ │ ├── annotation-box.tsx │ │ │ │ ├── annotations-in-page.tsx │ │ │ │ └── types.ts │ │ │ │ ├── logic.ts │ │ │ │ └── types.ts │ │ ├── content-conversations │ │ │ ├── services │ │ │ │ └── content-conversations.ts │ │ │ ├── storage │ │ │ │ └── index.ts │ │ │ └── ui │ │ │ │ ├── components │ │ │ │ ├── annotation-reply.tsx │ │ │ │ └── new-reply.tsx │ │ │ │ ├── logic.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ ├── content-sharing │ │ │ ├── service.ts │ │ │ ├── storage │ │ │ │ ├── index.test.data.ts │ │ │ │ ├── index.test.ts │ │ │ │ └── index.ts │ │ │ ├── types.ts │ │ │ └── ui │ │ │ │ └── pages │ │ │ │ ├── annotation-details │ │ │ │ ├── index.tsx │ │ │ │ ├── logic.ts │ │ │ │ └── types.ts │ │ │ │ ├── collection-details │ │ │ │ ├── constants.ts │ │ │ │ ├── index.tsx │ │ │ │ ├── logic.test.ts │ │ │ │ ├── logic.tsx │ │ │ │ ├── permission-key-overlay.tsx │ │ │ │ ├── space-access-box.tsx │ │ │ │ └── types.ts │ │ │ │ ├── page-details │ │ │ │ ├── index.tsx │ │ │ │ ├── logic.ts │ │ │ │ └── types.ts │ │ │ │ └── page-links │ │ │ │ ├── index.tsx │ │ │ │ ├── logic.ts │ │ │ │ └── types.ts │ │ ├── ext-detection │ │ │ └── ui │ │ │ │ ├── components │ │ │ │ ├── follow-space-overlay.tsx │ │ │ │ ├── install-ext-overlay.tsx │ │ │ │ └── missing-pdf-overlay.tsx │ │ │ │ └── logic.ts │ │ ├── lists-sidebar │ │ │ └── ui │ │ │ │ ├── components │ │ │ │ └── lists-sidebar.tsx │ │ │ │ ├── logic.ts │ │ │ │ └── types.ts │ │ ├── page-links │ │ │ └── services │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ ├── personal-cloud │ │ │ └── storage │ │ │ │ └── index.ts │ │ ├── reader │ │ │ ├── ui │ │ │ │ ├── components │ │ │ │ │ ├── OverlayModals.tsx │ │ │ │ │ ├── Sidebar.tsx │ │ │ │ │ └── Toolbar.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── logic.tsx │ │ │ │ └── types.ts │ │ │ └── utils │ │ │ │ ├── api.ts │ │ │ │ ├── iframe.ts │ │ │ │ └── utils.tsx │ │ ├── user-management │ │ │ ├── service │ │ │ │ └── index.ts │ │ │ ├── storage │ │ │ │ ├── index.test.ts │ │ │ │ └── index.ts │ │ │ ├── types.ts │ │ │ ├── ui │ │ │ │ ├── components │ │ │ │ │ ├── ActionButtons.tsx │ │ │ │ │ ├── auth-menu.tsx │ │ │ │ │ ├── curator-support-popup.tsx │ │ │ │ │ └── profile-popup.tsx │ │ │ │ ├── containers │ │ │ │ │ ├── account-settings-dialog │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── logic.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── auth-dialog │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── logic.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── auth-header │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── logic.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── curator-support-popup-container │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── logic.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── profile-edit-modal │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── logic.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ └── profile-popup-container │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── logic.ts │ │ │ │ │ │ └── types.ts │ │ │ │ └── utils.ts │ │ │ └── utils │ │ │ │ └── user-profile-cache.ts │ │ └── web-monetization │ │ │ ├── logic │ │ │ └── buttons │ │ │ │ ├── logic.ts │ │ │ │ └── types.ts │ │ │ ├── service │ │ │ ├── firebase │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── memory │ │ │ │ └── index.ts │ │ │ └── types.ts │ │ │ ├── ui │ │ │ ├── components │ │ │ │ └── web-monetization-icon │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── logic.ts │ │ │ └── containers │ │ │ │ └── curator-support-button-block │ │ │ │ ├── index.tsx │ │ │ │ └── logic.ts │ │ │ └── wm-types.ts │ ├── index.html │ ├── index.tsx │ ├── main-ui │ │ ├── classes │ │ │ ├── events.ts │ │ │ ├── index.tsx │ │ │ └── logic.ts │ │ ├── components │ │ │ ├── document-title.tsx │ │ │ ├── route-link │ │ │ │ ├── index.tsx │ │ │ │ └── logic.ts │ │ │ └── sidebar-toggle │ │ │ │ └── index.tsx │ │ ├── containers │ │ │ ├── app │ │ │ │ ├── index.tsx │ │ │ │ └── logic.ts │ │ │ └── overlay │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ ├── messages.ts │ │ ├── pages │ │ │ ├── landing-page │ │ │ │ ├── index.tsx │ │ │ │ ├── logic.ts │ │ │ │ └── types.ts │ │ │ ├── not-found │ │ │ │ └── index.tsx │ │ │ └── user-home │ │ │ │ ├── index.tsx │ │ │ │ └── logic.ts │ │ ├── routes.tsx │ │ ├── styles │ │ │ ├── global.ts │ │ │ ├── icons.tsx │ │ │ ├── theme.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ └── types │ │ │ └── index.ts │ ├── main.ts │ ├── meta-ui │ │ └── index.tsx │ ├── react-app-env.d.ts │ ├── routes.ts │ ├── rpc │ │ ├── index.ts │ │ └── types.ts │ ├── scenario-utils │ │ └── activities.ts │ ├── scenarios │ │ ├── activity-streams │ │ │ └── home-feed.ts │ │ ├── content-sharing │ │ │ ├── annotation-details.ts │ │ │ ├── collection-details.ts │ │ │ └── page-details.ts │ │ └── landing-page.ts │ ├── serviceWorker.ts │ ├── services │ │ ├── analytics.ts │ │ ├── auth │ │ │ ├── auth-sync.ts │ │ │ ├── base.ts │ │ │ ├── firebase.ts │ │ │ ├── memory │ │ │ │ └── index.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── clipboard │ │ │ ├── index.ts │ │ │ ├── mock.ts │ │ │ └── types.ts │ │ ├── device │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── document-title.ts │ │ ├── fixtures │ │ │ ├── generation.ts │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── full-text-search.ts │ │ ├── index.ts │ │ ├── local-storage │ │ │ ├── browser.ts │ │ │ ├── memory.ts │ │ │ └── types.ts │ │ ├── logic-registry │ │ │ └── index.ts │ │ ├── memex-extension.ts │ │ ├── overlay │ │ │ └── index.ts │ │ ├── router │ │ │ ├── index.ts │ │ │ ├── routes.test.ts │ │ │ └── routes.ts │ │ ├── scenarios │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── summarization.ts │ │ └── types.ts │ ├── setup │ │ ├── main.ts │ │ ├── meta.ts │ │ └── types.ts │ ├── storage │ │ ├── checks.ts │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── stories │ │ └── 0-Welcome.stories.tsx │ ├── styled-components-spacing.d.ts │ ├── styled-components.d.ts │ ├── tests │ │ ├── scenario-tests.test.ts │ │ ├── storage-tests.ts │ │ └── ui-logic.ts │ ├── types │ │ ├── auth.ts │ │ └── index.ts │ └── utils │ │ ├── call-modifier.ts │ │ ├── memex-installed.ts │ │ ├── monkey-patch.ts │ │ ├── ordered-map.ts │ │ ├── promises.ts │ │ ├── runtime-environment.ts │ │ ├── string.ts │ │ ├── translation.ts │ │ └── web-storage │ │ ├── index.ts │ │ └── types.ts ├── tsconfig.json ├── tsconfig.mocha.json ├── webpack │ ├── env.js │ ├── helpers.js │ ├── paths.js │ ├── plugins.js │ ├── resolve.js │ ├── rules.js │ ├── webpack.common.js │ ├── webpack.dev.js │ └── webpack.prod.js └── yarn.lock ├── lerna.json ├── package.json ├── tools └── ordered-packages.ts ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *swp 3 | firebase/public 4 | firebase/functions/.runtimeconfig.json 5 | .firebase/ 6 | *-debug.log 7 | private 8 | firebase/.runtimeconfig.json 9 | 10 | .env.staging 11 | 12 | .env.development 13 | 14 | frontend/.env 15 | 16 | .npmrc 17 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14.21.1 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | frontend/package.json 3 | .git/ 4 | node_modules/ 5 | firebase/public/ 6 | .firebase/ 7 | private/ 8 | frontend/code-templates/ 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "tabWidth": 4 6 | } 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | if: branch != master AND type = push 2 | language: node_js 3 | node_js: 4 | - 12.16.2 5 | install: 6 | - yarn bootstrap 7 | script: 8 | - cd frontend/ 9 | - yarn lint 10 | - yarn test 11 | - yarn build 12 | cache: 13 | yarn: true 14 | directories: 15 | - node_modules 16 | notifications: 17 | email: false 18 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.exclude": { 3 | "**/node_modules": true, 4 | ".firebase": true, 5 | "**/yarn.lock": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /firebase/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "worldbrain-staging", 4 | "production": "worldbrain-1057", 5 | "staging": "worldbrain-staging" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /firebase/firestore.indexes.json: -------------------------------------------------------------------------------- 1 | { 2 | "indexes": [ 3 | { 4 | "collectionGroup": "objects", 5 | "queryScope": "COLLECTION", 6 | "fields": [ 7 | { 8 | "fieldPath": "collection", 9 | "order": "ASCENDING" 10 | }, 11 | { 12 | "fieldPath": "createdWhen", 13 | "order": "ASCENDING" 14 | } 15 | ] 16 | }, 17 | { 18 | "collectionGroup": "sharedAnnotationListEntry", 19 | "queryScope": "COLLECTION", 20 | "fields": [ 21 | { 22 | "fieldPath": "sharedList", 23 | "order": "ASCENDING" 24 | }, 25 | { 26 | "fieldPath": "createdWhen", 27 | "order": "ASCENDING" 28 | } 29 | ] 30 | }, 31 | { 32 | "collectionGroup": "sharedListEntry", 33 | "queryScope": "COLLECTION", 34 | "fields": [ 35 | { 36 | "fieldPath": "sharedList", 37 | "order": "ASCENDING" 38 | }, 39 | { 40 | "fieldPath": "createdWhen", 41 | "order": "DESCENDING" 42 | } 43 | ] 44 | } 45 | ], 46 | "fieldOverrides": [] 47 | } 48 | -------------------------------------------------------------------------------- /firebase/functions/.gitignore: -------------------------------------------------------------------------------- 1 | ## Compiled JavaScript files 2 | **/*.js 3 | **/*.js.map 4 | 5 | # Typescript v1 declaration files 6 | typings/ 7 | 8 | node_modules/ 9 | 10 | .env* 11 | -------------------------------------------------------------------------------- /firebase/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "scripts": { 4 | "build": "tsc", 5 | "serve": "npm run build && firebase emulators:start --only functions", 6 | "shell": "npm run build && firebase functions:shell", 7 | "start": "npm run shell", 8 | "deploy": "firebase deploy --only functions", 9 | "logs": "firebase functions:log" 10 | }, 11 | "engines": { 12 | "node": "16" 13 | }, 14 | "main": "lib/index.js", 15 | "dependencies": { 16 | "@worldbrain/memex-common": "^0.1.1", 17 | "firebase-admin": "10.3.0", 18 | "firebase-functions": "4.4.1" 19 | }, 20 | "devDependencies": { 21 | "typescript": "^4.8.4", 22 | "firebase-functions-test": "^0.2.0" 23 | }, 24 | "private": true 25 | } 26 | -------------------------------------------------------------------------------- /firebase/functions/src/constants.ts: -------------------------------------------------------------------------------- 1 | import * as admin from 'firebase-admin' 2 | 3 | export const runningInEmulator = process.env.FUNCTIONS_EMULATOR 4 | export const emulatedConfig = { 5 | credential: admin.credential.applicationDefault(), 6 | databaseURL: 'https://worldbrain-staging.firebaseio.com', 7 | projectId: 'worldbrain-staging', 8 | } 9 | -------------------------------------------------------------------------------- /firebase/functions/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as admin from 'firebase-admin' 2 | import * as functionsV1 from 'firebase-functions/v1' 3 | import { onRequest, onCall } from 'firebase-functions/v2/https' 4 | import { defineSecret, defineString } from 'firebase-functions/params' 5 | import { 6 | onDocumentCreated, 7 | onDocumentDeleted, 8 | } from 'firebase-functions/v2/firestore' 9 | import { main } from '@worldbrain/memex-common/lib/firebase-backend/main' 10 | import type { 11 | RequiredFunctionParamsModules, 12 | RequiredFunctionV2Modules, 13 | } from '@worldbrain/memex-common/lib/firebase-backend/types' 14 | 15 | const functionsV2: RequiredFunctionV2Modules = { 16 | https: { onCall, onRequest }, 17 | firestore: { onDocumentCreated, onDocumentDeleted }, 18 | } 19 | 20 | const functionParams: RequiredFunctionParamsModules = { 21 | defineSecret, 22 | defineString, 23 | } 24 | 25 | module.exports = main(admin, functionsV1, functionsV2, functionParams) 26 | -------------------------------------------------------------------------------- /firebase/functions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "noImplicitReturns": true, 5 | "noUnusedLocals": true, 6 | "outDir": "lib", 7 | "sourceMap": true, 8 | "strict": true, 9 | "target": "es2017" 10 | }, 11 | "compileOnSave": true, 12 | "include": ["src"] 13 | } 14 | -------------------------------------------------------------------------------- /firebase/storage.rules: -------------------------------------------------------------------------------- 1 | rules_version = '2'; 2 | 3 | service firebase.storage { 4 | match /b/{bucket}/o { 5 | match /u/{userId} { 6 | match /docContent/{contentId} { 7 | allow read: if request.auth.uid == userId; 8 | allow write: if request.auth.uid == userId; 9 | } 10 | match /favIcon/{domain} { 11 | allow read: if request.auth.uid == userId; 12 | allow write: if request.auth.uid == userId; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/.env.development: -------------------------------------------------------------------------------- 1 | REACT_APP_FIREBASE_API_KEY=AIzaSyCyxWY7qZSWlncB_JDYOSzeTOfRnYhNcS8 2 | REACT_APP_FIREBASE_AUTH_DOMAIN=worldbrain-staging.firebaseapp.com 3 | REACT_APP_FIREBASE_DATABSE_URL=https://worldbrain-staging.firebaseio.com 4 | REACT_APP_FIREBASE_PROJECT_ID=worldbrain-staging 5 | REACT_APP_FIREBASE_MESSAGING_SENDER_ID=840601505816 6 | REACT_APP_FIREBASE_APP_ID=1:840601505816:web:69fbb7a789882e399fb36d 7 | REACT_APP_FIREBASE_MEASUREMENT_ID=G-0T84D1RBWZ 8 | -------------------------------------------------------------------------------- /frontend/.env.staging: -------------------------------------------------------------------------------- 1 | REACT_APP_FIREBASE_API_KEY=AIzaSyCyxWY7qZSWlncB_JDYOSzeTOfRnYhNcS8 2 | REACT_APP_FIREBASE_AUTH_DOMAIN=worldbrain-staging.firebaseapp.com 3 | REACT_APP_FIREBASE_DATABSE_URL=https://worldbrain-staging.firebaseio.com 4 | REACT_APP_FIREBASE_PROJECT_ID=worldbrain-staging 5 | REACT_APP_FIREBASE_MESSAGING_SENDER_ID=840601505816 6 | REACT_APP_FIREBASE_APP_ID=1:840601505816:web:69fbb7a789882e399fb36d 7 | REACT_APP_FIREBASE_MEASUREMENT_ID=G-0T84D1RBWZ 8 | MEMEX_EXTENSION_ID=ielfhekmfbpebfogdeipegfeooelelge 9 | 10 | -------------------------------------------------------------------------------- /frontend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: 'react-app', 4 | ignorePatterns: ['../external/**/*', '**/node_modules/**/*'], 5 | parser: '@typescript-eslint/parser', 6 | parserOptions: { project: ['./tsconfig.json'] }, 7 | plugins: ['@typescript-eslint'], 8 | rules: { 9 | 'jsx-a11y/accessible-emoji': 'off', 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | .env.production 21 | 22 | *-debug.log* 23 | *-error.log* 24 | .env*.local 25 | -------------------------------------------------------------------------------- /frontend/.nvmrc: -------------------------------------------------------------------------------- 1 | v16 2 | -------------------------------------------------------------------------------- /frontend/.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ['../src/**/*.stories.tsx'], 3 | addons: [ 4 | '@storybook/preset-create-react-app', 5 | '@storybook/addon-actions', 6 | '@storybook/addon-links', 7 | ], 8 | } 9 | -------------------------------------------------------------------------------- /frontend/code-templates/storage-module.ts: -------------------------------------------------------------------------------- 1 | import { StorageModule, StorageModuleConfig } from "@worldbrain/storex-pattern-modules"; 2 | import { STORAGE_VERSIONS } from "../versions"; 3 | 4 | export default class [Name]Storage extends StorageModule { 5 | getConfig() : StorageModuleConfig { 6 | return { 7 | collections: { 8 | [something]: { 9 | version: STORAGE_VERSIONS[0].date, 10 | fields: { 11 | }, 12 | }, 13 | }, 14 | operations: { 15 | }, 16 | methods: { 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /frontend/code-templates/ui-element/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { UIElement, UIElementServices } from '../../classes'; 3 | import Logic, { State, Event } from './logic'; 4 | 5 | interface Props { 6 | services : UIElementServices 7 | } 8 | 9 | export default class [name] extends UIElement { 10 | constructor(props : Props) { 11 | super(props, { logic: new Logic() }) 12 | } 13 | 14 | render() { 15 | return ( 16 |
17 |
18 | ) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /frontend/code-templates/ui-element/logic.ts: -------------------------------------------------------------------------------- 1 | import { UILogic, UIEvent } from "../../classes/logic" 2 | 3 | export interface State { 4 | 5 | } 6 | export type Event = UIEvent<{}> 7 | 8 | export default class Logic extends UILogic { 9 | getInitialState() : State { 10 | return {} 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /frontend/dev-server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "allowJs": true, 5 | "target": "ES6", 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "esModuleInterop": true, 9 | "jsx": "react", 10 | "noImplicitAny": false, 11 | "sourceMap": true, 12 | "emitDecoratorMetadata": true, 13 | "experimentalDecorators": true, 14 | "allowSyntheticDefaultImports": true, 15 | "skipDefaultLibCheck": true, 16 | "skipLibCheck": true, 17 | "strictNullChecks": false, 18 | "outDir": "tmp", 19 | "lib": ["es2017", "dom", "esnext.asynciterable"] 20 | }, 21 | "include": ["./src/**/*", "../src/**/*"], 22 | "exclude": ["node_modules", "./src/**/*.js", "./src/**/*.jsx"] 23 | } 24 | -------------------------------------------------------------------------------- /frontend/fixtures/annotated-list-with-user-and-follows.yaml: -------------------------------------------------------------------------------- 1 | extends: 2 | [ 3 | with-default-user, 4 | with-annotated-list, 5 | with-list-follows, 6 | with-joined-lists, 7 | ] 8 | -------------------------------------------------------------------------------- /frontend/fixtures/annotated-list-with-user.yaml: -------------------------------------------------------------------------------- 1 | extends: [with-default-user, with-annotated-list] 2 | -------------------------------------------------------------------------------- /frontend/fixtures/annotation-coversation-with-user.yaml: -------------------------------------------------------------------------------- 1 | extends: [with-default-user, with-annotation-conversations] 2 | -------------------------------------------------------------------------------- /frontend/fixtures/cocurated-list.yaml: -------------------------------------------------------------------------------- 1 | extends: 2 | [ 3 | with-multiple-users, 4 | with-cocurated-list, 5 | with-annotated-list, 6 | with-list-follows, 7 | ] 8 | -------------------------------------------------------------------------------- /frontend/fixtures/default-curator-with-public-profile.yaml: -------------------------------------------------------------------------------- 1 | extends: ['with-default-curator', 'with-public-profile'] 2 | -------------------------------------------------------------------------------- /frontend/fixtures/default-lists-with-user.yaml: -------------------------------------------------------------------------------- 1 | extends: [with-default-user, with-default-shared-lists] 2 | -------------------------------------------------------------------------------- /frontend/fixtures/discord-list-with-user.yaml: -------------------------------------------------------------------------------- 1 | extends: [with-discord-user, with-discord-list] 2 | -------------------------------------------------------------------------------- /frontend/fixtures/page-link-with-user.yaml: -------------------------------------------------------------------------------- 1 | extends: [with-default-user, with-page-link] 2 | -------------------------------------------------------------------------------- /frontend/fixtures/slack-list-with-user.yaml: -------------------------------------------------------------------------------- 1 | extends: [with-slack-user, with-slack-list] 2 | -------------------------------------------------------------------------------- /frontend/fixtures/with-default-curator.yaml: -------------------------------------------------------------------------------- 1 | objects: 2 | users: 3 | - $store: default 4 | id: default-curator 5 | displayName: 'Tiago Forte' 6 | -------------------------------------------------------------------------------- /frontend/fixtures/with-default-user.yaml: -------------------------------------------------------------------------------- 1 | objects: 2 | users: 3 | - $store: default 4 | id: default-user 5 | displayName: 'John Doe' 6 | userPublicProfiles: 7 | - $store: default 8 | user: { $ref: users.default } 9 | websiteURL: 'https://fortelabs.co/' 10 | mediumURL: 'https://medium.com/@fortelabs' 11 | twitterURL: 'https://twitter.com/fortelabs' 12 | substackURL: 'https://every.to/@tiago' 13 | bio: 'Founder @fortelabs.co | Teaching @buildingasecondbrain.com | Writer @fortelabs.co/blog + the best productivity newsletter on the web: fortelabs.co/subscribe' 14 | avatarURL: '' 15 | paymentPointer: '$ilp.uphold.com/zHjHFKyUWbwB' 16 | -------------------------------------------------------------------------------- /frontend/fixtures/with-discord-user.yaml: -------------------------------------------------------------------------------- 1 | objects: 2 | users: 3 | - $store: default 4 | id: 'discord:default-user' 5 | platform: discord 6 | platformId: discord-user-id 7 | displayName: Darren 8 | # userPublicProfiles: 9 | # - $store: default 10 | # user: { $ref: users.default } 11 | # websiteURL: 'https://fortelabs.co/' 12 | # mediumURL: 'https://medium.com/@fortelabs' 13 | # twitterURL: 'https://twitter.com/fortelabs' 14 | # substackURL: 'https://every.to/@tiago' 15 | # bio: 'Founder @fortelabs.co | Teaching @buildingasecondbrain.com | Writer @fortelabs.co/blog + the best productivity newsletter on the web: fortelabs.co/subscribe' 16 | # avatarURL: '' 17 | # paymentPointer: '$ilp.uphold.com/zHjHFKyUWbwB' 18 | -------------------------------------------------------------------------------- /frontend/fixtures/with-slack-user.yaml: -------------------------------------------------------------------------------- 1 | objects: 2 | users: 3 | - $store: default 4 | id: 'slack:default-user' 5 | platform: slack 6 | platformId: slack-user-id 7 | displayName: Darren 8 | # userPublicProfiles: 9 | # - $store: default 10 | # user: { $ref: users.default } 11 | # websiteURL: 'https://fortelabs.co/' 12 | # mediumURL: 'https://medium.com/@fortelabs' 13 | # twitterURL: 'https://twitter.com/fortelabs' 14 | # substackURL: 'https://every.to/@tiago' 15 | # bio: 'Founder @fortelabs.co | Teaching @buildingasecondbrain.com | Writer @fortelabs.co/blog + the best productivity newsletter on the web: fortelabs.co/subscribe' 16 | # avatarURL: '' 17 | # paymentPointer: '$ilp.uphold.com/zHjHFKyUWbwB' 18 | -------------------------------------------------------------------------------- /frontend/ignore.loader.js: -------------------------------------------------------------------------------- 1 | function donothing() { 2 | return null 3 | } 4 | 5 | require.extensions['.css'] = donothing 6 | require.extensions['.less'] = donothing 7 | require.extensions['.scss'] = donothing 8 | require.extensions['.svg'] = donothing 9 | require.extensions['.png'] = donothing 10 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Black.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Black.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-BlackItalic.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-BlackItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-BlackItalic.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Bold.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Bold.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-BoldItalic.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-BoldItalic.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Italic.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Italic.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Light.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Light.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-LightItalic.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-LightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-LightItalic.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Medium.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Medium.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-MediumItalic.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-MediumItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-MediumItalic.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Regular.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Regular.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Variable.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Variable.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-Variable.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-Variable.woff -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-VariableItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-VariableItalic.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Satoshi/Satoshi-VariableItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/public/fonts/Satoshi/Satoshi-VariableItalic.woff -------------------------------------------------------------------------------- /frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /frontend/public/reader-injection.js: -------------------------------------------------------------------------------- 1 | console.log('injected script loaded') 2 | 3 | document.addEventListener('DOMContentLoaded', async () => {}) 4 | -------------------------------------------------------------------------------- /frontend/public/reader-sw.js: -------------------------------------------------------------------------------- 1 | // self.addEventListener('install', (event) => { 2 | // }) 3 | 4 | self.addEventListener('activate', () => { 5 | clients.claim() 6 | }) 7 | 8 | self.addEventListener('fetch', (event) => { 9 | event.respondWith(fetch(event.request)) 10 | 11 | // event.respondWith(async () => { 12 | // let response 13 | // try { 14 | // response = fetch(event.request) 15 | // } catch (err) { 16 | // response = null 17 | // } 18 | // if (response?.ok) { 19 | // return response 20 | // } 21 | 22 | // return fetch( 23 | // `https://cloudflare-memex-staging.memex.workers.dev/webarchive?url=${encodeURIComponent( 24 | // event.request.href, 25 | // )}`, 26 | // ) 27 | // }) 28 | }) 29 | -------------------------------------------------------------------------------- /frontend/public/webrecorder-custom.js: -------------------------------------------------------------------------------- 1 | console.log('Custom Script, Location is: ' + window.location.href) 2 | -------------------------------------------------------------------------------- /frontend/run-build.sh: -------------------------------------------------------------------------------- 1 | # Do main build then move output to hosting dir 2 | env-cmd -f $ENV_FILE webpack --config webpack/webpack.prod.js 3 | mkdir -p ../firebase/public 4 | rm -rf ../firebase/public/* 5 | mv build/* ../firebase/public/ 6 | cp -r public/* ../firebase/public/ 7 | 8 | if [ $SKIP_DEPLOY_SOCIAL_PREVIEW_FUNCS = "true" ]; then 9 | exit 0 10 | fi 11 | 12 | # Derive bundle names (contain dynamic cache-busting hashes) 13 | bundle_names='' 14 | for bundle in ../firebase/public/*.{js,css}; do 15 | base_name=$(basename $bundle) 16 | bundle_names+="${base_name} " 17 | done 18 | 19 | # Remove trailing space 20 | bundle_names=$(echo $bundle_names | sed 's/ *$//') 21 | 22 | # Write latest bundle names to .env.*, so functions can access them 23 | for env_file in ../firebase/functions/{.env.production,.env.staging}; do 24 | # If var already there, replace, else append 25 | if grep -q "WEB_UI_BUNDLES=" $env_file; then 26 | sed -i '' -e "s/WEB_UI_BUNDLES=.*/WEB_UI_BUNDLES=\"${bundle_names}\"/" $env_file 27 | else 28 | echo "WEB_UI_BUNDLES=\"${bundle_names}\"" >> $env_file 29 | fi 30 | done 31 | -------------------------------------------------------------------------------- /frontend/scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "allowJs": true, 5 | "target": "ES6", 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "esModuleInterop": true, 9 | "jsx": "react", 10 | "noImplicitAny": false, 11 | "sourceMap": true, 12 | "emitDecoratorMetadata": true, 13 | "experimentalDecorators": true, 14 | "allowSyntheticDefaultImports": true, 15 | "skipDefaultLibCheck": true, 16 | "skipLibCheck": true, 17 | "strictNullChecks": false, 18 | "outDir": "tmp", 19 | "lib": ["es2017", "dom", "esnext.asynciterable"], 20 | "types": ["node"] 21 | }, 22 | "include": ["./**/*"], 23 | "exclude": ["node_modules", "./src/**/*.js", "./src/**/*.jsx"] 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/assets/img/3dots.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/src/assets/img/alertRound.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/appStore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/appStore.png -------------------------------------------------------------------------------- /frontend/src/assets/img/apple_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/arrow-up.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/img/arrowDown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/arrowLeft.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/arrowRight.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/arrowUp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/atoms/icons/base/finish.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/bell.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/block.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/blueRoundCheck.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/img/boldIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/bookmarkRibbon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/bulletListIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/camera.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/checkRound.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/checkedRound.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/clock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/collection.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/collections_add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/collections_full.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/command.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/comment-empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/comment-empty1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/comment.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/comment1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/comment_add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/comment_edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/src/assets/img/comment_edit_full.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/src/assets/img/comment_empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/comment_full.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/compress-alt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/compress.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/cursor.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/date.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/diigo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/diigo.png -------------------------------------------------------------------------------- /frontend/src/assets/img/dollar-sign.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/img/doubleArrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/assets/img/dropImage.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/img/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/emptyCircle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/expand-alt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/expand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/feed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/file-pdf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/fileFull.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/src/assets/img/filterIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/firefox.png -------------------------------------------------------------------------------- /frontend/src/assets/img/folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/fullPageReading.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/img/goTo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/google-drive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/google-drive.png -------------------------------------------------------------------------------- /frontend/src/assets/img/googleLogo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/img/googlePlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/googlePlay.png -------------------------------------------------------------------------------- /frontend/src/assets/img/h1Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/h2Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/hamburger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/heart_empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/heart_full.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/highlightOff.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/highlightOn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/highlights.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/imageIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/import.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/inbox.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/infoIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/integrate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/italicIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/lock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/lockFine.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/img/login.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/logout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/longArrowLeft.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/longArrowRight.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/longarrow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/img/macOption.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/assets/img/mail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/memex-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/memex-logo.png -------------------------------------------------------------------------------- /frontend/src/assets/img/memexLogoHorizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/memexLogoHorizontal.png -------------------------------------------------------------------------------- /frontend/src/assets/img/memex_text_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/memex_text_logo.png -------------------------------------------------------------------------------- /frontend/src/assets/img/mobilehalf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/mobilehalf.png -------------------------------------------------------------------------------- /frontend/src/assets/img/multiedit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/newFeed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/onboarding/arrow2.svg: -------------------------------------------------------------------------------- 1 | _ -------------------------------------------------------------------------------- /frontend/src/assets/img/onboarding/icon-externalLink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /frontend/src/assets/img/open.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/openSidebar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/assets/img/pause.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/img/pen.svg: -------------------------------------------------------------------------------- 1 | 2459-Brandfex-Icons-for-nounproject-vector -------------------------------------------------------------------------------- /frontend/src/assets/img/people.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/peoplePlusFine.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/person.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/phone.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/pin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/playFull.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/plusIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/pocket.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/img/raindrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/raindrop.png -------------------------------------------------------------------------------- /frontend/src/assets/img/readwise.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/src/assets/img/redo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/reload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/removeX.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/reply.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/ribbonOff.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /frontend/src/assets/img/ribbonOn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /frontend/src/assets/img/saveIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/img/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/share.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/shareEmpty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/shareWhite.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/shared.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/sideBySide.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/sidebarOn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/slack.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/assets/img/smileFace.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/sort.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/spaceEmpty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/spaceFull.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/spotify-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/img/star_empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/star_full.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/star_full_grey.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | noun_537691_3EB995 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /frontend/src/assets/img/stop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/strikethroughIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/substack-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/sunrise.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/tag_empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/img/tag_full.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/img/thread.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/assets/img/threads.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/assets/img/thumbtack.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/img/tooltipOn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/tooltip_full.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/triangleSmall.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/tutorialBlur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/tutorialBlur.png -------------------------------------------------------------------------------- /frontend/src/assets/img/twitter-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/img/warning_red.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /frontend/src/assets/img/windows_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/src/assets/img/worldbrain-logo-narrow-bw-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/worldbrain-logo-narrow-bw-16.png -------------------------------------------------------------------------------- /frontend/src/assets/img/worldbrain-logo-narrow-bw-48 copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/worldbrain-logo-narrow-bw-48 copy.png -------------------------------------------------------------------------------- /frontend/src/assets/img/worldbrain-logo-narrow-bw-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/worldbrain-logo-narrow-bw-48.png -------------------------------------------------------------------------------- /frontend/src/assets/img/worldbrain-logo-narrow-bw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/assets/img/worldbrain-logo-narrow-bw.png -------------------------------------------------------------------------------- /frontend/src/assets/img/youtube-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /frontend/src/comment-empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/button.tsx: -------------------------------------------------------------------------------- 1 | export { default } from '@worldbrain/memex-common/lib/common-ui/components/button' 2 | export type { ButtonProps } from '@worldbrain/memex-common/lib/common-ui/components/button' 3 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/creation-info.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CommonCreationInfo, { 3 | CreationInfoProps, 4 | } from '@worldbrain/memex-common/lib/common-ui/components/creation-info' 5 | import { ProfilePopupContainerDependencies } from '../../features/user-management/ui/containers/profile-popup-container/types' 6 | import ProfilePopupContainer from '../../features/user-management/ui/containers/profile-popup-container' 7 | 8 | export default function CreationInfo( 9 | props: CreationInfoProps & { 10 | profilePopup?: ProfilePopupContainerDependencies | null 11 | }, 12 | ) { 13 | if (props.profilePopup) { 14 | return ( 15 | 16 | 17 | 18 | ) 19 | } else { 20 | return 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/error-box.tsx: -------------------------------------------------------------------------------- 1 | export { default } from '@worldbrain/memex-common/lib/common-ui/components/error-box' 2 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/external-link.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components' 3 | 4 | const Link = styled.a` 5 | font-size: inherit; 6 | color: inherit; 7 | font-weight: bold; 8 | display: contents; 9 | text-decoration: none; 10 | padding: 0 3px; 11 | margin-top: 2px; 12 | cursor: pointer; 13 | left: 3px; 14 | position: relative; 15 | ` 16 | 17 | export default function ExternalLink(props: { 18 | href: string 19 | children: React.ReactNode 20 | className?: string 21 | }) { 22 | return ( 23 | 24 | {props.children} 25 | 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/icon.tsx: -------------------------------------------------------------------------------- 1 | export { default } from '@worldbrain/memex-common/lib/common-ui/components/icon' 2 | export type { IconProps } from '@worldbrain/memex-common/lib/common-ui/components/icon' 3 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/item-box-bottom.tsx: -------------------------------------------------------------------------------- 1 | export * from '@worldbrain/memex-common/lib/common-ui/components/item-box-bottom' 2 | export { default } from '@worldbrain/memex-common/lib/common-ui/components/item-box-bottom' 3 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/item-box.tsx: -------------------------------------------------------------------------------- 1 | import ItemBox from '@worldbrain/memex-common/lib/common-ui/components/item-box' 2 | 3 | export default ItemBox 4 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/loading-indicator.tsx: -------------------------------------------------------------------------------- 1 | export { default } from '@worldbrain/memex-common/lib/common-ui/components/loading-indicator' 2 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/loading-screen.tsx: -------------------------------------------------------------------------------- 1 | export { default } from '@worldbrain/memex-common/lib/common-ui/components/loading-screen' 2 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/markdown.tsx: -------------------------------------------------------------------------------- 1 | import Markdown from '@worldbrain/memex-common/lib/common-ui/components/markdown' 2 | export default Markdown 3 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/message-box.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components' 3 | import { Margin } from 'styled-components-spacing' 4 | 5 | const StyledMessageBox = styled.div` 6 | font-family: ${(props) => props.theme.fonts.primary}; 7 | width: 100%; 8 | padding: 20px 20px; 9 | text-align: center; 10 | ` 11 | 12 | const MessageBoxTitle = styled.div` 13 | font-weight: 800; 14 | color: ${(props) => props.theme.colors.white}; 15 | font-size: 18px; 16 | ` 17 | 18 | const MessageBoxBody = styled.div` 19 | color: ${(props) => props.theme.colors.greyScale5}; 20 | font-weight: 300; 21 | font-size: 16px; 22 | ` 23 | 24 | export default function MessageBox(props: { 25 | title: string 26 | children: React.ReactNode 27 | }) { 28 | return ( 29 | 30 | 31 | {props.title} 32 | 33 | {props.children} 34 | 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/page-info-box.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CommonPageInfoBox, { 3 | PageInfoBoxProps, 4 | PageInfoBoxAction, 5 | } from '@worldbrain/memex-common/lib/common-ui/components/page-info-box' 6 | import { ProfilePopupContainerDependencies } from '../../features/user-management/ui/containers/profile-popup-container/types' 7 | import CreationInfo from './creation-info' 8 | 9 | export type { PageInfoBoxAction } 10 | 11 | export default function PageInfoBox( 12 | props: PageInfoBoxProps & { 13 | profilePopup?: ProfilePopupContainerDependencies | null 14 | }, 15 | ) { 16 | return ( 17 | ( 20 | 24 | )} 25 | /> 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/select.tsx: -------------------------------------------------------------------------------- 1 | export { default } from '@worldbrain/memex-common/lib/common-ui/components/select' 2 | export type { 3 | OptionProps, 4 | SelectProps, 5 | } from '@worldbrain/memex-common/lib/common-ui/components/select' 6 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/text-area.tsx: -------------------------------------------------------------------------------- 1 | export * from '@worldbrain/memex-common/lib/common-ui/components/text-area' 2 | export { default } from '@worldbrain/memex-common/lib/common-ui/components/text-area' 3 | -------------------------------------------------------------------------------- /frontend/src/common-ui/components/user-avatar.tsx: -------------------------------------------------------------------------------- 1 | export { default } from '@worldbrain/memex-common/lib/common-ui/components/user-avatar' 2 | -------------------------------------------------------------------------------- /frontend/src/common-ui/utils/dom-events.tsx: -------------------------------------------------------------------------------- 1 | export * from '@worldbrain/memex-common/lib/common-ui/utils/dom-events' 2 | -------------------------------------------------------------------------------- /frontend/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const USER_PROFILE_BIO_CHAR_LIMIT = 280 2 | 3 | export const VALID_URL_TEST = /^(ftp|http|https):\/\/[^ "]+$/ 4 | 5 | /** 6 | * Keys should take the form `@FeatureName-individual-state_name` 7 | */ 8 | export const LOCAL_STORAGE_KEYS = { 9 | isListSidebarShown: '@ListSidebar-is_shown', 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/features/activity-follows/storage/index.ts: -------------------------------------------------------------------------------- 1 | import ActivityFollowsStorage from '@worldbrain/memex-common/lib/activity-follows/storage' 2 | export default ActivityFollowsStorage 3 | -------------------------------------------------------------------------------- /frontend/src/features/activity-streams/storage/index.ts: -------------------------------------------------------------------------------- 1 | import ActivityStreamsStorage from '@worldbrain/memex-common/lib/activity-streams/storage' 2 | export default ActivityStreamsStorage 3 | -------------------------------------------------------------------------------- /frontend/src/features/activity-streams/ui/containers/unseen-activity-indicator/types.ts: -------------------------------------------------------------------------------- 1 | import { UIEvent, UISignal } from '../../../../../main-ui/classes/logic' 2 | import { UIElementServices } from '../../../../../services/types' 3 | import { StorageModules } from '../../../../../storage/types' 4 | import { UITaskState } from '../../../../../main-ui/types' 5 | 6 | export interface UnseenActivityIndicatorDependencies { 7 | services: UIElementServices<'activityStreams' | 'auth'> 8 | storage: Pick 9 | } 10 | 11 | export type UnseenActivityIndicatorState = { 12 | loadState: UITaskState 13 | isAuthenticated?: boolean 14 | hasUnseen?: boolean 15 | } 16 | 17 | export type UnseenActivityIndicatorEvent = UIEvent<{}> 18 | 19 | export type UnseenActivityIndicatorSignal = UISignal<{ type: 'not-yet' }> 20 | -------------------------------------------------------------------------------- /frontend/src/features/annotations/ui/components/annotation-box.tsx: -------------------------------------------------------------------------------- 1 | export * from '@worldbrain/memex-common/lib/content-conversations/ui/components/annotation-box' 2 | export { default } from '@worldbrain/memex-common/lib/content-conversations/ui/components/annotation-box' 3 | -------------------------------------------------------------------------------- /frontend/src/features/annotations/ui/components/annotations-in-page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import AnnotsInPage, { 3 | AnnotationsInPageProps as Props, 4 | } from '@worldbrain/memex-common/lib/content-conversations/ui/components/annotations-in-page' 5 | 6 | import ProfilePopupContainer, { 7 | ProfilePopupProps, 8 | } from '../../../user-management/ui/containers/profile-popup-container' 9 | 10 | export type { Props } 11 | 12 | const AnnotationsInPage = ({ 13 | profilePopupProps, 14 | ...props 15 | }: Omit & { 16 | profilePopupProps?: Omit 17 | }) => ( 18 | ({ children }) => ( 21 | 22 | {children} 23 | 24 | )} 25 | /> 26 | ) 27 | 28 | export default AnnotationsInPage 29 | -------------------------------------------------------------------------------- /frontend/src/features/annotations/ui/components/types.ts: -------------------------------------------------------------------------------- 1 | export * from '@worldbrain/memex-common/lib/content-conversations/ui/components/types' 2 | -------------------------------------------------------------------------------- /frontend/src/features/content-conversations/storage/index.ts: -------------------------------------------------------------------------------- 1 | import ContentConversationStorage from '@worldbrain/memex-common/lib/content-conversations/storage' 2 | export default ContentConversationStorage 3 | -------------------------------------------------------------------------------- /frontend/src/features/content-conversations/ui/components/annotation-reply.tsx: -------------------------------------------------------------------------------- 1 | export * from '@worldbrain/memex-common/lib/content-conversations/ui/components/annotation-reply' 2 | export { default } from '@worldbrain/memex-common/lib/content-conversations/ui/components/annotation-reply' 3 | -------------------------------------------------------------------------------- /frontend/src/features/content-conversations/ui/components/new-reply.tsx: -------------------------------------------------------------------------------- 1 | export * from '@worldbrain/memex-common/lib/content-conversations/ui/components/new-reply' 2 | export { default } from '@worldbrain/memex-common/lib/content-conversations/ui/components/new-reply' 3 | -------------------------------------------------------------------------------- /frontend/src/features/content-conversations/ui/types.ts: -------------------------------------------------------------------------------- 1 | export * from '@worldbrain/memex-common/lib/content-conversations/ui/types' 2 | -------------------------------------------------------------------------------- /frontend/src/features/content-conversations/ui/utils.ts: -------------------------------------------------------------------------------- 1 | export * from '@worldbrain/memex-common/lib/content-conversations/ui/utils' 2 | -------------------------------------------------------------------------------- /frontend/src/features/content-sharing/storage/index.ts: -------------------------------------------------------------------------------- 1 | import ContentSharingStorage from '@worldbrain/memex-common/lib/content-sharing/storage' 2 | export default ContentSharingStorage 3 | -------------------------------------------------------------------------------- /frontend/src/features/content-sharing/types.ts: -------------------------------------------------------------------------------- 1 | type BoolStr = 'true' | 'false' 2 | 3 | export interface ContentSharingQueryParams { 4 | key?: string 5 | /** Exists to prevent the reader automatically opening pages in the extension. */ 6 | noAutoOpen?: BoolStr 7 | annotationId?: string 8 | fromListEntry?: string 9 | toListEntry?: string 10 | fromAnnotEntry?: string 11 | toAnnotEntry?: string 12 | fromReply?: string 13 | toReply?: string 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/features/content-sharing/ui/pages/collection-details/constants.ts: -------------------------------------------------------------------------------- 1 | import { COLLECTION_DETAILS_PAGE_SIZE } from '@worldbrain/memex-common/lib/content-sharing/constants' 2 | 3 | export const PAGE_SIZE = COLLECTION_DETAILS_PAGE_SIZE 4 | -------------------------------------------------------------------------------- /frontend/src/features/content-sharing/ui/pages/page-links/types.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateServerID } from '@worldbrain/memex-common/lib/content-sharing/service/types' 2 | import type { UIEvent } from '../../../../../main-ui/classes/logic' 3 | import type { UIElementServices } from '../../../../../services/types' 4 | import type { StorageModules } from '../../../../../storage/types' 5 | 6 | export interface PageLinkCreationPageDependencies { 7 | services: UIElementServices< 8 | | 'auth' 9 | | 'router' 10 | | 'overlay' 11 | | 'pageLinks' 12 | | 'userManagement' 13 | | 'webMonetization' 14 | | 'activityStreams' 15 | | 'pdfUploadService' 16 | > 17 | storage: Pick 18 | fullPageUrl: string | null 19 | generateServerId: GenerateServerID 20 | getRootElement: () => HTMLElement 21 | } 22 | 23 | export type PageLinkCreationPageEvent = UIEvent<{}> 24 | -------------------------------------------------------------------------------- /frontend/src/features/lists-sidebar/ui/types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | SharedListReference, 3 | SharedList as SharedListBase, 4 | } from '@worldbrain/memex-common/lib/content-sharing/types' 5 | import { UITaskState } from '../../../main-ui/types' 6 | import { UIEventHandler } from '../../../main-ui/classes/logic' 7 | 8 | type SharedList = SharedListBase & { reference: SharedListReference } 9 | export interface ListsSidebarState { 10 | isListSidebarShown: boolean 11 | followedLists: SharedList[] 12 | collaborativeLists: SharedList[] 13 | listSidebarLoadState: UITaskState 14 | } 15 | 16 | export interface ListsSidebarEvent { 17 | initActivityFollows: undefined 18 | toggleListSidebar: undefined 19 | } 20 | 21 | export type ListsSidebarHandlers = { 22 | [EventName in keyof ListsSidebarEvent]: UIEventHandler< 23 | ListsSidebarState, 24 | ListsSidebarEvent, 25 | EventName 26 | > 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/features/page-links/services/index.ts: -------------------------------------------------------------------------------- 1 | import { extractIdsFromSinglePageShareUrl } from '@worldbrain/memex-common/lib/content-sharing/utils' 2 | import type { ContentSharingBackendInterface } from '@worldbrain/memex-common/lib/content-sharing/backend/types' 3 | import type { PageLinkServiceInterface } from './types' 4 | 5 | export default class PageLinkService implements PageLinkServiceInterface { 6 | constructor( 7 | private deps: { 8 | contentSharingBackend: Pick< 9 | ContentSharingBackendInterface, 10 | 'createPageLink' 11 | > 12 | }, 13 | ) {} 14 | 15 | createPageLink: PageLinkServiceInterface['createPageLink'] = async ({ 16 | fullPageUrl, 17 | uploadedPdfParams, 18 | }) => { 19 | const { link } = await this.deps.contentSharingBackend.createPageLink({ 20 | fullPageUrl, 21 | uploadedPdfParams, 22 | }) 23 | const { 24 | remoteListId, 25 | remoteListEntryId, 26 | } = extractIdsFromSinglePageShareUrl(link) 27 | return { remoteListId, remoteListEntryId } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /frontend/src/features/page-links/services/types.ts: -------------------------------------------------------------------------------- 1 | import type { AutoPk } from '@worldbrain/memex-common/lib/storage/types' 2 | 3 | export interface PageLinkServiceInterface { 4 | createPageLink: (options: { 5 | fullPageUrl: string 6 | uploadedPdfParams?: { 7 | uploadId: string 8 | fingerprints: string[] 9 | title: string 10 | } 11 | }) => Promise<{ 12 | remoteListId: AutoPk 13 | remoteListEntryId: AutoPk 14 | }> 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/features/personal-cloud/storage/index.ts: -------------------------------------------------------------------------------- 1 | import PersonalCloudStorage from '@worldbrain/memex-common/lib/personal-cloud/storage' 2 | export default PersonalCloudStorage 3 | -------------------------------------------------------------------------------- /frontend/src/features/reader/ui/components/Sidebar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components' 3 | 4 | export function Sidebar() { 5 | return 6 | } 7 | 8 | export const Container = styled.div` 9 | height: 100%; 10 | width: 300px; 11 | position: fixed; 12 | top: 0; 13 | right: 0; 14 | bottom: 0; 15 | background-color: #333333; 16 | z-index: 9999; 17 | ` 18 | -------------------------------------------------------------------------------- /frontend/src/features/reader/ui/components/Toolbar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components' 3 | 4 | export function Toolbar() { 5 | return ( 6 | 7 |

Example text

8 |
9 | ) 10 | } 11 | 12 | export const ToolbarWrapper = styled.div` 13 | height: 80px; 14 | width: 100%; 15 | position: fixed; 16 | top: 0; 17 | left: 0; 18 | right: 0; 19 | background-color: #333333; 20 | z-index: 9999; 21 | ` 22 | -------------------------------------------------------------------------------- /frontend/src/features/reader/utils/api.ts: -------------------------------------------------------------------------------- 1 | import { CLOUDFLARE_WORKER_URLS } from '@worldbrain/memex-common/lib/content-sharing/storage/constants' 2 | import { determineEnv } from '../../../utils/runtime-environment' 3 | 4 | export const ARCHIVE_PROXY_URL = 5 | determineEnv() === 'production' 6 | ? CLOUDFLARE_WORKER_URLS.production 7 | : CLOUDFLARE_WORKER_URLS.staging 8 | 9 | async function fetchAndHandleErrors(url: string): Promise { 10 | const response = await fetch(url) 11 | if (!response.ok) { 12 | throw new Error( 13 | `Page fetch failed with HTTP code ${response.status}: ${response.statusText}`, 14 | ) 15 | } 16 | return response 17 | } 18 | 19 | export const fetchWebsiteHTML = async ( 20 | originalUrl: string, 21 | ): Promise => { 22 | const response = await fetchAndHandleErrors( 23 | `${ARCHIVE_PROXY_URL}/webarchive?url=${encodeURIComponent( 24 | originalUrl, 25 | )}`, 26 | ) 27 | const html = await response.text() 28 | return html 29 | } 30 | -------------------------------------------------------------------------------- /frontend/src/features/reader/utils/iframe.ts: -------------------------------------------------------------------------------- 1 | import { highlightDOMRange } from '@worldbrain/memex-common/lib/annotations/highlight-dom-range' 2 | 3 | export interface IframMessageHandlers { 4 | sendMessageFromIframe(message: string): void 5 | } 6 | 7 | export const setupIframeComms = (handlers: IframMessageHandlers) => { 8 | ;(window as any).injected = { 9 | ...handlers, 10 | highlightDOMRange, 11 | } 12 | 13 | return { 14 | cleanup: () => { 15 | delete (window as any).injected 16 | }, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/features/user-management/storage/index.ts: -------------------------------------------------------------------------------- 1 | import UserStorage from '@worldbrain/memex-common/lib/user-management/storage' 2 | export default UserStorage 3 | -------------------------------------------------------------------------------- /frontend/src/features/user-management/types.ts: -------------------------------------------------------------------------------- 1 | import { UserReference as UserRef } from '@worldbrain/memex-common/lib/web-interface/types/users' 2 | import { 3 | UserPublicProfile as Profile, 4 | User as ImportedUser, 5 | } from '@worldbrain/memex-common/ts/web-interface/types/storex-generated/user-management' 6 | import { IconKeys } from '@worldbrain/memex-common/lib/common-ui/styles/types' 7 | 8 | export type UserPublicProfile = Profile 9 | export type User = ImportedUser 10 | export type UserReference = UserRef 11 | 12 | export type ProfileWebLinkLabel = 'Website' | 'Medium' | 'Twitter' | 'Substack' 13 | export type ProfileWebLinkName = 14 | | 'websiteURL' 15 | | 'mediumURL' 16 | | 'twitterURL' 17 | | 'substackURL' 18 | export interface ProfileWebLink { 19 | urlPropName: ProfileWebLinkName 20 | label: ProfileWebLinkLabel 21 | url: string 22 | icon: IconKeys 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/features/user-management/ui/containers/account-settings-dialog/types.ts: -------------------------------------------------------------------------------- 1 | import { UIEvent, UISignal } from '../../../../../main-ui/classes/logic' 2 | import { UIElementServices } from '../../../../../services/types' 3 | import { StorageModules } from '../../../../../storage/types' 4 | import { UITaskState } from '../../../../../main-ui/types' 5 | 6 | export interface AccountSettingsDependencies { 7 | services: UIElementServices<'auth' | 'overlay'> 8 | storage: Pick 9 | onCloseRequested(): void 10 | } 11 | 12 | export interface AccountSettingsState { 13 | loadState: UITaskState 14 | displayName?: string 15 | } 16 | 17 | export type AccountSettingsEvent = UIEvent<{}> 18 | 19 | export type AccountSettingsSignal = UISignal<{ type: 'nothing-yet' }> 20 | -------------------------------------------------------------------------------- /frontend/src/features/user-management/ui/containers/auth-header/types.ts: -------------------------------------------------------------------------------- 1 | import { UIEvent, UISignal } from '../../../../../main-ui/classes/logic' 2 | import { UIElementServices } from '../../../../../services/types' 3 | import { User } from '@worldbrain/memex-common/lib/web-interface/types/users' 4 | import { UITaskState } from '../../../../../main-ui/types' 5 | 6 | export interface AuthHeaderDependencies { 7 | services: UIElementServices<'auth' | 'overlay' | 'userManagement'> 8 | getRootElement: () => HTMLElement 9 | } 10 | 11 | export interface AuthHeaderState { 12 | loadState: UITaskState 13 | user: Pick | null 14 | showMenu: boolean 15 | showSettings: boolean 16 | showAccountSettings: boolean 17 | isMemexInstalled: boolean 18 | } 19 | 20 | export type AuthHeaderEvent = UIEvent<{ 21 | toggleMenu: null 22 | hideMenu: null 23 | showSettings: null 24 | hideSettings: null 25 | showAccountSettings: null 26 | hideAccountSettings: null 27 | login: null 28 | logout: null 29 | }> 30 | 31 | export type AuthHeaderSignal = UISignal<{ type: 'nothing-yet' }> 32 | -------------------------------------------------------------------------------- /frontend/src/features/user-management/ui/containers/curator-support-popup-container/logic.ts: -------------------------------------------------------------------------------- 1 | import ProfilePopupLogic from '../profile-popup-container/logic' 2 | 3 | export default class CuratorSupportPopupContainerLogic extends ProfilePopupLogic {} 4 | -------------------------------------------------------------------------------- /frontend/src/features/user-management/ui/containers/curator-support-popup-container/types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ProfilePopupContainerDependencies, 3 | ProfilePopupContainerState, 4 | ProfilePopupContainerEvent, 5 | } from '../profile-popup-container/types' 6 | 7 | export type CuratorSupportPopupDependencies = ProfilePopupContainerDependencies 8 | export type CuratorSupportPopupState = ProfilePopupContainerState 9 | export type CuratorSupportPopupEvent = ProfilePopupContainerEvent 10 | -------------------------------------------------------------------------------- /frontend/src/features/user-management/ui/containers/profile-popup-container/index.test.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/features/user-management/ui/containers/profile-popup-container/index.test.ts -------------------------------------------------------------------------------- /frontend/src/features/user-management/ui/containers/profile-popup-container/types.ts: -------------------------------------------------------------------------------- 1 | import { UIEvent } from '../../../../../main-ui/classes/logic' 2 | import { UIElementServices } from '../../../../../services/types' 3 | import { 4 | UserReference, 5 | UserPublicProfile, 6 | User, 7 | ProfileWebLink, 8 | } from '../../../types' 9 | import { UITaskState } from '../../../../../main-ui/types' 10 | 11 | export interface ProfilePopupContainerDependencies { 12 | services: UIElementServices< 13 | | 'device' 14 | | 'documentTitle' 15 | | 'logicRegistry' 16 | | 'userManagement' 17 | | 'webMonetization' 18 | > 19 | userRef: UserReference | null 20 | } 21 | 22 | export interface ProfilePopupContainerState { 23 | isDisplayed: boolean 24 | loadState: UITaskState 25 | user: User 26 | userPublicProfile: UserPublicProfile | null 27 | profileLinks: ProfileWebLink[] 28 | } 29 | 30 | export type ProfilePopupContainerEvent = UIEvent<{ 31 | initPopup: null 32 | hidePopup: null 33 | initCuratorSupport: null 34 | }> 35 | -------------------------------------------------------------------------------- /frontend/src/features/web-monetization/logic/buttons/types.ts: -------------------------------------------------------------------------------- 1 | import { UIEvent } from '../../../../main-ui/classes/logic' 2 | import { UIElementServices } from '../../../../services/types' 3 | import { UITaskState } from '../../../../main-ui/types' 4 | import { UserReference } from '../../../user-management/types' 5 | 6 | export interface WebMonetizationButtonDependencies { 7 | services: UIElementServices< 8 | 'userManagement' | 'webMonetization' | 'documentTitle' 9 | > 10 | curatorUserRef: UserReference 11 | isFollowedSpace?: boolean 12 | getRootElement: () => HTMLElement 13 | } 14 | 15 | export interface WebMonetizationButtonState { 16 | loadState: UITaskState 17 | paymentState: UITaskState 18 | isDisplayed: boolean 19 | isMonetizationAvailable: boolean 20 | paymentMade: boolean 21 | curatorPaymentPointer: string 22 | } 23 | 24 | export type WebMonetizationButtonEvent = UIEvent<{ 25 | makeSupporterPayment: null 26 | showPopup: null 27 | hidePopup: null 28 | }> 29 | -------------------------------------------------------------------------------- /frontend/src/features/web-monetization/service/firebase/index.ts: -------------------------------------------------------------------------------- 1 | import WebMonetizationBase from '..' 2 | 3 | export default class FirebaseWebMonetizationService extends WebMonetizationBase {} 4 | -------------------------------------------------------------------------------- /frontend/src/features/web-monetization/service/memory/index.ts: -------------------------------------------------------------------------------- 1 | import WebMonetizationBase from '../' 2 | 3 | export default class MemoryWebMonetizationService extends WebMonetizationBase { 4 | initiatePayment(paymentPointer: string): void { 5 | this.events.emit('monetizationstart', { 6 | paymentPointer, 7 | requestId: 'bar', 8 | }) 9 | setTimeout(() => { 10 | this.events.emit('monetizationstop', { 11 | paymentPointer, 12 | requestId: 'bar', 13 | finalized: true, 14 | }) 15 | }, 1000) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/features/web-monetization/ui/components/web-monetization-icon/logic.ts: -------------------------------------------------------------------------------- 1 | import WebMonetizationButtonLogic from '../../../logic/buttons/logic' 2 | 3 | export default class WebMonetizationIconLogic extends WebMonetizationButtonLogic {} 4 | -------------------------------------------------------------------------------- /frontend/src/features/web-monetization/ui/containers/curator-support-button-block/logic.ts: -------------------------------------------------------------------------------- 1 | import WebMonetizationButtonLogic from '../../../logic/buttons/logic' 2 | 3 | export default class CuratorSupportButtonBlockLogic extends WebMonetizationButtonLogic {} 4 | -------------------------------------------------------------------------------- /frontend/src/index.tsx: -------------------------------------------------------------------------------- 1 | import queryString from 'query-string' 2 | import { main } from './main' 3 | import { BackendType } from './types' 4 | 5 | main({ 6 | backend: process.env['REACT_APP_BACKEND'] as BackendType, 7 | logLogicEvents: process.env['REACT_APP_LOG_LOGIC'] === 'true', 8 | queryParams: queryString.parse(window.location.search), 9 | }) 10 | -------------------------------------------------------------------------------- /frontend/src/main-ui/classes/events.ts: -------------------------------------------------------------------------------- 1 | export { EventHandlers } from '@worldbrain/memex-common/lib/main-ui/classes/events' 2 | export type { EventHandler } from '@worldbrain/memex-common/lib/main-ui/classes/events' 3 | -------------------------------------------------------------------------------- /frontend/src/main-ui/classes/index.tsx: -------------------------------------------------------------------------------- 1 | export { UIElement } from '@worldbrain/memex-common/lib/main-ui/classes' 2 | -------------------------------------------------------------------------------- /frontend/src/main-ui/classes/logic.ts: -------------------------------------------------------------------------------- 1 | export { 2 | mergeTaskStates, 3 | loadInitial, 4 | executeUITask, 5 | UILogic, 6 | } from '@worldbrain/memex-common/lib/main-ui/classes/logic' 7 | export type { 8 | UIEvent, 9 | UIMutation, 10 | UIEventHandler, 11 | UISignal, 12 | } from '@worldbrain/memex-common/lib/main-ui/classes/logic' 13 | -------------------------------------------------------------------------------- /frontend/src/main-ui/components/route-link/logic.ts: -------------------------------------------------------------------------------- 1 | import { UILogic, UIEvent } from '../../classes/logic' 2 | 3 | export interface State {} 4 | export type Event = UIEvent<{}> 5 | 6 | export default class Logic extends UILogic { 7 | getInitialState(): State { 8 | return {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/main-ui/containers/app/logic.ts: -------------------------------------------------------------------------------- 1 | import { UILogic, UIEvent } from '../../classes/logic' 2 | 3 | interface State {} 4 | type Event = UIEvent<{}> 5 | 6 | export default class Logic extends UILogic { 7 | getInitialState() { 8 | return {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/main-ui/containers/overlay/index.tsx: -------------------------------------------------------------------------------- 1 | export { 2 | default, 3 | OverlayContainer, 4 | } from '@worldbrain/memex-common/lib/main-ui/containers/overlay' 5 | export type { OverlayProps } from '@worldbrain/memex-common/lib/main-ui/containers/overlay' 6 | -------------------------------------------------------------------------------- /frontend/src/main-ui/messages.ts: -------------------------------------------------------------------------------- 1 | type Message = string 2 | type Messages = { [id: string]: Message } 3 | 4 | const MESSAGES: Messages = { 5 | 'landing-intro-header': 6 | 'Engage with your communities, prioritize what you care about', 7 | 'landing-intro-body': ` 8 | A social network created for people who want help each other and make a positive change in the world, 9 | but already have too many things asking their attention. 10 | `, 11 | 'landing-intro-1': 'Help and be helped with social projects you care about', 12 | 'landing-intro-2': 'Receive only the updates you care about, how you want', 13 | 'landing-intro-3': ' ', 14 | } 15 | 16 | export default MESSAGES 17 | -------------------------------------------------------------------------------- /frontend/src/main-ui/pages/not-found/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | class NotFound extends Component { 4 | render() { 5 | return
Uh oh, page not found....
6 | } 7 | } 8 | 9 | export default NotFound 10 | -------------------------------------------------------------------------------- /frontend/src/main-ui/pages/user-home/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Storage } from '../../../storage/types' 3 | import { UIElement } from '../../classes' 4 | import { UIElementServices } from '../../../services/types' 5 | import Logic, { State, Event } from './logic' 6 | 7 | interface Props { 8 | storage: Storage 9 | services: UIElementServices<'auth' | 'router'> 10 | } 11 | 12 | export default class UserHome extends UIElement { 13 | constructor(props: Props) { 14 | super(props, { logic: new Logic(props) }) 15 | } 16 | 17 | render() { 18 | const user = this.props.services.auth.getCurrentUser() 19 | if (!user) { 20 | throw new Error('User home activated without active user') 21 | } 22 | if (!user.displayName) { 23 | throw new Error('User has no display name') 24 | } 25 | 26 | return
27 | } 28 | } 29 | -------------------------------------------------------------------------------- /frontend/src/main-ui/pages/user-home/logic.ts: -------------------------------------------------------------------------------- 1 | import { UILogic, UIEvent, loadInitial } from '../../classes/logic' 2 | import { Storage } from '../../../storage/types' 3 | import { Services } from '../../../services/types' 4 | import { UITaskState } from '../../types' 5 | 6 | export interface State { 7 | loadState: UITaskState 8 | } 9 | export type Event = UIEvent<{}> 10 | 11 | export default class Logic extends UILogic { 12 | constructor( 13 | private options: { 14 | services: Pick 15 | storage: Storage 16 | }, 17 | ) { 18 | super() 19 | } 20 | 21 | getInitialState(): State { 22 | return { 23 | loadState: 'pristine', 24 | } 25 | } 26 | 27 | async processInit() { 28 | await loadInitial(this, async () => { 29 | const user = this.options.services.auth.getCurrentUser() 30 | if (!user) { 31 | throw new Error( 32 | `Tried to access user home page without logged in user`, 33 | ) 34 | } 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /frontend/src/main-ui/styles/global.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components' 2 | import { theme } from './theme' 3 | 4 | const GlobalStyle = createGlobalStyle` 5 | 6 | 7 | 8 | html { 9 | width: 100%; 10 | 11 | margin: 0; 12 | background: ${theme.colors.black}; 13 | } 14 | 15 | body { 16 | width: 100%; 17 | height: 100vh; 18 | overflow: none; 19 | 20 | margin: 0; 21 | background: ${theme.colors.black}; 22 | 23 | scrollbar-width: none; 24 | 25 | &::-webkit-scrollbar { 26 | display: none; 27 | } 28 | } 29 | 30 | body, input, button { 31 | font-family: monospace; 32 | } 33 | 34 | * { 35 | box-sizing: border-box; 36 | } 37 | 38 | } 39 | ` 40 | 41 | export default GlobalStyle 42 | -------------------------------------------------------------------------------- /frontend/src/main-ui/styles/icons.tsx: -------------------------------------------------------------------------------- 1 | export const logo = '/img/open.svg' 2 | -------------------------------------------------------------------------------- /frontend/src/main-ui/styles/types.ts: -------------------------------------------------------------------------------- 1 | export type { 2 | MemexTheme as Theme, 3 | ViewportBreakpoint, 4 | } from '@worldbrain/memex-common/lib/common-ui/styles/types' 5 | -------------------------------------------------------------------------------- /frontend/src/main-ui/styles/utils.ts: -------------------------------------------------------------------------------- 1 | export { getViewportBreakpoint } from '@worldbrain/memex-common/lib/common-ui/styles/utils' 2 | -------------------------------------------------------------------------------- /frontend/src/main-ui/types/index.ts: -------------------------------------------------------------------------------- 1 | import type * as history from 'history' 2 | import type { GenerateServerID } from '@worldbrain/memex-common/lib/content-sharing/service/types' 3 | import type { Services } from '../../services/types' 4 | import type { Storage } from '../../storage/types' 5 | import { ImageSupportInterface } from '@worldbrain/memex-common/lib/image-support/types' 6 | 7 | export type { UITaskState } from '@worldbrain/memex-common/lib/main-ui/types' 8 | 9 | export interface UIRunnerOptions { 10 | services: Services 11 | storage: Storage 12 | history: history.History 13 | generateServerId: GenerateServerID 14 | imageSupport: ImageSupportInterface 15 | getRootElement: () => HTMLElement 16 | } 17 | 18 | export type UIRunner = (options: UIRunnerOptions) => Promise 19 | -------------------------------------------------------------------------------- /frontend/src/rpc/types.ts: -------------------------------------------------------------------------------- 1 | import { ProgramQueryParams } from '../setup/types' 2 | 3 | export interface DevelopmentRpcInterface { 4 | run(options: { queryParams: ProgramQueryParams }): Promise 5 | stepWalkthrough(): Promise 6 | } 7 | export type DevelopmentRpcRequest = { func: string; args: any[] } 8 | export type DevelopmentRpcResponse = { success: boolean; data: any } 9 | -------------------------------------------------------------------------------- /frontend/src/scenarios/landing-page.ts: -------------------------------------------------------------------------------- 1 | import { ScenarioMap } from '../services/scenarios/types' 2 | import { LandingPageEvent } from '../main-ui/pages/landing-page/types' 3 | import { scenario } from '../services/scenarios/utils' 4 | 5 | type Targets = { 6 | LandingPage: { 7 | events: LandingPageEvent 8 | } 9 | } 10 | 11 | export const SCENARIOS: ScenarioMap = { 12 | default: scenario(({ step }) => ({ 13 | startRoute: { route: 'landingPage' }, 14 | steps: [ 15 | step({ 16 | name: 'first-toggle', 17 | target: 'LandingPage', 18 | eventName: 'toggle', 19 | eventArgs: {}, 20 | }), 21 | step({ 22 | name: 'second-toggle', 23 | target: 'LandingPage', 24 | eventName: 'toggle', 25 | eventArgs: {}, 26 | }), 27 | ], 28 | })), 29 | } 30 | -------------------------------------------------------------------------------- /frontend/src/services/analytics.ts: -------------------------------------------------------------------------------- 1 | export class AnalyticsService { 2 | trackEvent(eventName: string, eventId: string) { 3 | const fathom = (globalThis as any)['fathom'] 4 | if (fathom) { 5 | fathom.trackGoal(eventId, 0) 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/services/clipboard/index.ts: -------------------------------------------------------------------------------- 1 | import type { ClipboardServiceInterface } from '@worldbrain/memex-common/lib/services/clipboard/types' 2 | import type { ClipboardServiceDependencies as Dependencies } from './types' 3 | 4 | export default class ClipboardService implements ClipboardServiceInterface { 5 | constructor(private dependencies: Dependencies) {} 6 | 7 | async copy(text: string) { 8 | await this.dependencies.clipboard.writeText(text) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/services/clipboard/mock.ts: -------------------------------------------------------------------------------- 1 | import type { ClipboardServiceDependencies } from './types' 2 | 3 | export const mockClipboardAPI: ClipboardServiceDependencies['clipboard'] = { 4 | writeText: async (text) => 5 | console.log('Clipboard Service - received text copy request:', text), 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/services/clipboard/types.ts: -------------------------------------------------------------------------------- 1 | export interface ClipboardServiceDependencies { 2 | clipboard: Pick 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/services/device/index.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'events' 2 | import type { 3 | DeviceServiceInterface, 4 | RectSize, 5 | } from '@worldbrain/memex-common/lib/services/device/types' 6 | 7 | export class DeviceService implements DeviceServiceInterface { 8 | events = new EventEmitter() 9 | private cachedRootSize: RectSize 10 | 11 | constructor( 12 | private options: { 13 | rootElement: { clientWidth: number; clientHeight: number } 14 | }, 15 | ) { 16 | this.cachedRootSize = this.calculateRootSize() 17 | } 18 | 19 | get rootSize(): RectSize { 20 | return this.cachedRootSize 21 | } 22 | 23 | processRootResize() { 24 | this.cacheRootSize() 25 | this.events.emit('rootResize') 26 | } 27 | 28 | private cacheRootSize() { 29 | this.cachedRootSize = this.calculateRootSize() 30 | } 31 | 32 | private calculateRootSize(): RectSize { 33 | return { 34 | width: this.options.rootElement?.clientWidth, 35 | height: this.options.rootElement?.clientHeight, 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /frontend/src/services/device/types.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WorldBrain/Memex-Social/649d681889191b5b4a4f059a3a0919ae5c5b438b/frontend/src/services/device/types.ts -------------------------------------------------------------------------------- /frontend/src/services/fixtures/types.ts: -------------------------------------------------------------------------------- 1 | export interface Fixture { 2 | extends?: string | string[] 3 | objects: { [collection: string]: any[] } 4 | } 5 | export type FixtureFetcher = (name: string) => Promise 6 | -------------------------------------------------------------------------------- /frontend/src/services/full-text-search.ts: -------------------------------------------------------------------------------- 1 | import { 2 | SharedListEntrySearchRequest, 3 | SharedListEntrySearchResponse, 4 | SHARED_LIST_ENTRY_SEARCH_ROUTE, 5 | } from '@worldbrain/memex-common/lib/content-sharing/search' 6 | import { CLOUDFLARE_WORKER_URLS } from '@worldbrain/memex-common/lib/content-sharing/storage/constants' 7 | import { determineEnv } from '../utils/runtime-environment' 8 | 9 | export class FullTextSearchService { 10 | async searchListEntries( 11 | request: SharedListEntrySearchRequest, 12 | ): Promise { 13 | const baseUrl = 14 | determineEnv() === 'production' 15 | ? CLOUDFLARE_WORKER_URLS.production 16 | : CLOUDFLARE_WORKER_URLS.staging 17 | const response = await fetch( 18 | `${baseUrl}${SHARED_LIST_ENTRY_SEARCH_ROUTE}`, 19 | { 20 | method: 'POST', 21 | headers: { 22 | 'Content-Type': 'application/json', 23 | }, 24 | body: JSON.stringify(request), 25 | }, 26 | ) 27 | return (await response.json()) as SharedListEntrySearchResponse 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /frontend/src/services/local-storage/browser.ts: -------------------------------------------------------------------------------- 1 | import { LocalStorageService } from './types' 2 | import { LimitedWebStorage } from '../../utils/web-storage/types' 3 | 4 | export class BrowserLocalStorageService implements LocalStorageService { 5 | constructor(private localStorage: LimitedWebStorage) {} 6 | 7 | getItem(key: string) { 8 | return this.localStorage.getItem(key) 9 | } 10 | 11 | setItem(key: string, value: string) { 12 | this.localStorage.setItem(key, value) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/services/local-storage/memory.ts: -------------------------------------------------------------------------------- 1 | import { LocalStorageService } from './types' 2 | 3 | export class MemoryLocalStorageService implements LocalStorageService { 4 | _items: { [key: string]: string } = {} 5 | 6 | getItem(key: string) { 7 | return this._items[key] ?? null 8 | } 9 | 10 | setItem(key: string, value: string) { 11 | this._items[key] = value 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/services/local-storage/types.ts: -------------------------------------------------------------------------------- 1 | export interface LocalStorageService { 2 | getItem(key: string): string | null 3 | setItem(key: string, value: string): void 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/services/logic-registry/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from '@worldbrain/memex-common/lib/services/logic-registry' 2 | -------------------------------------------------------------------------------- /frontend/src/services/overlay/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from '@worldbrain/memex-common/lib/services/overlay' 2 | -------------------------------------------------------------------------------- /frontend/src/services/summarization.ts: -------------------------------------------------------------------------------- 1 | import { CLOUDFLARE_WORKER_URLS } from '@worldbrain/memex-common/lib/content-sharing/storage/constants' 2 | import { determineEnv } from '../utils/runtime-environment' 3 | 4 | export class SummarizationService { 5 | async summarize(originalUrl: string) { 6 | const baseUrl = 7 | determineEnv() === 'production' 8 | ? CLOUDFLARE_WORKER_URLS.production 9 | : CLOUDFLARE_WORKER_URLS.staging 10 | const url = `${baseUrl}/summarize` 11 | const response = await fetch(url, { 12 | method: 'POST', 13 | headers: { 14 | 'Content-Type': 'application/json', 15 | }, 16 | body: JSON.stringify({ 17 | originalUrl, 18 | }), 19 | }) 20 | 21 | return (await response.json()) as 22 | | { status: 'success'; choices: Array<{ text: string }> } 23 | | { status: 'prompt-too-long' } 24 | | { status: 'unknown-error' } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/storage/checks.ts: -------------------------------------------------------------------------------- 1 | import { AccountCollectionInfoMap } from './constants' 2 | import { StorageRegistry } from '@worldbrain/storex' 3 | import { collectAccountCollections } from './utils' 4 | 5 | export function checkAccountCollectionInfoMap(options: { 6 | accountCollections: AccountCollectionInfoMap 7 | storageRegistry: StorageRegistry 8 | }) { 9 | const accountCollections = collectAccountCollections( 10 | options.storageRegistry, 11 | ) 12 | const collectionsWithAccountInfo = new Set( 13 | Object.keys(options.accountCollections), 14 | ) 15 | const collectionsMissingAccountInfo = new Set( 16 | Object.keys(accountCollections).filter( 17 | (collection) => !collectionsWithAccountInfo.has(collection), 18 | ), 19 | ) 20 | if (collectionsMissingAccountInfo.size > 0) { 21 | throw new Error( 22 | `We don't have account collection info on the following collections which should have it: ` + 23 | [...collectionsMissingAccountInfo].join(', '), 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/storage/constants.ts: -------------------------------------------------------------------------------- 1 | export type AccountCollectionInfoMap = { 2 | [collection: string]: AccountCollectionInfo 3 | } 4 | export interface AccountCollectionInfo { 5 | onAccountDelete: 'delete' | 'ignore' 6 | } 7 | 8 | export const ACCOUNT_COLLECTIONS: AccountCollectionInfoMap = { 9 | userEmail: { 10 | onAccountDelete: 'delete', 11 | }, 12 | userRight: { 13 | onAccountDelete: 'delete', 14 | }, 15 | projectSubscription: { 16 | onAccountDelete: 'delete', 17 | }, 18 | projectSubscriptionConfiguration: { 19 | onAccountDelete: 'delete', 20 | }, 21 | projectMembership: { 22 | onAccountDelete: 'delete', 23 | }, 24 | sharedList: { 25 | onAccountDelete: 'delete', 26 | }, 27 | sharedListEntry: { 28 | onAccountDelete: 'delete', 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /frontend/src/stories/0-Welcome.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { linkTo } from '@storybook/addon-links' 3 | import { Welcome } from '@storybook/react/demo' 4 | 5 | export default { 6 | title: 'Welcome', 7 | component: Welcome, 8 | } 9 | 10 | export const ToStorybook = () => 11 | 12 | ToStorybook.story = { 13 | name: 'to Storybook', 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/styled-components.d.ts: -------------------------------------------------------------------------------- 1 | import type { MemexTheme } from '@worldbrain/memex-common/lib/common-ui/styles/types' 2 | 3 | declare module 'styled-components' { 4 | export interface DefaultTheme extends MemexTheme {} 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/types/auth.ts: -------------------------------------------------------------------------------- 1 | export type AuthProvider = 'facebook' | 'google' | 'github' | 'twitter' 2 | -------------------------------------------------------------------------------- /frontend/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type BackendType = 'memory' | 'firebase' | 'firebase-emulator' 2 | export type AutoPk = number | string 3 | -------------------------------------------------------------------------------- /frontend/src/utils/memex-installed.ts: -------------------------------------------------------------------------------- 1 | import { DETECTION_EL_ID } from '@worldbrain/memex-common/lib/common-ui/utils/content-script' 2 | 3 | export const isMemexInstalled = () => { 4 | if (document.getElementById(DETECTION_EL_ID)) { 5 | return true 6 | } else { 7 | return false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/utils/monkey-patch.ts: -------------------------------------------------------------------------------- 1 | export function monkeyPatchGlobals() { 2 | // Webpack v5 removed node stdlib polyfilling, which included node globals like process. 3 | // One dep of a dep (react-markdown -> ... -> vfile) assumes `process.cwd` is defined and 4 | // my attempts at setting that via webpack (ProvidePlugin, DefinePlugin, aliases) failed. 5 | globalThis['process'] = { 6 | cwd: () => '/', 7 | env: { ...process.env }, // This should be defined via webpack's DefinePlugin 8 | } as any 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/utils/promises.ts: -------------------------------------------------------------------------------- 1 | export function sleepPromise(miliseconds: number) { 2 | return new Promise((resolve) => setTimeout(resolve, miliseconds)) 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/utils/runtime-environment.ts: -------------------------------------------------------------------------------- 1 | export function determineEnv(): 'staging' | 'production' | 'testing' { 2 | const { NODE_ENV, REACT_APP_FIREBASE_PROJECT_ID } = process.env 3 | if ( 4 | REACT_APP_FIREBASE_PROJECT_ID === 'worldbrain-staging' || 5 | NODE_ENV === 'development' 6 | ) { 7 | return 'staging' 8 | } 9 | if ( 10 | REACT_APP_FIREBASE_PROJECT_ID === 'worldbrain-1057' || 11 | NODE_ENV === 'production' 12 | ) { 13 | return 'production' 14 | } 15 | return 'testing' 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/utils/string.ts: -------------------------------------------------------------------------------- 1 | const externalSlugify = require('slugify') 2 | 3 | export function capitalize(s: string) { 4 | return s.charAt(0).toUpperCase() + s.substring(1) 5 | } 6 | 7 | export function slugify(s: string) { 8 | return externalSlugify(s, { 9 | lower: true, 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/utils/translation.ts: -------------------------------------------------------------------------------- 1 | export function shouldTranslate(message: string): string { 2 | return message 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/utils/web-storage/index.ts: -------------------------------------------------------------------------------- 1 | import { LimitedWebStorage } from './types' 2 | 3 | export class MemoryLocalStorage implements LimitedWebStorage { 4 | private items: { [key: string]: string } = {} 5 | private changes: Array< 6 | | { type: 'set'; key: string; value: string } 7 | | { type: 'remove'; key: string } 8 | > = [] 9 | 10 | setItem(key: string, value: string) { 11 | this.changes.push({ type: 'set', key, value }) 12 | this.items[key] = value 13 | } 14 | 15 | getItem(key: string) { 16 | return this.items[key] 17 | } 18 | 19 | removeItem(key: string) { 20 | this.changes.push({ type: 'remove', key }) 21 | delete this.items[key] 22 | } 23 | 24 | popChanges() { 25 | const changes = this.changes 26 | this.changes = [] 27 | return changes 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /frontend/src/utils/web-storage/types.ts: -------------------------------------------------------------------------------- 1 | export interface LimitedWebStorage { 2 | setItem: WindowLocalStorage['localStorage']['setItem'] 3 | getItem: WindowLocalStorage['localStorage']['getItem'] 4 | removeItem: WindowLocalStorage['localStorage']['removeItem'] 5 | } 6 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "types": ["node", "webpack-env", "mocha"], 6 | "allowJs": true, 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "downlevelIteration": true, 17 | "noEmit": true, 18 | "jsx": "react" 19 | }, 20 | "include": ["src"] 21 | } 22 | -------------------------------------------------------------------------------- /frontend/webpack/helpers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Are we in development mode? 3 | */ 4 | function inDev() { 5 | return process.env.NODE_ENV == 'development' 6 | } 7 | 8 | // Export helpers 9 | module.exports = { 10 | inDev, 11 | } 12 | -------------------------------------------------------------------------------- /frontend/webpack/resolve.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const jsdomPath = path.resolve( 4 | __dirname, 5 | '../../external/@worldbrain/memex-common', 6 | 'node_modules/jsdom', 7 | ) 8 | module.exports = { 9 | extensions: ['.js', '.ts', '.jsx', '.tsx', '.css'], 10 | fallback: { 11 | buffer: require.resolve('buffer/'), 12 | path: require.resolve('path-browserify'), 13 | url: require.resolve('url/'), 14 | util: require.resolve('util/'), 15 | // These are all used by `jsdom` which Memex Social frontend doesn't actually use 16 | fs: false, 17 | os: false, 18 | net: false, 19 | tls: false, 20 | http: false, 21 | zlib: false, 22 | https: false, 23 | stream: false, 24 | crypto: false, 25 | assert: false, 26 | process: false, 27 | perf_hooks: false, 28 | child_process: false, 29 | }, 30 | alias: { 31 | react: require.resolve('react'), 32 | 'react-dom': require.resolve('react-dom'), 33 | 'styled-components': require.resolve('styled-components'), 34 | [jsdomPath]: false, 35 | }, 36 | } 37 | -------------------------------------------------------------------------------- /frontend/webpack/webpack.common.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | mode: 'development', 5 | entry: ['./src/index.tsx'], 6 | module: { 7 | rules: require('./rules'), 8 | }, 9 | output: { 10 | filename: '[name].[contenthash].js', 11 | chunkFilename: '[name].[contenthash].chunk.js', 12 | path: path.resolve(__dirname, '../build'), 13 | publicPath: '/', 14 | }, 15 | plugins: require('./plugins'), 16 | resolve: require('./resolve'), 17 | stats: 'errors-warnings', 18 | devtool: 'cheap-module-source-map', 19 | devServer: { 20 | port: 3000, 21 | // open: true, 22 | historyApiFallback: true, 23 | }, 24 | optimization: { 25 | splitChunks: { 26 | chunks: 'all', 27 | }, 28 | }, 29 | performance: { 30 | hints: false, 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /frontend/webpack/webpack.dev.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV ?? 'development' 2 | 3 | const { merge } = require('webpack-merge') 4 | const common = require('./webpack.common') 5 | 6 | module.exports = merge(common, { 7 | mode: 'development', 8 | devtool: 'cheap-module-source-map', 9 | devServer: { 10 | port: 3000, 11 | // open: true, 12 | historyApiFallback: true, 13 | }, 14 | optimization: { 15 | splitChunks: { 16 | chunks: 'all', 17 | }, 18 | }, 19 | performance: { 20 | hints: false, 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /frontend/webpack/webpack.prod.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV ?? 'production' 2 | 3 | const { merge } = require('webpack-merge') 4 | const common = require('./webpack.common') 5 | 6 | module.exports = merge(common, { 7 | mode: 'production', 8 | output: { 9 | clean: true, 10 | }, 11 | optimization: { 12 | minimize: true, 13 | sideEffects: true, 14 | concatenateModules: true, 15 | runtimeChunk: 'single', 16 | splitChunks: { 17 | chunks: 'all', 18 | maxInitialRequests: 10, 19 | minSize: 0, 20 | cacheGroups: { 21 | vendor: { 22 | name: 'vendors', 23 | test: /[\\/]node_modules[\\/]/, 24 | chunks: 'all', 25 | }, 26 | }, 27 | }, 28 | }, 29 | }) 30 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "independent", 3 | "npmClient": "yarn", 4 | "command": { 5 | "publish": { 6 | "ignoreChanges": ["ignored-file"], 7 | "message": "chore(release): publish" 8 | }, 9 | "bootstrap": { 10 | "npmClientArgs": ["--no-package-lock"] 11 | } 12 | }, 13 | "packages": [ 14 | "external/*", 15 | "external/@worldbrain/*", 16 | "frontend", 17 | "firebase/functions" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "allowSyntheticDefaultImports": true, 8 | "esModuleInterop": true, 9 | "removeComments": true, 10 | "lib": ["es2017", "dom"], 11 | "noLib": false, 12 | "preserveConstEnums": true, 13 | "suppressImplicitAnyIndexErrors": true, 14 | "declaration": true, 15 | "sourceMap": true, 16 | "jsx": "react", 17 | "typeRoots": ["./node_modules/@types"] 18 | }, 19 | "xxxfilesGlob": ["./ts/**/*.ts", "!./node_modules/**/*.ts"] 20 | } 21 | --------------------------------------------------------------------------------