这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 91 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,106 @@ _Telegram group for this repo https://t.me/fivechandev_

# 5chan

5chan is a serverless, adminless, decentralized and open-source 4chan alternative, where anyone can create and cryptographically own unlimited boards. All boards are selfhosted by their owners, who run [plebbit nodes](https://github.com/plebbit/plebbit-cli) that users connect to, peer-to-peer. All data is text-only, including links to load media/embeds.
5chan is a serverless, adminless, decentralized and open-source 4chan alternative built on the [Plebbit protocol](https://plebbit.com). It features the same directory structure as 4chan, but with a crucial difference: **anyone can create and own boards, and multiple boards can compete for each directory slot**.

- web version: https://5chan.app, also available using Brave/IPFS Companion on https://5chan.eth
## Key Features

### Downloads
- desktop version (full p2p plebbit node, seeds automatically): available for Mac/Windows/Linux, [download link in the release page](https://github.com/plebbit/5chan/releases/latest)
- mobile version: available for Android, [download link in the release page](https://github.com/plebbit/5chan/releases/latest)
### Decentralized Board Ownership
Unlike traditional imageboards, 5chan has no global admins or central authority. Anyone can create unlimited boards using their own [plebbit node](https://github.com/plebbit/plebbit-cli). Each board owner runs their own P2P node that users connect to peer-to-peer, giving them complete control over their board's content, moderation, and rules.

## How to create a board
In the plebbit protocol, a 5chan board is called a _subplebbit_. To run a subplebbit, you can choose between two options:
### Competitive Directory System
5chan maintains the familiar 4chan directory structure (Japanese Culture, Video Games, Interests, Creative, etc.), but introduces competition: **multiple boards can compete for each directory slot**. For example, there can be unlimited "Business & Finance" boards, but only the highest-voted one appears in the directory on the homepage.

1. If you prefer to use a **GUI**, download the desktop version of the Seedit client, available for Windows, MacOS and Linux: [latest release](https://github.com/plebbit/seedit/releases/latest). Create a subplebbit using using the familiar old.reddit-like UI, and modify its settings to your liking. The app runs an IPFS node, meaning you have to keep it running to have your board online.
2. If you prefer to use a **command line interface**, install plebbit-cli, available for Windows, MacOS and Linux: [latest release](https://github.com/plebbit/plebbit-cli/releases/latest). Follow the instructions in the readme of the repo. When running the daemon for the first time, it will output WebUI links you can use to manage your subplebbit with the ease of the GUI.
Currently, directory assignments are temporarily handpicked by developers through GitHub pull requests. In the future, this will be fully automated through **gasless pubsub voting** (see [Future Roadmap](#future-roadmap) below), making the process completely decentralized and community-driven.

Peers can connect to your subplebbit using any plebbit client, such as 5chan or Seedit. They only need the subplebbit's address, which is not stored in any central database, as plebbit is a pure peer-to-peer protocol.
### How It Works

### How to add a board to the boards list
The boards list on 5chan is plebbit's [lists](https://github.com/plebbit/lists) repository, specifically the [5chan-multisub.json](https://github.com/plebbit/lists/blob/master/5chan-multisub.json) file. You can open a pull request in that repo to add your subplebbit to the list, or contact devs via telegram [@plebbit](https://t.me/plebbit). In the future, this process will be automated by submitting proposals to a plebbit DAO, using the [plebbit token](https://etherscan.io/token/0xea81dab2e0ecbc6b5c4172de4c22b6ef6e55bd8f).
- **Current System**: Developers manually curate directory assignments by reviewing pull requests to the [5chan-multisub.json](https://github.com/plebbit/lists/blob/master/5chan-multisub.json) file. This is temporary until DAO curation is implemented.

## To run locally
- **Future System**: Directory board assignments will be determined through gasless voting using pubsub. Community members will vote on which board should be assigned to each directory, and the highest-voted board will automatically become the directory board. This creates a competitive marketplace where board quality and community engagement determine directory placement.

1. Install Node v22 (Download from https://nodejs.org)
2. Install Yarn: `npm install -g yarn`
3. `yarn install --frozen-lockfile` to install 5chan dependencies
4. `yarn start` to run the web client
- **Accessing Boards**: Users can access any board at any time using its address, regardless of directory assignment. Boards can be accessed via the search bar, by subscribing to them (which adds them to the top bar), or by directly navigating to their address.

### Scripts:
### Future Roadmap

- Web client: `yarn start`
- Electron client (must start web client first): `yarn electron`
- Electron client and don't delete data: `yarn electron:no-delete-data`
- Web client and electron client: `yarn electron:start`
- Web client and electron client and don't delete data: `yarn electron:start:no-delete-data`
The protocol design for pubsub voting is already drafted in [plebbit-js issue #25](https://github.com/plebbit/plebbit-js/issues/25). This will enable:
- Gasless voting using pubsub topics
- Weighted voting based on token balances
- Automatic directory resolution based on vote tallies
- Full decentralization without any intermediaries

### Build:
This feature is on the plebbit-js roadmap but hasn't been implemented yet.

The linux/windows/mac/android build scripts are in https://github.com/plebbit/5chan/blob/master/.github/workflows/release.yml
## Downloads

- **Web version**: https://5chan.app (also available using Brave/IPFS Companion on https://5chan.eth)
- **Desktop version** (full P2P plebbit node, seeds automatically): Available for Mac/Windows/Linux, [download from the release page](https://github.com/plebbit/5chan/releases/latest)
- **Mobile version**: Available for Android, [download from the release page](https://github.com/plebbit/5chan/releases/latest)

## Creating a Board

In the plebbit protocol, a 5chan board is called a _subplebbit_. To create and run a subplebbit, you can choose between two options:

### Option 1: Seedit GUI Client (Recommended for beginners)

1. Download the desktop version of the Seedit client, available for Windows, macOS, and Linux: [latest release](https://github.com/plebbit/seedit/releases/latest)
2. Create a subplebbit using the familiar old.reddit-like UI
3. Modify its settings to your liking
4. Keep the app running to keep your board online (it runs an IPFS node)

### Option 2: plebbit-cli Command Line Interface

1. Install plebbit-cli, available for Windows, macOS, and Linux: [latest release](https://github.com/plebbit/plebbit-cli/releases/latest)
2. Follow the instructions in the repo's README
3. When running the daemon for the first time, it will output WebUI links you can use to manage your subplebbit with a GUI

Once created, anyone can connect to your subplebbit using any plebbit client (such as 5chan or Seedit) by using the subplebbit's address. The address is not stored in any central database—plebbit is a pure peer-to-peer protocol.

## Submitting Your Board to a Directory

To have your board appear in a directory on the 5chan homepage:

1. Ensure your board meets these requirements:
- Active and well-moderated
- Relevant to the directory category
- **99% uptime** (since a board acts like its own server—it's a P2P node)

2. Open a pull request on GitHub by editing the [5chan-multisub.json](https://github.com/plebbit/lists/blob/master/5chan-multisub.json) file

3. Add your board's entry with:
- Title
- Address
- NSFW status (if applicable)

4. The developers will review your PR and merge it if approved

**Note**: Even if your board isn't assigned to a directory, users can still access it at any time using its address. Directory assignment only affects visibility on the homepage.

## Development

### Prerequisites

- Node.js v22 (Download from https://nodejs.org)
- Yarn: `npm install -g yarn`

### Setup

1. Clone the repository
2. Install dependencies: `yarn install --frozen-lockfile`
3. Start the web client: `yarn start`

### Scripts

- **Web client**: `yarn start`
- **Electron client** (must start web client first): `yarn electron`
- **Electron client** (don't delete data): `yarn electron:no-delete-data`
- **Web client and electron client**: `yarn electron:start`
- **Web client and electron client** (don't delete data): `yarn electron:start:no-delete-data`

### Build

The Linux/Windows/macOS/Android build scripts are in [.github/workflows/release.yml](https://github.com/plebbit/5chan/blob/master/.github/workflows/release.yml)

## License

5chan is open-source software (GPLv2 license) with no owner—anyone can host their own instance on any domain. The operator of any domain is merely hosting the web app and does not own, create, moderate, or control 5chan or any board content, which is stored peer-to-peer and generated by board owners and users.
2 changes: 1 addition & 1 deletion public/translations/en/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
"show_all_boards": "Show All Boards",
"show_nsfw_content_only": "Show NSFW Content Only",
"show_nsfw_boards_only": "Show NSFW Boards Only",
"use_catalog": "use catalog",
"use_catalog": "Use Catalog",
"show_worksafe_boards_only": "Show Worksafe Boards Only",
"show_all_content": "Show All Content",
"link_type": "Link type",
Expand Down
9 changes: 9 additions & 0 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useAccountComment } from '@plebbit/plebbit-react-hooks';
import { initSnow, removeSnow } from './lib/snow';
import { isAllView, isModView, isSubscriptionsView } from './lib/utils/view-utils';
import useReplyModalStore from './stores/use-reply-modal-store';
import useDirectoryModalStore from './stores/use-directory-modal-store';
import useSpecialThemeStore from './stores/use-special-theme-store';
import useIsMobile from './hooks/use-is-mobile';
import useTheme from './hooks/use-theme';
Expand All @@ -18,6 +19,7 @@ import Post from './views/post';
import { DesktopBoardButtons, MobileBoardButtons } from './components/board-buttons';
import BoardHeader from './components/board-header';
import ChallengeModal from './components/challenge-modal';
import DirectoryModal from './components/directory-modal';
import ReplyModal from './components/reply-modal';
import PostForm from './components/post-form';
import SubplebbitStats from './components/subplebbit-stats';
Expand Down Expand Up @@ -93,13 +95,20 @@ const GlobalLayout = () => {
}, [theme]);

const { activeCid, threadCid, subplebbitAddress, closeModal, showReplyModal, scrollY } = useReplyModalStore();
const { closeDirectoryModal } = useDirectoryModalStore();

const location = useLocation();
const isInSettingsView = location.pathname.endsWith('/settings');

// Close directory modal when navigating to a different page
useEffect(() => {
closeDirectoryModal();
}, [location.pathname, closeDirectoryModal]);

return (
<>
<ChallengeModal />
<DirectoryModal />
{activeCid && threadCid && subplebbitAddress && (
<ReplyModal
closeModal={closeModal}
Expand Down
9 changes: 7 additions & 2 deletions src/components/board-header/board-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Plebbit from '@plebbit/plebbit-js';
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
import { isAllView, isSubscriptionsView, isModView } from '../../lib/utils/view-utils';
import styles from './board-header.module.css';
import { useMultisubMetadata } from '../../hooks/use-default-subplebbits';
import { useMultisubMetadata, useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
import useIsMobile from '../../hooks/use-is-mobile';
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
import { shouldShowSnow } from '../../lib/snow';
Expand Down Expand Up @@ -35,13 +35,18 @@ const BoardHeader = () => {
const { address, shortAddress } = subplebbit || {};

const multisubMetadata = useMultisubMetadata();
const defaultSubplebbits = useDefaultSubplebbits();

// Find matching subplebbit from default list to get its title
const defaultSubplebbit = subplebbitAddress ? defaultSubplebbits.find((s) => s.address === subplebbitAddress) : null;

const title = isInAllView
? multisubMetadata?.title || 'all'
: isInSubscriptionsView
? 'Subscriptions'
: isInModView
? _.startCase(t('boards_you_moderate'))
: subplebbit?.title;
: defaultSubplebbit?.title || subplebbit?.title;
const subtitle = isInAllView ? 'p/all' : isInSubscriptionsView ? 'p/subscriptions' : isInModView ? 'p/mod' : `p/${address}`;

const { isOffline, isOnlineStatusLoading, offlineIconClass, offlineTitle } = useIsSubplebbitOffline(subplebbit);
Expand Down
120 changes: 120 additions & 0 deletions src/components/directory-modal/directory-modal.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
.backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(128, 128, 128, 0.5);
z-index: 999;
}

.directoryDialog {
position: absolute;
width: 500px;
top: 50px;
left: 50%;
margin-left: -251px;
background-color: rgb(255, 255, 255);
border: 1px solid rgb(136, 0, 0);
color: rgb(136, 0, 0);
box-shadow: rgba(0, 0, 0, 0.1) 2px 2px 0px 1px;
font-family: arial, helvetica, clean, sans-serif;
font-size: 13px;
line-height: 16.003px;
z-index: 1000;
}

@media (max-width: 600px) {
.directoryDialog {
width: calc(100% - 20px);
margin-left: -50%;
left: 50%;
max-width: 500px;
}
}

.hd {
position: relative;
background-color: rgb(136, 0, 0);
color: rgb(255, 255, 255);
padding: 4px 6px;
display: flex;
justify-content: space-between;
align-items: center;
}

.hd h2 {
margin: 0;
padding: 0;
font-size: 131%;
font-weight: bold;
}

.closeButton {
all: unset;
cursor: pointer;
width: 16px;
height: 16px;
position: absolute;
top: 4px;
right: 4px;
background-image: var(--disclaimer-modal-close-button-background-image);
background-size: 100%;
background-position: center;
background-repeat: no-repeat;
}

.bd {
padding: 10px;
}

.introMessage {
font-size: 15px;
margin: 10px 0 20px 0;
text-align: center;
}

.introMessage strong {
font-weight: bold;
}

.section {
margin-bottom: 20px;
}

.section:last-child {
margin-bottom: 0;
}

.section h3 {
margin: 0 0 8px 0;
padding: 0;
font-size: 14px;
font-weight: bold;
color: rgb(136, 0, 0);
letter-spacing: 0.3px;
}

.section p {
margin: 0 0 12px 0;
font-size: 13px;
line-height: 16.003px;
}

.section p:last-child {
margin-bottom: 0;
}

.bd a {
color: rgb(136, 0, 0);
text-decoration: underline;
}

.directoryFooter {
padding: 10px;
display: flex;
justify-content: center;
gap: 10px;
}


Loading