{"id":14956111,"url":"https://github.com/ipfs/ipld-explorer-components","last_synced_at":"2025-04-06T06:09:07.975Z","repository":{"id":38172722,"uuid":"147528357","full_name":"ipfs/ipld-explorer-components","owner":"ipfs","description":"React components for https://explore.ipld.io and ipfs-webui","archived":false,"fork":false,"pushed_at":"2024-10-17T22:42:54.000Z","size":15605,"stargazers_count":24,"open_issues_count":15,"forks_count":23,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-10-29T12:11:27.673Z","etag":null,"topics":["ipfs","ipfs-gui"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ipfs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-05T14:10:03.000Z","updated_at":"2024-10-18T17:40:02.000Z","dependencies_parsed_at":"2023-02-17T22:46:26.138Z","dependency_job_id":"dd32a47d-6c0c-40b6-a8e8-c66ce45fc1ab","html_url":"https://github.com/ipfs/ipld-explorer-components","commit_stats":{"total_commits":241,"total_committers":23,"mean_commits":"10.478260869565217","dds":"0.44398340248962653","last_synced_commit":"7eefce26c3890fb6c6262f0ef6ede079e6010175"},"previous_names":[],"tags_count":46,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ipfs%2Fipld-explorer-components","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ipfs%2Fipld-explorer-components/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ipfs%2Fipld-explorer-components/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ipfs%2Fipld-explorer-components/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ipfs","download_url":"https://codeload.github.com/ipfs/ipld-explorer-components/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222073979,"owners_count":16926418,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ipfs","ipfs-gui"],"created_at":"2024-09-24T13:12:19.800Z","updated_at":"2025-03-15T02:08:40.282Z","avatar_url":"https://github.com/ipfs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IPLD Explorer Components\n\n\u003e React components for https://explore.ipld.io (https://github.com/ipfs/explore.ipld.io) and ipfs-webui\n\n![Screenshot of the IPLD explorer](https://user-images.githubusercontent.com/58871/43152632-f310763c-8f66-11e8-9449-2e362a9f3047.png)\n\n[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg)](https://protocol.ai/) [![](https://img.shields.io/badge/project-IPFS-blue.svg)](http://ipfs.io/) [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg)](http://webchat.freenode.net/?channels=%23ipfs) [![Build Status](https://img.shields.io/circleci/project/github/ipfs-shipyard/ipld-explorer-components.svg?style=flat-square)](https://circleci.com/gh/ipfs-shipyard/ipld-explorer-components) [![Dependencies Status](https://david-dm.org/ipfs-shipyard/ipld-explorer-components/master/status.svg)](https://david-dm.org/ipfs-shipyard/ipld-explorer-components/master)\n\n## Background\n\nThis module was extracted from the [explore.ipld.io](https://github.com/ipfs/explore.ipld.io) so it could be reused from the [IPFS Web UI](https://github.com/ipfs/ipfs-webui).\n\n## Usage\n\n**WARNING: This module is not intended to be re-used in it's current form by other projects.** There is more work to do to make this a nice set of generic components.\n\nInstall it from npm:\n\n```console\nnpm install --save ipld-explorer-components\n```\n\nThere are `peerDependencies` so that the consuming app can pick the versions of common deps. You'll need to add relevant deps to your project.\n\n### Use it in your project\n\nYou can see an example of how to use these components in the [devPage.tsx](./dev/devPage.tsx) file.\n\n```jsx\n// index.tsx\nimport React from 'react'\nimport {render} from 'react-dom'\nimport MyHeader from './app'\n\nconst PageRenderer = (): React.ReactElement =\u003e {\n  /**\n   * This is a simple example of listening to the hash change event that occurs when the user clicks around in the content rendered by ExplorePage.\n   */\n  const [route, setRoute] = useState(window.location.hash.slice(1) ?? '/')\n\n  useEffect(() =\u003e {\n    const onHashChange = (): void =\u003e { setRoute(window.location.hash.slice(1) ?? '/') }\n    window.addEventListener('hashchange', onHashChange)\n    return () =\u003e { window.removeEventListener('hashchange', onHashChange) }\n  }, [])\n\n  const RenderPage: React.FC = () =\u003e {\n    switch (true) {\n      case route.startsWith('/explore'):\n        return \u003cExplorePage /\u003e\n      case route === '/':\n      default:\n        return \u003cStartExploringPage /\u003e\n    }\n  }\n\n  return (\n    \u003cRenderPage /\u003e\n  )\n}\nconst App = (): React.ReactElement =\u003e {\n  return (\n    \u003cHeliaProvider\u003e\n      \u003cExploreProvider\u003e\n        \u003cMyHeader /\u003e\n        \u003cPageRenderer /\u003e\n      \u003c/ExploreProvider\u003e\n    \u003c/HeliaProvider\u003e\n  )\n}\n\nconst rootEl = document.getElementById('root')\nif (rootEl == null) {\n  throw new Error('No root element found with the id \"root\"')\n}\nconst root = createRoot(rootEl)\nroot.render(\n  \u003cI18nextProvider i18n={i18n}\u003e\n    \u003cApp /\u003e\n  \u003c/I18nextProvider\u003e\n)\n\n```\n\n### Exports provided by this library\n\n```js\nimport { HeliaProvider, ExploreProvider } from 'ipld-explorer-components/providers'\nimport { StartExploringPage, ExplorePage } from 'ipld-explorer-components/pages'\nimport { IpldExploreForm, IpldCarExploreForm } from 'ipld-explorer-components/forms'\n// or import all components at once\nimport { HeliaProvider, ExploreProvider, StartExploringPage, ExplorePage, IpldExploreForm, IpldCarExploreForm, CidInfo, ObjectInfo } from 'ipld-explorer-components'\n```\n\nThe following Components are available:\n\n```js\nexport {\n  /**\n   * Helia provider required for IPLD Explorer components\n   */\n  HeliaProvider,\n  /**\n   * A hook to gain access to the Helia node\n   */\n  useHelia,\n  /**\n   * Explore provider required for IPLD Explorer components. This must be a child  (direct or not) of HeliaProvider.\n   */\n  ExploreProvider,\n  /**\n   * A hook to gain access to the Explore state. You can programmatically set the CID or path to explore using the provided functions.\n   */\n  useExplore,\n  /**\n   * The page to render when you do not have an explicit CID in the URL to explore yet.\n   */\n  StartExploringPage,\n  /**\n   * When there is a #/explore/CID in the URL, this component will render the ExplorePage\n   */\n  ExplorePage,\n  /**\n   * The form to use to allow entry of a CID to explore. You can place this anywhere in your app within the ExploreProvider.\n   */\n  IpldExploreForm,\n  /**\n   * The form to use to allow uploading of a CAR file to explore. You can place this anywhere in your app within the ExploreProvider.\n   */\n  IpldCarExploreForm,\n  CidInfo,\n  ObjectInfo,\n}\n```\n\n\n### Styling\n\nAnd, assuming you are using `create-react-app` or a similar webpack set up, you'll need the following CSS imports:\n\n```js\nimport 'tachyons'\nimport 'ipfs-css'\nimport 'ipld-explorer-components/css'\n```\n\n### Customizing the links displayed in the StartExploringPage\n\nTo customize the links displayed in the start exploring page, you can pass a `links` property to the `StartExploringPage` component. This property should be an array of objects with the following properties:\n\n```\n{\n  name: 'Name of your example link',\n  cid: 'bafyfoo...',\n  type: 'dag-pb' // or dag-json, etc...\n}\n```\n\n### i18n support\n\nThe translations used for this library are provided in `dist/locales`. You can use them in your project by importing them and passing them to the `i18n` instance in your project.\n\n```ts\nimport i18n from 'i18next'\nimport LanguageDetector from 'i18next-browser-languagedetector'\nimport Backend from 'i18next-chained-backend'\nimport HttpBackend from 'i18next-http-backend'\nimport ICU from 'i18next-icu'\nimport LocalStorageBackend from 'i18next-localstorage-backend'\nimport { version } from '../package.json'\nimport locales from './lib/languages.json'\n\nexport const localesList = Object.values(locales)\n\nawait i18n\n  .use(ICU)\n  .use(Backend)\n  .use(LanguageDetector)\n  .init({\n    backend: {\n      backends: [\n        LocalStorageBackend,\n        HttpBackend\n      ],\n      backendOptions: [\n        { // LocalStorageBackend\n          defaultVersion: version,\n          expirationTime: (!import.meta.env.NODE_ENV || imObjectInfo.publicGatewayport.meta.env.NODE_ENV === 'development') ? 1 : 7 * 24 * 60 * 60 * 1000\n        },\n        { // HttpBackend\n          // ensure a relative path is used to look up the locales, so it works when loaded from /ipfs/\u003ccid\u003e\n          loadPath: (lngs, namespaces) =\u003e {\n            const lang = lngs[0]\n            const ns = namespaces[0]\n            if (ns === 'explore') {\n              // use the ipld-explorer-components locales\n              return 'node_modules/ipld-explorer-components/dist/locales/{{lng}}/{{ns}}.json'\n            }\n\n            // you can override keys in the explore namespace with your own translations. If they are not found, the explore translations will be used.\n            return `locales/${lang}/${ns}.json`\n          }\n        }\n      ]\n    },\n    ns: ['explore', 'app'],\n    defaultNS: 'app',\n    fallbackNS: 'explore', // fallback to explore namespace if the key is not found in the app namespace\n    fallbackLng: {\n      'zh-Hans': ['zh-CN', 'en'],\n      'zh-Hant': ['zh-TW', 'en'],\n      zh: ['zh-CN', 'en'],\n      default: ['en']\n    },\n    debug: import.meta.env.DEBUG,\n    // react i18next special options (optional)\n    react: {\n      // wait: true,\n      // useSuspense: false,\n      bindI18n: 'languageChanged loaded',\n      bindStore: 'added removed',\n      nsMode: 'default'\n    }\n  })\n```\n\n## Development\n\n### Adding another codec\n\n**NOTE:** PRs adding an old IPLDFormat codec would need the old `blockcodec-to-ipld-format` tool, which has many out-of-date deps. We will only accept PRs for adding BlockCodec interface codecs.\n\nTo add another codec, you will need to update all locations containing the comment `// #WhenAddingNewCodec`:\n\n1. Add a dependency on the codec to this package (if it's not already in multiformats or other package)\n1. Add the codec in the switch statement in [./src/lib/codec-importer.ts](./src/lib/codec-importer.ts)\n1. Update [./src/lib/get-codec-name-from-code.ts](./src/lib/get-codec-name-from-code.ts) to return the codec name for your codec\n1. Add a unit test to [./src/lib/resolve-ipld-path.test.js](./src/lib/resolve-ipld-path.test.js) and ensure that calling `resolveIpldPath` returns the expected results\n    * If the default `resolveFn` in [./src/lib/get-codec-for-cid.ts](./src/lib/get-codec-for-cid.ts) doesn't resolve your paths correctly, you will need to add a resolver method for your codec to the `codecResolverMap` in [./src/lib/get-codec-for-cid.ts](./src/lib/get-codec-for-cid.ts)\n\nsee https://github.com/ipfs/ipld-explorer-components/pull/360#discussion_r1206251817 for history.\n\n### Adding another hasher\n\nTo add another hasher, you will need to update all locations containing the comment `// #WhenAddingNewHasher`:\n\n1. Add a dependency on the hasher to this package (if it's not already in multiformats or other package)\n1. Update [./src/lib/hash-importer.ts](./src/lib/hash-importer.ts)\n    - Update `SupportedHashers` to include your hasher type\n    - Update `getHasherForCode` to return your hasher\n1. Update the hasher codes used by the `hashers` property passed to Helia init in [./src/lib/init-helia.ts](./src/lib/init-helia.ts)\n\nsee https://github.com/ipfs/ipld-explorer-components/pull/395 for an example.\n\n## Contribute\n\nFeel free to dive in! [Open an issue](https://github.com/ipfs/ipld-explorer-components/issues/new) or submit PRs.\n\nTo contribute to IPFS in general, see the [contributing guide](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md).\n\n[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md)\n\n## Releasing\n\n- Run `tx pull -a` to pull the latest translations from Transifex ([i18n#transifex-101)](https://github.com/ipfs-shipyard/i18n#transifex-101))\n- Update the version (`npm version major/minor/patch`)\n- Push the changes (`git push \u0026\u0026 git push --follow-tags`)\n- Update the [changelog](./CHANGELOG.md)\n- Add release notes to https://github.com/ipfs/ipld-explorer-components/releases, use the tag and copy changelog changes\n- Publish to npm (`npm publish`)\n\n## License\n\n[MIT](LICENSE) © Protocol Labs\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fipfs%2Fipld-explorer-components","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fipfs%2Fipld-explorer-components","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fipfs%2Fipld-explorer-components/lists"}