### Fetch JSON Directory Listing Example Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers An example demonstrating how to fetch a JSON directory listing from an IPFS mirror URL. The file/folder list can be accessed using await response.json(). ```javascript url = 'ipfs://bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze/wiki/' response = await fetch(url, { headers: { Accept: 'application/json' } }) ``` -------------------------------- ### Example URL Query Parameter Source: https://agregore.mauve.moe/docs/tutorials/texteditor An example of a URL query parameter used to specify a file to load or save. ```url ?url=./example.txt ``` -------------------------------- ### Install Ollama Source: https://agregore.mauve.moe/docs/ai Installs Ollama on your system using a curl command. This is a prerequisite for running local LLM models. ```bash curl -fsSL https://ollama.com/install.sh | sh ``` -------------------------------- ### Handle Upload Start and Completion Events Source: https://agregore.mauve.moe/docs/tutorials/ipfs-dir-upload Update the loadSidebar function in lib.js to handle 'dirUploadStart' by showing a modal dialog, and 'dirUpload' to update the modal and redirect after a delay. ```javascript dirUploadForm.addEventListener('dirUploadStart', e => { const modalDiv = document.createElement('dialog') modal.id = 'uploadStatus' modal.innerHTML = `

Uploading ${e.detail.fileCount} file(s)

` document.body.appendChild(modal) modal.showModal() }) dirUploadForm.addEventListener('dirUpload', e => { console.log('onDirUpload', e) let modal = document.getElementById('uploadStatus') modal.innerHTML = `

Upload complete. You will be redirected shortly

` setTimeout(te => window.location = e.detail.cid, 5000) }) ``` -------------------------------- ### Navigate to a Blank Site Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-1 Resets the browser's location to a specific IPFS CID, effectively starting with a blank site for development. ```javascript window.location = 'ipfs://bafybeiczsscdsbs7ffqz55asqdf3smv6klcw3gofszvwlyarci47bgf354' ``` -------------------------------- ### Adding Google Search Provider Source: https://agregore.mauve.moe/docs/search-provider Example of how to add Google as a custom search provider by specifying its search URI template. Ensure the template includes '%s' for the search query. ```text https://www.google.com/search?q=%s ``` -------------------------------- ### Configure LLM Settings in .agregorerc Source: https://agregore.mauve.moe/docs/ai Example JSON configuration for the .agregorerc file to enable and configure the local LLM API, specifying the base URL, API key, and model. ```json { "llm": { "enabled": true, "baseURL": "http://127.0.0.1:11434/v1/", "apiKey": "ollama", "model": "qwen2.5-coder" } } ``` -------------------------------- ### Fetch File with GET Method (Explicit) Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers Explicitly using the 'GET' method for fetching a file. This is functionally equivalent to omitting the method option. ```javascript await fetch('ipfs://CID/example.txt', { method: 'GET' }) ``` -------------------------------- ### Get Function as String Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-1 This snippet demonstrates how to get the string representation of a JavaScript function using the `.toString()` method. This is useful for saving functions to files on IPFS. ```javascript async function updateSite(newPageContent){ let cid = window.location.hostname const resp = await fetch(`ipfs://${cid}/index.html`, {method: 'put', body: newPageContent}) const newLocation = resp.headers.get('location') window.location = newLocation } updateSite.toString() ``` -------------------------------- ### Initialize PubSub on Form Submit Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat Attaches an event listener to a form to initialize the PubSub class and start listening for messages when the form is submitted. ```javascript window.addEventListener('load', (event) => { const form = document.getElementById('roomNameForm') form.addEventListener('submit', event => { event.preventDefault() const channelName = document.getElementById('channelNameInput').value console.log('start pubsub', channelName) window.pubsub = new PubSub(channelName) window.pubsub.listenForMsg().catch(console.error) }) }) ``` -------------------------------- ### Adding Bing Search Provider Source: https://agregore.mauve.moe/docs/search-provider Example of how to add Bing as a custom search provider by specifying its search URI template. Ensure the template includes '%s' for the search query. ```text https://www.bing.com/search?q=%s ``` -------------------------------- ### Get JSON Directory Listing Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers Request a JSON array of files and folders in a directory by setting the 'Accept' header to 'application/json'. ```javascript var response = await fetch('ipfs://CID/example/', { headers: {Accept: 'application/json'} }) ``` -------------------------------- ### Initialize ACE Editor in showEditor Function Source: https://agregore.mauve.moe/docs/tutorials/ipfs-3rdparty-dep Update the showEditor function in lib.js to initialize the ACE editor instance and set up the form submission handler to get content from the editor. This prepares the editor for user interaction. ```javascript async function showEditor(){ let editorDiv = document.getElementById("editor") if (!editorDiv){ editorDiv = document.createElement('div') editorDiv.id = 'editor' } editorDiv.style = `display: flex; position: absolute; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgb(233 233 233 / 95%); ` const editorStyle = document.createElement('style') //+ editorStyle.innerHTML = "#idForm pre { flex-grow: 1; margin: 0; }" //+ document.body.appendChild(editorStyle) //+ editorDiv.innerHTML = `

Files

` document.body.appendChild(editorDiv) window.editor = ace.edit("idContentInput") //+ const form = document.getElementById('idForm') form.onsubmit = e => { e.preventDefault() const filename = document.getElementById('idFilenameInput').value //- const content = document.getElementById('idContentInput').value const content = window.editor.getValue() //+ updateSite(filename, content) } await loadSidebar() } ``` -------------------------------- ### Edit File Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-2 Opens the editor interface and loads the content of the specified file. Use this to start editing an existing file. ```javascript async function editFile(filename){ openEditor() loadFile(filename) } ``` -------------------------------- ### Get Hyper URL from Site Name Source: https://agregore.mauve.moe/docs/snippets Generates a Hyperdrive key and returns its URL. Ensure the Agregore service is running and accessible. ```javascript async function getHyperURL(siteName) { const response = await fetch(`hyper://localhost/?key=${siteName}`, { method: 'POST' }); if (!response.ok) { throw new Error(`Failed to generate Hyperdrive key: ${await response.text()}`); } return await response.text() } ``` -------------------------------- ### Load lib.js and Get updateSite Function Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-1 Injects the 'lib.js' script into the document's head to make the 'updateSite' function available in the global scope. It also attempts to retrieve the function's string representation. ```javascript let script = document.createElement('script') script.src = 'lib.js' document.head.appendChild(script) updateSite.toString() ``` -------------------------------- ### Dispatch Custom Event on Directory Upload Start Source: https://agregore.mauve.moe/docs/tutorials/ipfs-dir-upload In upload.js, add a line within the onSubmit handler to dispatch a 'dirUploadStart' event, passing the file count. This signals the beginning of the upload process. ```javascript const fileInput = document.querySelector('#dirForm input[type="file"]') this.dispatchEvent(new CustomEvent('dirUploadStart', { detail: { fileCount: fileInput.files.length } })) // <--- Add this line const newCid = await batchUpload(fileInput.files, pathPrefix) ``` -------------------------------- ### Display Chat Interface and Handle Message Submission Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat Adds code to display the chat interface and hide the initial room setup. It also sets up an event listener to send messages when the form is submitted. ```javascript onopen(e) { // ... document.getElementById('setup').classList.add('hidden') document.getElementById('chat').classList.remove('hidden') document.getElementById('roomName').innerHTML = this.channelName document.querySelector('#chatForm').addEventListener('submit', e => { e.preventDefault() let textInput = document.querySelector('#chat input') fetch(`pubsub://${this.channelName}/`, { method: 'POST', body: JSON.stringify({message: textInput.value}), }).catch(console.error) textInput.value = '' }) } ``` -------------------------------- ### Initialize Gallery and Lightbox Functionality Source: https://agregore.mauve.moe/docs/tutorials/ipfs-gallery Set up click event listeners for images to open the lightbox and for the lightbox image to close it. ```javascript function galleryInit(){ layout() for (const img of document.querySelectorAll('.gallery .row img')){ img.addEventListener('click', e => { document.querySelector('.lightBox img').src = img.src document.querySelector('.lightBox').classList.remove('hidden') }) } document.querySelector('.lightBox img').addEventListener('click', e => document.querySelector('.lightBox').classList.add('hidden') ) } ``` -------------------------------- ### Initialize PubSub Class Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat Sets up the PubSub class to handle IPFS PUBSUB connections. This code snippet is intended to be added to 'pubsub.js'. ```javascript class PubSub { constructor(channelName) { this.channelName = channelName } } ``` -------------------------------- ### Fetch and Add Website Files Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-3 Fetches 'index.html' and 'lib.js' from a URL and adds them to the site using the addFiles function. ```javascript let resp = await fetch('https://www.thebacklog.net/projects/agregore-web-apps/amt3.js') const libjs = await resp.text() resp = await fetch('https://www.thebacklog.net/projects/agregore-web-apps/amt3-index.tmpl') const indexhtml = await resp.text() addFiles([ new File([indexhtml], 'index.html', {type: 'text/html'}) new File([libjs], 'lib.js', {type: 'text/javascript'}) ]) ``` -------------------------------- ### Initialize PubSub Class Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat Defines the basic structure for the PubSub class, holding the channel name. ```javascript class PubSub { constructor(channelName){ this.channelName=channelName } } ``` -------------------------------- ### Get IPLD Data Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers You can get raw IPLD data from a CID using the `ipld` protocol scheme. The data pointed to by the CID will not be interpreted as UnixFS and will use raw IPLD traversal. ```APIDOC ## GET ipld://CID/example ### Description Retrieves raw IPLD data from a CID using raw IPLD traversal. ### Method GET ### Endpoint ipld://CID/example ### Parameters #### Query Parameters - **Accept** (string) - Optional - The desired response format (e.g., `application/json`, `application/vnd.ipld.dag-json`, `application/vnd.ipld.dag-cbor`). ### Response #### Success Response (200) - Raw IPLD data in the requested format. ### Request Example ```javascript await fetch('ipld://CID/example', { method: 'GET', headers: { 'Accept': "application/json" } }) ``` ``` -------------------------------- ### Getting Editor Content Source: https://agregore.mauve.moe/docs/tutorials/ipfs-3rdparty-dep Retrieve the current content from the ACE editor instance within an onSubmit callback. ```javascript const content = window.editor.getValue() ``` -------------------------------- ### Basic HTML Structure for Chat App Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat Sets up the initial HTML for the chat application, including a title, a form for selecting a room name, and links to JavaScript files. ```html PUBSUB chat

IPFS PUBSUB chat

``` -------------------------------- ### Get raw IPLD data from a CID Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers Use the 'ipld://' protocol scheme to get raw IPLD data from a CID. The data will not be interpreted as UnixFS and will use raw IPLD traversal with the path. Path segments can have custom parameters separated by ';', and URL encoding can be used for special characters. The 'Accept' header can re-encode the data into 'application/json', 'application/vnd.ipld.dag-json', or 'application/vnd.ipld.dag-cbor'. ```javascript await fetch('ipld://CID/example', { method: 'GET', headers: { 'Accept': "application/json" } }) ``` -------------------------------- ### Load Script and Create index.html with Delay Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-1 Injects the 'lib.js' script and then, after a 1-second delay, updates 'index.html' with content including the script tag. This ensures the script is loaded before the HTML is updated. ```javascript let script = document.createElement('script') script.src = 'lib.js' document.head.appendChild(script) setTimeout( () => updateSite('index.html', ` Page title

Hello world

`), 1000) ``` -------------------------------- ### Get IPNS URL from Site Name Source: https://agregore.mauve.moe/docs/snippets Generates an IPNS key and returns its URL. This function requires the Agregore service to be running. ```javascript async function getIPNSURL(siteName) { const response = await fetch(`ipns://localhost/?key=${siteName}`, { method: 'POST' }); if (!response.ok) { throw new Error(`Failed to generate IPNS key: ${await response.text()}`); } await response.text() return response.headers.get('Location') } ``` -------------------------------- ### Complete lib.js Code Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-3 Contains the final implementation of publishSite, updateSite, and the beginning of loadFile for lib.js. ```javascript async function publishSite(){ let resp = await fetch('ipns://localhost/?key=mysite', {method: 'POST'}) const key = resp.headers.get('location') resp = await fetch(key, {method: 'POST', body: window.origin}) window.location = new URL(resp.headers.get('location')).origin } async function updateSite(filename, content){ const resp = await fetch(`${window.origin}/${filename}`, {method: 'put', body: content}) const newLocation = resp.headers.get('location') window.location = new URL(newLocation).origin } async function loadFile(filename){ ``` -------------------------------- ### Populate Sidebar with File List Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-2 Fetches the list of files in the current directory using listDir, then dynamically creates an unordered list of clickable file links to populate the sidebar. Clicking a file loads it into the editor. ```javascript const sidebar = document.getElementById('idSidebar') const files = await listDir(window.origin) const list = document.createElement('ul') list.style = "list-style: none; padding-inline-start: 0;" files.map( file => { let li = document.createElement('li') li.innerHTML = `${file}` li.querySelector('a').onclick = e => loadFile(file) ``` -------------------------------- ### Assemble Code for Uploading Source: https://agregore.mauve.moe/docs/tutorials/p2pad-code-editor Prepares HTML, CSS, and JavaScript into a single HTML file format and converts it to a Blob for uploading. Shows a loading spinner during the process. ```javascript export async function assembleCode() { // Implementation to assemble and upload the code } ``` -------------------------------- ### Setting ACE Editor Mode Source: https://agregore.mauve.moe/docs/tutorials/ipfs-3rdparty-dep Set the editor's mode based on certain conditions. This example shows setting it to CSS or plain text. ```javascript editor.session.setMode("ace/mode/css") } else { editor.session.setMode("ace/mode/text") ``` -------------------------------- ### Placeholder for Upload File Function Source: https://agregore.mauve.moe/docs/tutorials/drag-and-drop This is a placeholder indicating where the main file upload logic resides. The actual implementation is detailed in the full code example. ```javascript async function uploadFile(file) { // ... [full code above] } ``` -------------------------------- ### HTML Structure for Image Gallery Source: https://agregore.mauve.moe/docs/tutorials/ipfs-gallery Sets up the basic HTML for an image gallery using nested divs and placeholder images. Includes CSS for flexbox layout. ```html Image gallery ``` -------------------------------- ### List IPFS Directory Contents in Console Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-2 Tests the listDir function by calling it with the current origin. Expects to return an array of file names like ['index.html', 'lib.js']. ```javascript await listDir(window.origin) ``` -------------------------------- ### Clown Theme JSON Source: https://agregore.mauve.moe/docs/theming An example of a highly contrasting and vibrant theme, referred to as the 'Clown Theme'. Use with caution due to its intense color palette. ```json { "theme": { "font-family": "Arial", "background": "#0000ff", "text": "#00ff00", "page": "#ff0000", "primary": "#ffff00", "secondary": "#ffffff", "border-radius": "1em" } } ``` -------------------------------- ### JavaScript to Get Form Data Source: https://agregore.mauve.moe/docs/snippets This JavaScript snippet retrieves form data from the 'saveForm' element, extracting filename, save type, and site name. ```javascript saveForm.onsubmit = (e) => { e.preventDefault() const formData = new FormData(saveForm) const filename = formData.get('fileName') const saveType = formData.get('saveType') const siteName = formData.get('siteName') } ``` -------------------------------- ### Placeholder for Generate Hyperdrive Key Function Source: https://agregore.mauve.moe/docs/tutorials/drag-and-drop This is a placeholder indicating where the Hyperdrive key generation logic resides. The actual implementation is detailed in the full code example. ```javascript async function generateHyperdriveKey(name) { // ... [full code above] } ``` -------------------------------- ### Minimal HTML Structure for Agregore Editor Source: https://agregore.mauve.moe/docs/tutorials/ipfs-3rdparty-dep This is the updated index.html file. It now only includes a single script tag for lib.js, as all other resources are loaded dynamically by the showEditor function. ```html Agregore self-hosted devenv V2

Agregore self-hosted devenv V2

``` -------------------------------- ### JavaScript to Get URL Parameter Source: https://agregore.mauve.moe/docs/tutorials/texteditor Extracts the 'url' search parameter from the current page's URL. This is used to specify a text file to be loaded into the editor. ```javascript function getURLFromSearch() { const {searchParams} = new URL(window.location) const url = searchParams.get('url') return url } ``` -------------------------------- ### JavaScript Function to Handle File Picker Source: https://agregore.mauve.moe/docs/tutorials/ipfs-gallery This asynchronous JavaScript function, `handleHelpClick`, utilizes the `showOpenFilePicker` API to allow users to select multiple image files. It then minimizes the help overlay and adds the selected files to the gallery. ```javascript async function handleHelpClick(e){ e.stopPropagation() const opts = { types: [ { description: "Images", accept: { "image/*": [".png", ".gif", ".jpeg", ".jpg"], }, }, ], excludeAcceptAllOption: true, multiple: true, startIn: "pictures", } let result = await showOpenFilePicker(opts) document.querySelector('.helpOverlay').classList.add('small') for (const fileHandle of result){ let file = await fileHandle.getFile() await addFileToGallery(file) } } ``` -------------------------------- ### Basic HTML Structure for Theme Builder Source: https://agregore.mauve.moe/docs/tutorials/themebuilder-tutorial This HTML provides the basic structure for the Theme Builder tutorial, including headings and paragraphs that will be styled by the CSS. ```html

Theme Builder

The Idea ✨

Jesse is using the Agregore theme (found here or here) to keep their apps looking cohesive. They want to change up the theme, so they navigate to ipns://themebuild.er to play around with the colors until they find something they like.

Preamble

This tutorial assumes a very basic level of web development experience as well as a small familiarity with p2p web protocols or IPFS. Maybe you've made a handful of single page web apps and have heard about the distributed web before but haven't really played around with it.

Getting Started 🏁

To keep things simple for this tutorial I'm just going to use an online code playground (I used JSFiddle specifically) as our dev environment. Of course, you're free to use whatever you want, but that's the context that surround this tutorial.

We will use Agregore's built in IPFS Fetch API to publish our site on IPFS. At the time of writing the latest version for Agregore can be found here.

Developing Our App

So, let's start making our app, our basic endgoal here is to have some color pickers to choose the theme colors, an "example page" to reflect the color changes, and a way for the user to "save" those changes.

First let's set up our file, if you navigate to agregore://theme/style.css we're just going to copy paste this whole thing into the css.

Once you've done that, delete the second line (the @import url("agregore://theme/vars.css")) and replace it with the following:

:root {
  --ag-theme-font-family: system-ui;
  --ag-theme-background: #111;
  --ag-theme-text: #F2F2F2;
  --ag-theme-primary: #6e2de5;
  --ag-theme-secondary: #2de56e;
  --ag-theme-indent: 16px;
  --ag-theme-max-width: 666px;
}

If you took a peek at agregore://theme/vars.css you might notice that this looks very similar because it's essentially that file. The reason we're doing things this was is because we're gonna want to be able to mess with the CSS file and edit it freely.

After we've done that we're going to want to have some content for the CSS to style. For that I decided to use this tutorial up to this point!

``` -------------------------------- ### HTML Form for Directory Upload Source: https://agregore.mauve.moe/docs/tutorials/ipfs-dir-upload Sets up an HTML form with inputs for an optional path prefix and a file input that accepts directories using the `webkitdirectory` attribute. ```html Agregore IPFS directory upload

Agregore IPFS directory upload

Choose files to upload

``` -------------------------------- ### HTML Structure for Drag and Drop App Source: https://agregore.mauve.moe/docs/tutorials/drag-and-drop Sets up the basic HTML for a drag-and-drop file upload application, including a protocol selector, a drop zone, and a list for uploaded file URLs. External CSS and JavaScript files are linked for styling and functionality. ```html Drag and Drop to IPFS and Hypercore
Drop a file here
``` -------------------------------- ### Listen for Pub/Sub Messages Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat Sets up an EventSource to listen for messages on a specific Pub/Sub channel. Requires the channel name to be available. ```javascript async listenForMsg() { let es = new EventSource(`pubsub://${this.channelName}/?format=json`) es.onmessage = this.onmessage es.onopen = this.onopen es.onerror = this.onerror } ``` -------------------------------- ### Add Publish Button to Sidebar Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-3 Adds a 'Publish site' button to the sidebar if the current origin starts with 'ipfs://'. Clicking the button calls the publishSite function. ```javascript if (window.origin.startsWith('ipfs://')){ const button = document.createElement('button') button.innerHTML = 'Publish site' button.onclick = e => { e.preventDefault() publishSite() } sidebar.appendChild(button) } ``` -------------------------------- ### Upload File and Add URL Source: https://agregore.mauve.moe/docs/tutorials/dlinktree-builder Handles the creation of a File object and initiates the upload process, then adds the resulting URL to the UI. ```javascript const file = new File([blob], "index.html", { type: 'text/html' }); // Upload the file const response = await uploadFile(file); addURL(response.url); } ``` -------------------------------- ### Setup Drag and Drop Event Handlers Source: https://agregore.mauve.moe/docs/tutorials/drag-and-drop Configures the 'ondragover' and 'ondrop' event handlers for the upload box element. It prevents the default dragover behavior and processes dropped files. ```javascript const uploadBox = $('#uploadBox'); uploadBox.ondragover = () => false; uploadBox.ondrop = async (e) => { e.preventDefault(); const { dataTransfer } = e; if (!dataTransfer) return; for (const file of dataTransfer.files) { await uploadFile(file); } }; ``` -------------------------------- ### HTML for Help Overlay with File Selector Button Source: https://agregore.mauve.moe/docs/tutorials/ipfs-gallery This updated HTML snippet enhances the help overlay by adding a button that triggers a file selector, providing an alternative to drag-and-drop for adding images. ```html

Drag and drop images to begin or . Click anywhere to view the gallery.

``` -------------------------------- ### HTML Structure for P2Pad Code Editor Source: https://agregore.mauve.moe/docs/tutorials/p2pad-code-editor Sets up the basic HTML document, including meta tags, title, CSS link, and the main layout for the code editor. It defines text areas for HTML, CSS, and JavaScript input, and an iframe for output preview. ```html P2Pad: Real-Time Editor
``` -------------------------------- ### JavaScript to Load URL Content into Editor Source: https://agregore.mauve.moe/docs/tutorials/texteditor Combines the functions to get a URL from the search parameters and load its text content into the editor's textarea. This code should be placed at the top of the JavaScript section. ```javascript const url = getURLFromSearch() if(url) { const text = await loadTextFromURL(url) editorBox.value = text } ``` -------------------------------- ### Basic HTML Structure for Text Editor Source: https://agregore.mauve.moe/docs/tutorials/texteditor Sets up the fundamental HTML elements for the text editor, including a header, a textarea for editing, and dialog elements for file loading and creation. ```html

Text Editor

Load file

Create file

``` -------------------------------- ### HTML Button for Opening Create File Dialog Source: https://agregore.mauve.moe/docs/tutorials/texteditor This HTML snippet adds a button to the header that, when clicked, will open the 'Create file' modal dialog. ```html

Text Editor

``` -------------------------------- ### Redirect to IPNS Public Key URL Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers You can redirect to a `ipns://k2k4r...` public key URL by doing a `GET` on an existing key using the special `localhost` IPNS domain. You must specify a custom "key name" in the `key` URL search parameter. ```APIDOC ## GET ipns://localhost/?key=example_key ### Description Retrieves an IPNS public key URL via redirect. Requires a 'key' query parameter. ### Method GET ### Endpoint ipns://localhost/?key=example_key ### Parameters #### Query Parameters - **key** (string) - Required - The custom name of the IPNS key. ### Response #### Success Response (302) - **Location** (string) - The IPNS public key URL. #### Error Response (404) - Sent if the key has not been created. ### Request Example ```javascript await fetch('ipns://localhost/?key=example_key') ``` ``` -------------------------------- ### Import Default Theme Styles Source: https://agregore.mauve.moe/docs/theming Link to the default stylesheet to apply browser-wide styling for elements like buttons. This simplifies page structure by offloading styling details. ```html ``` -------------------------------- ### Initialize Drag and Drop Functionality Source: https://agregore.mauve.moe/docs/tutorials/drag-and-drop Sets up the drag-and-drop event listeners for the upload box. Prevents default dragover behavior and handles file drops by initiating the upload process. ```javascript function $(query) { return document.querySelector(query) } const uploadBox = $('#uploadBox') uploadBox.ondragover = () => false uploadBox.ondrop = async (e) => { e.preventDefault() const { dataTransfer } = e if(!dataTransfer) return await uploadFiles(dataTransfer.files); } ``` -------------------------------- ### Resolve IPNS key using localhost Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers Redirect to an IPNS public key URL by performing a GET request on an existing key using the special 'localhost' IPNS domain. A custom key name must be specified in the 'key' URL search parameter. A 302 redirect with the URL in the 'Location' response header is returned. A 404 response is sent if the key has not been created. ```javascript await fetch('ipns://localhost/?key=example_key') ``` -------------------------------- ### Show Editor Interface Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-3 Creates and displays an editor interface for managing files. This includes a sidebar for file navigation and a form for editing filename and content. It also handles form submission to update the site. ```javascript async function showEditor(){ let editorDiv = document.getElementById("editor") if (!editorDiv){ editorDiv = document.createElement('div') editorDiv.id = 'editor' } editorDiv.style = `display: flex; flex-direction: column; position: absolute; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgb(233 233 233 / 95%); ` editorDiv.innerHTML = `

Files

` document.body.appendChild(editorDiv) const form = document.getElementById('idForm') form.onsubmit = e => { e.preventDefault() const filename = document.getElementById('idFilenameInput').value const content = document.getElementById('idContentInput').value updateSite(filename, content) } await loadSidebar() } ``` -------------------------------- ### Adding a Generic Custom Search Provider Source: https://agregore.mauve.moe/docs/search-provider Template for adding any custom search engine. Replace 'your-search-engine.com' and adjust the query parameter as needed. The '%s' placeholder is mandatory. ```text https://your-search-engine.com/search?query=%s ``` -------------------------------- ### Open App with Default URL Source: https://agregore.mauve.moe/docs/snippets If no 'url' parameter is present in the query string, this snippet redirects to a default Agregore app creation URL after a short delay. ```javascript const {searchParams} = new URL(window.location) const url = searchParams.get('url') if(!url) { setTimeout(() => { location.href = new URL(`hyper://agregore.mauve.moe/apps/create.html?url=${location.href}`).href }, 100) } else { loadData(url) } ``` -------------------------------- ### Initialize ACE Editor Instance Source: https://agregore.mauve.moe/docs/tutorials/ipfs-3rdparty-dep This snippet shows how to initialize the ACE editor by calling `ace.edit()` and passing the ID of the textarea element that will be replaced by the editor. This is a core step for integrating ACE. ```javascript window.editor = ace.edit("idContentInput") ``` -------------------------------- ### Initialize Gallery and Remove Stock Rows Source: https://agregore.mauve.moe/docs/tutorials/ipfs-gallery This JavaScript code initializes the gallery by removing any existing stock image rows and adding a new row. It's a foundational step for managing gallery content. ```javascript const gallery = document.querySelector('.gallery') if (gallery.querySelectorAll('.row.stock').length > 0){ for (const stockRow of gallery.querySelectorAll('.row.stock')){ gallery.removeChild(stockRow) } const div = document.createElement('div') div.classList.add('row') gallery.appendChild(div) } ``` -------------------------------- ### Generate HTML Page Template Source: https://agregore.mauve.moe/docs/tutorials/scraper Creates a full HTML page structure including title, description, and viewport meta tags. Use this to format scraped content into a presentable page. ```javascript function genPage({ title, description, html }={}) { return ` ${title} ${html} ` } ``` -------------------------------- ### CSS for Help Overlay Source: https://agregore.mauve.moe/docs/tutorials/ipfs-gallery This CSS defines the appearance and behavior of the help overlay, including its fixed positioning, background, and a minimized state for when it's clicked. ```css .gallery > div.helpOverlay { display: flex; flex-direction: column; position: fixed; width: 100%; height: 100vh; background: rgba(0,0,0, 0.6); color: white; align-items: center; justify-content: center; padding: 0 5px; } .gallery > div.helpOverlay.small { height: unset; bottom: 0; padding-bottom: 15px; } .gallery > div.helpOverlay.small span { display: none; } ``` -------------------------------- ### Assemble and Upload DLinktree Source: https://agregore.mauve.moe/docs/tutorials/dlinktree-builder This asynchronous function compiles the DLinktree builder into a single HTML file, incorporating dynamic elements and styles, before uploading it to the decentralized web. ```javascript async function assembleCode() { // Process to assemble the HTML content // Upload the assembled HTML to the decentralized web // Refer to the full javascript code for reference } ``` -------------------------------- ### Load Sidebar with File List Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-3 Dynamically loads a sidebar with a list of files and directories fetched from the current origin. It recursively builds the file list and attaches click handlers to load files. ```javascript async function loadSidebar(){ const sidebar = document.getElementById('idSidebar') const files = await listDir(window.origin) const list = document.createElement('ul') list.style = "list-style: none; padding-inline-start: 0;" async function makeFileListElements(path, file) { if (file.endsWith('/')){ let subfiles = await listDir(window.origin + path + file) let elements = await Promise.all( subfiles.map(subfile => makeFileListElements(path + file, subfile) ) ) return elements.reduce( (arr, el) => [...arr, ...el] ) } let li = document.createElement('li') li.innerHTML = `${path}${file}` li.querySelector('a').onclick = e => loadFile(path + file) return [li] } await Promise.all( files.map(async file => { let elements = await makeFileListElements('/', file) elements.map(li => list.appendChild(li)) }) ) sidebar.appendChild(list) if (window.origin.startsWith('ipfs://')){ const button = document.createElement('button') button.innerHTML = 'Publish site' button.onclick = e => { e.preventDefault() publishSite() } sidebar.appendChild(button) } } ```