diff --git a/package-lock.json b/package-lock.json index f61b240f..d3d5f3de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ }, "devDependencies": { "@svgr/webpack": "^8.1.0", + "@tailwindcss/typography": "^0.5.16", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", @@ -2472,6 +2473,36 @@ "tslib": "^2.4.0" } }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz", + "integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + } + }, + "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -5654,12 +5685,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", diff --git a/package.json b/package.json index 7b58f20a..b9e6f20d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ }, "devDependencies": { "@svgr/webpack": "^8.1.0", + "@tailwindcss/typography": "^0.5.16", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", diff --git a/public/images/packrat/downloading.avif b/public/images/packrat/downloading.avif new file mode 100644 index 00000000..460515a7 Binary files /dev/null and b/public/images/packrat/downloading.avif differ diff --git a/public/images/packrat/hero-screenshot.png b/public/images/packrat/hero-screenshot.png new file mode 100644 index 00000000..00dfac29 Binary files /dev/null and b/public/images/packrat/hero-screenshot.png differ diff --git a/public/images/packrat/packrat-lockup-color.svg b/public/images/packrat/packrat-lockup-color.svg new file mode 100644 index 00000000..3f77ae4c --- /dev/null +++ b/public/images/packrat/packrat-lockup-color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/packrat/sharing.avif b/public/images/packrat/sharing.avif new file mode 100644 index 00000000..35547b6b Binary files /dev/null and b/public/images/packrat/sharing.avif differ diff --git a/src/app/globals.css b/src/app/globals.css index f12fd9e6..56c736ce 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -21,8 +21,7 @@ @font-face { font-family: "BerkeleyMono"; - src: - url("https://general-static-assets.nyc3.digitaloceanspaces.com/website-assets/fonts/BerkeleyMonoVariable-Italic.woff") + src: url("https://general-static-assets.nyc3.digitaloceanspaces.com/website-assets/fonts/BerkeleyMonoVariable-Italic.woff") format("woff"), url("https://general-static-assets.nyc3.digitaloceanspaces.com/website-assets/fonts/BerkeleyMonoVariable-Italic.woff2") format("woff2"); @@ -33,8 +32,7 @@ @font-face { font-family: "BerkeleyMono"; - src: - url("https://general-static-assets.nyc3.digitaloceanspaces.com/website-assets/fonts/BerkeleyMonoVariable-Regular.woff2") + src: url("https://general-static-assets.nyc3.digitaloceanspaces.com/website-assets/fonts/BerkeleyMonoVariable-Regular.woff2") format("woff2"), url("https://general-static-assets.nyc3.digitaloceanspaces.com/website-assets/fonts/BerkeleyMonoVariable-Regular.woff") format("woff"); @@ -45,8 +43,7 @@ @font-face { font-family: "BerkeleyMono"; - src: - url("https://general-static-assets.nyc3.digitaloceanspaces.com/website-assets/fonts/BerkeleyMonoVariable-Regular.woff2") + src: url("https://general-static-assets.nyc3.digitaloceanspaces.com/website-assets/fonts/BerkeleyMonoVariable-Regular.woff2") format("woff2"), url("https://general-static-assets.nyc3.digitaloceanspaces.com/website-assets/fonts/BerkeleyMonoVariable-Regular.woff") format("woff"); @@ -195,6 +192,7 @@ a:visited { } button, +a.buttonstyle, [type="submit"], [type="button"] { font-family: "BerkeleyMono"; @@ -206,9 +204,13 @@ button, @apply whitespace-pre; @apply py-[8px]; @apply px-[20px]; + @apply no-underline; + @apply block; + @apply w-fit; } -button.fixed-w { +button.fixed-w, +a.buttonstyle.fixed-w { @apply w-[125px]; @apply md:w-[158px]; } diff --git a/src/app/packrat/page.tsx b/src/app/packrat/page.tsx new file mode 100644 index 00000000..ce18848c --- /dev/null +++ b/src/app/packrat/page.tsx @@ -0,0 +1,343 @@ +import React from "react"; + +export default function About() { + return ( +
+
+
+
+
+
+ Packrat by OPFN +

+ Next-generation browser history +

+ {/* + Install Chrome Extension + */} +
+
+
+ Screenshot of the packrat extension showing a handful of pages archived. A large button reads: share current page +
+
+
+
+
+
+
+
+
+
+

+ Save your own copy of the web +

+

+ Packrat archives every webpage you visit locally to your + computer. +

+

Keep a web archive of everything you browse!

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

Share pages with one click

+

Send specific archived pages directly to friends.

+

+ All data is sent directly with a peer-to-peer transfer, OPFN + never sees the content of your web archives. +

+
+
+
+
+
+

Get Packrat!

+

+ Packrat is currently available as an extension for Chrome and + Chromium-based browsers. +

+
+
+ {/* + Install Chrome Extension + */} + Coming soon! +
+
+
+
+

FAQ

+
+ What else can I do with my archives? +
+

+ Lots! Packrat lets you export your archived pages as WACZ files + which are supported by various web archiving tools such as{" "} + + Browsertrix + {" "} + and can be viewed or embedded in your own content using{" "} + + ReplayWeb.page + + . +

+

+ WACZs are also just ZIP files. If you unzip them they'll reveal + their component{" "} + + WARC files + {" "} + (another web archiving format) that is compatible with other + tools. +

+
+
+
+ + What analytics information do you collect? How do you use this + data? + +
+

+ If analytics are enabled we collect the following anonymized + data: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tracking IdentifierDescription
ViewPage + Triggers when a user clicks to view an archived page. +
TorrentCreated + Triggers when a torrent is created for sharing archived + content. Tracks how many pages are included. +
PageArchivedTriggers when a page is successfully archived.
PageSize + Logs the size of the archived page if available, rounded + to the nearest kilobyte. +
CookiesEnabledTracks if cookie archiving is enabled.
LocalstorageEnabledTracks if local storage archiving is enabled.
ScreenshotsEnabled + Tracks if thumbnail screenshot archiving is enabled. +
AnalyticsEnabledTracks if analytics tracking is enabled.
SkippedDomains + Logs the number of domains added to the skip list when + changed. +
TotalSize + Tracks the total size of all archived content, rounded to + megabytes. +
Started + Triggered when the archiving process begins for a page. +
Stopped + Triggered when the archiving process is stopped, either + manually or for another reason. +
+

+ This information helps us understand if you're finding the + features we've developed valuable! We self-host our analytics + and we will not sell or reveal this data to third parties. +

+
+
+
+ Is Packrat open source? +

+ Yes it is!{" "} + + download the Packrat source code on Github + + . Packrat is developed under the AGPL-3.0 license. +

+
+
+
+
+
+
+
+
+

Why we built Packrat

+

+ We believe that browser history and bookmarks are some of the + most un-iterated-upon features shipped in browsers today. In + recent years other companies have stepped in to help fill this + innovation void: +

+
    +
  • +

    + Obsidian has released{" "} + + Web Clipper + {" "} + which enables users to extract key text and information from + pages they visit as Markdown to save in their own notes. +

    +
  • +
  • +

    + Webrecorder maintains{" "} + + ArchiveWeb.page + {" "} + which allows users to create focused, curated web archives + of content they care about. ArchiveWeb.page is great, but + like Web Clipper it's ui is focused on the user making + active curatorial decisions about what content they deem + valuable. +

    +
  • +
  • +

    + Other tools like{" "} + ArchiveBox require + users to host a dedicated server to handle extraction and + preservation of content — a much more cohesive record of + what was browsed, but at the added cost that comes with + running infrastructure. +

    +
  • +
+ +

+ We think that there is opportunity for a middle ground between + these tools. Building upon Webrecorder's work enabling fully + browser-based capture and replay of web archives, Packrat seeks + to offer the same ease of use afforded by ArchiveWeb.page but + with a new user interface focused less on curation.{" "} + + Chrome's Side Panel API + {" "} + (launched in 2022) allows us to showcase the user's archived + pages directly beside the current page with the same Material 3 + design language adopted by Chrome, enabling a seamless + transition between live web content and navigating archived + pages. +

+

Challenges

+

+ Extensions aren't without their limitations, the biggest one we + face is our use of the Chrome Developer Tools API which, for + well-intentioned security reasons, displays a persistent banner + above the current page telling the user that an extension is + "debugging the page". While users can hide this by launching + their browser with the{" "} + --silent-debugger-extension-api command line flag + if they are sufficiently motivated to do so, ultimately we are + restricted by the browser environment. +

+

+ Webtorrent is close to a perfect solution for hosting + decentralized web archives, but it still isn't supported in most + major torrent clients as of publishing. Unlike most other + standard torrent clients, Webtorrent uses WebRTC to communicate + between peers.{" "} + + While WebRTC support was added to libtorrent + {" "} + (a common C++ library used by many torrent clients) in 2020, as + of publishing it is hidden behind a compiler flag and no release + of libtorrent has shipped with it enabled by default. In + practice, most clients follow the defaults of libtorrent and + therefore don't support seeding to Webtorrent peers. While this + doesn't pose a direct problem for Packrat — our peers are always + other Packrat instances using Webtorrent — having this enabled + in libtorrent by default would enable other interesting + decentralized web archive hosting projects. +

+
+

+ We hope that you find Packrat useful, either as a case study or + as a tool! +

+
+
+
+
+
+ ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 358e5710..af647283 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -178,7 +178,7 @@ export default function Home() {
-
+
@@ -246,7 +246,7 @@ export default function Home() {
-
+
@@ -506,7 +506,7 @@ type CogClosure =
-
+
@@ -781,7 +781,7 @@ Nats - natural numbers: opaque data or opcodes`}
-
+
diff --git a/src/components/Nav.tsx b/src/components/Nav.tsx index d9c8a78f..250047c9 100644 --- a/src/components/Nav.tsx +++ b/src/components/Nav.tsx @@ -14,32 +14,33 @@ export default function Nav() { const [isScrolledDown, setIsScrolledDown] = useState(false); const [elementColor, setElementColor] = useState("white"); - useEffect(() => { - if (!isHomePage) { - setIsScrolledDown(true); - setElementColor("black"); - return; - } + useEffect(() => { + if (!isHomePage) { + setIsScrolledDown(true); + setElementColor("black"); + return; + } - const timer = setTimeout(() => { - setIsVisible(true); - }, 250); + const timer = setTimeout(() => { + setIsVisible(true); + }, 250); - const handleScroll = () => { - const navbarHeight = (document.getElementById("topNav") as HTMLElement)?.offsetHeight || 0; - const heroHeight = (document.querySelector(".top-hero") as HTMLElement)?.offsetHeight; - const scrolledPast = window.scrollY > heroHeight - (navbarHeight - 20); - setIsScrolledDown(scrolledPast); - scrolledPast ? setElementColor("black") : setElementColor("white"); - }; - - window.addEventListener("scroll", handleScroll); - return () => { - window.removeEventListener("scroll", handleScroll); - clearTimeout(timer); - }; - }, [pathname, isHomePage]); + const handleScroll = () => { + const navbarHeight = + (document.getElementById("topNav") as HTMLElement)?.offsetHeight || 0; + const heroHeight = (document.querySelector(".top-hero") as HTMLElement) + ?.offsetHeight; + const scrolledPast = window.scrollY > heroHeight - (navbarHeight - 20); + setIsScrolledDown(scrolledPast); + scrolledPast ? setElementColor("black") : setElementColor("white"); + }; + window.addEventListener("scroll", handleScroll); + return () => { + window.removeEventListener("scroll", handleScroll); + clearTimeout(timer); + }; + }, [pathname, isHomePage]); return (
@@ -69,8 +72,15 @@ export default function Nav() { - diff --git a/tailwind.config.ts b/tailwind.config.ts index 20197159..950a1c53 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -74,6 +74,8 @@ const config: Config = { }, }, }, - plugins: [], + plugins: [ + require('@tailwindcss/typography'), + ], }; export default config;