Compare commits
23 Commits
main
...
2f5736ffde
| Author | SHA1 | Date | |
|---|---|---|---|
|
2f5736ffde
|
|||
|
b43360e32a
|
|||
|
ded3110fce
|
|||
|
6f4712e461
|
|||
|
bd3299154c
|
|||
|
8b97cbfd9b
|
|||
|
246f95a00c
|
|||
|
cc27f367ea
|
|||
|
72b8f39825
|
|||
|
c3d75140d8
|
|||
|
a45ba54323
|
|||
|
a77cdc1e58
|
|||
|
9db0aab05a
|
|||
|
320d98b2da
|
|||
|
e05868c9b1
|
|||
|
9d78ee8627
|
|||
|
16c785bf0f
|
|||
|
b5e44947da
|
|||
|
f26ef781f3
|
|||
|
b5b3850f7b
|
|||
|
c61fd5c748
|
|||
|
005ddc36cf
|
|||
|
5acaa7aeec
|
40
.github/workflows/cf-pages.yml
vendored
@@ -1,40 +0,0 @@
|
||||
name: Deploy to Cloudflare Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'web/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
working-directory: web
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
working-directory: web
|
||||
|
||||
- name: Deploy to Cloudflare Pages
|
||||
uses: cloudflare/wrangler-action@v3
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
command: pages deploy web/dist/aiat --project-name=${{ secrets.CLOUDFLARE_PROJECT_NAME }}
|
||||
38
.github/workflows/generate-record.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Generate Record JSON
|
||||
|
||||
on:
|
||||
workflow_dispatch: # 手動トリガー
|
||||
push:
|
||||
paths:
|
||||
- scpt/generate_record.py # スクリプトに変更があったとき
|
||||
schedule:
|
||||
- cron: '0 3 * * *' # 毎日03:00 UTCに自動生成(任意)
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
pip install -r requirements.txt || true # 必要なら
|
||||
|
||||
- name: Run Record Generator Script
|
||||
run: |
|
||||
python scpt/generate_record.py
|
||||
|
||||
- name: Commit and Push Generated JSON
|
||||
run: |
|
||||
git config --global user.name "GitHub Actions Bot"
|
||||
git config --global user.email "actions@github.com"
|
||||
git add record.json
|
||||
git commit -m "🧬 Auto-generate record.json" || echo "No changes to commit"
|
||||
git push origin main
|
||||
11
.gitignore
vendored
@@ -1,12 +1 @@
|
||||
repos
|
||||
.claude
|
||||
deploy.yml
|
||||
claude.md
|
||||
embedded.mobileprovision
|
||||
.env
|
||||
k8s/secrets.env
|
||||
k8s/deploy.yml
|
||||
web/dist
|
||||
node_modules
|
||||
package-lock.json
|
||||
/tmp
|
||||
|
||||
148
README.md
@@ -1,71 +1,125 @@
|
||||
# at
|
||||
|
||||
- https://github.com/bluesky-social/atproto
|
||||
- https://github.com/bluesky-social/social-app
|
||||
https://github.com/bluesky-social/atproto
|
||||
|
||||
|name|type|example|
|
||||
|word|name|example|
|
||||
|---|---|---|
|
||||
|at|uri|at://example.com|
|
||||
|@|user|@example.com|
|
||||
|at|uri|at://ai.syu.is|
|
||||
|@|user|@ai.syu.is|
|
||||
|[at]proto|repo|`git@github.com:bluesky-social/atproto`|
|
||||
|[at]mosphere|system|pds, bsky(appview), ozone, bgs, plc|
|
||||
|[a]uthenticated [t]ransfer|protocol|[did](https://www.w3.org/TR/did-core/)|
|
||||
|
||||
- https://atproto.com/ja/guides/glossary
|
||||
|
||||
## account
|
||||
|
||||
- [ai@syu.is](https://syu.is/profile/did:plc:6qyecktefllvenje24fcxnie)
|
||||
- [yui@bsky.social](https://bsky.app/profile/did:plc:6qyecktefllvenje24fcxnie)
|
||||
[@ai.syu.is](https://web.syu.is/profile/ai.syu.is)
|
||||
|
||||
- https://plc.syu.is/did:plc:6qyecktefllvenje24fcxnie
|
||||
- https://plc.directory/did:plc:6qyecktefllvenje24fcxnie
|
||||
- https://plc.directory/did:plc:ytvoptig4ddshmwdsjmhtcym
|
||||
|
||||
[@yui.syui.ai](https://bsky.app/profile/did:plc:4hqjfn7m6n5hno3doamuhgef)
|
||||
|
||||
```sh
|
||||
$ curl -sL syu.is/xrpc/_health
|
||||
{"version":"0.4.65"}
|
||||
|
||||
# latest
|
||||
# https://github.com/bluesky-social/atproto/blob/main/packages/pds/package.json
|
||||
$ curl -sL https://raw.githubusercontent.com/bluesky-social/atproto/refs/heads/main/packages/pds/package.json |jq -r .version
|
||||
```
|
||||
|
||||
```sh
|
||||
$ curl -sL "syu.is/xrpc/com.atproto.repo.describeRepo?repo=ai.syu.is" |jq -r .did
|
||||
did:plc:6qyecktefllvenje24fcxnie
|
||||
|
||||
$ curl -sL "syu.is/xrpc/com.atproto.repo.listRecords?repo=ai.syu.is&collection=app.bsky.feed.post&reverse=true&limit=1"
|
||||
{"records":[{"uri":"at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.post/3l6s2riuouk2j","cid":"bafyreibjohl7va4upkibw5twaxdd4jg3l6rmfatu4dpjjfd5xkb2ijtlx4","value":{"text":"hello","$type":"app.bsky.feed.post","langs":["ja"],"createdAt":"2024-10-18T13:21:39.809Z"}}],"cursor":"3l6s2riuouk2j"}
|
||||
```
|
||||
|
||||
## feed
|
||||
|
||||
> at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/app
|
||||
> at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/cmd
|
||||
|
||||
- https://syu.is/profile/did:plc:6qyecktefllvenje24fcxnie/feed/app
|
||||
- https://feed.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/app
|
||||
- https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd
|
||||
- https://feed.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd
|
||||
- https://desc.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/cmd
|
||||
|
||||
```json
|
||||
{
|
||||
"uri": "at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/app",
|
||||
"cid": "bafyreifme6g5mhuiwfmjaubwnkoyvwak6c6zvcy4uv3giikxvqpvhqdtau",
|
||||
"value": {
|
||||
"did": "did:web:feed.syu.is",
|
||||
"$type": "app.bsky.feed.generator",
|
||||
"avatar": {
|
||||
"$type": "blob",
|
||||
"ref": {
|
||||
"$link": "bafkreigo3ucp32carhbn3chfc3hlf6i7f4rplojc76iylihzpifyexi24y"
|
||||
},
|
||||
"mimeType": "image/jpeg",
|
||||
"size": 375259
|
||||
},
|
||||
"createdAt": "2025-12-06T09:07:32Z",
|
||||
"description": "Automated App Feed",
|
||||
"displayName": "App Feed"
|
||||
}
|
||||
}
|
||||
```
|
||||
## link
|
||||
|
||||
## build
|
||||
- https://github.com/bluesky-social/atproto
|
||||
- https://github.com/itaru2622/bluesky-selfhost-env
|
||||
- https://github.com/bluesky-social/atproto/discussions/2026
|
||||
|
||||
## self-host
|
||||
|
||||
currently, bsky and bsync require patches to function properly. additionally, social-app is not displaying avatars. for components that are not working, it's recommended to use [itaru2622/bluesky-selfhost-env](https://github.com/itaru2622/bluesky-selfhost-env). this repository provides an environment for self-hosting bluesky.
|
||||
|
||||
- bsky = appview
|
||||
- ozone = mod
|
||||
|
||||
|name|service|patch|
|
||||
|---|---|---|
|
||||
|pds|https://github.com/bluesky-social/atproto/blob/main/services/pds/Dockerfile||
|
||||
|bsky|https://github.com/bluesky-social/atproto/blob/main/services/bsky/Dockerfile|[itaru2622/bluesky-atproto-bsky](https://github.com/itaru2622/bluesky-selfhost-env/blob/master/patching/105-atproto-services-for-docker.diff)|
|
||||
|bsync|https://github.com/bluesky-social/atproto/blob/main/services/bsync/Dockerfile||
|
||||
|ozone|https://github.com/bluesky-social/atproto/blob/main/services/ozone/Dockerfile||
|
||||
|plc|https://github.com/did-method-plc/did-method-plc/tree/main/packages/server||
|
||||
|bgs|https://github.com/bluesky-social/indigo/tree/main/cmd/bigsky||
|
||||
|feed|https://github.com/bluesky-social/feed-generator||
|
||||
|web|https://github.com/bluesky-social/social-app|[bluesky-selfhost-env](https://github.com/itaru2622/bluesky-selfhost-env/blob/master/patching/160-social-app-disable-hackModifyThumbnailPath.diff)|
|
||||
|
||||
```sh
|
||||
# build
|
||||
./install.zsh
|
||||
|
||||
# build social-app
|
||||
./install.zsh pull;./install.zsh patch;./install.zsh build social-app;./install.zsh push social-app
|
||||
---
|
||||
# server
|
||||
./install.zsh
|
||||
---
|
||||
# social-app ios
|
||||
# https://appstoreconnect.apple.com/
|
||||
# https://developer.apple.com/account/resources/profiles/list
|
||||
./install.zsh pull;./ios/setup.zsh
|
||||
./ios/build.zsh
|
||||
# BSKY_IMG_URI_ENDPOINT, BSKY_BLOB_CACHE_LOC
|
||||
# avatar link example
|
||||
1. https://appview.${host}/img/avatar/plain/${did}/${cid}@jpeg
|
||||
2. https://${host}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}
|
||||
```
|
||||
|
||||
docker compose will not be published unless you write ports. it is only valid internally. add ports only for what you want to publish.
|
||||
|
||||
## api
|
||||
|
||||
```sh
|
||||
# create account
|
||||
url=https://${pds}/xrpc/com.atproto.server.createAccount
|
||||
json="{\"email\": \"$email\", \"handle\": \"$handle\", \"password\": \"$password\"}"
|
||||
curl -X POST -H "Content-Type: application/json" -d $json -sL $url
|
||||
```
|
||||
|
||||
change `src/pds/handle` to use a name of 3 characters or less. also, you cannot create an account with a name of 3 characters or less from social-app (web client). please create it from api.
|
||||
|
||||
- [/atproto/packages/pds/src/handle/index.ts](https://github.com/bluesky-social/atproto/blame/d4d5a6edba972c0e9976289bde8bc0b42ff547ca/packages/pds/src/handle/index.ts#L86-L88)
|
||||
|
||||
```sh
|
||||
# invite code
|
||||
admin_password=xxx
|
||||
url=https://$host/xrpc/com.atproto.server.createInviteCode
|
||||
json="{\"useCount\":1}"
|
||||
curl -X POST -u admin:${admin_password} -H "Content-Type: application/json" -d "$json" -sL $url
|
||||
```
|
||||
|
||||
## oauth
|
||||
|
||||
```sh
|
||||
# https://github.com/bluesky-social/cookbook/tree/main/python-oauth-web-app
|
||||
$ cd ./repos/cookbook/python-oauth-web-app
|
||||
$ rye sync
|
||||
$ rye run python3 -c 'import secrets; print(secrets.token_hex())'|xargs echo FLASK_SECRET_KEY|tr -d ' ' >> .env
|
||||
$ rye run python3 generate_jwk.py |xargs echo FLASK_CLIENT_SECRET_JWK|tr -d ' ' >> .env
|
||||
$ cat .env
|
||||
$ rye run flask run
|
||||
```
|
||||
|
||||
please access `127.0.0.1:5000`. it may not work if you use localhost.
|
||||
|
||||
also, oauth doesn't work on localhost. use [ngrok](https://ngrok.com/), [tailscale](https://tailscale.com/), [cloudflare](https://github.com/cloudflare/cloudflared).
|
||||
|
||||
```sh
|
||||
$ ngrok http http://localhost:5000
|
||||
```
|
||||
|
||||
```sh
|
||||
$ cloudflared tunnel --url http://localhost:5000
|
||||
```
|
||||
|
||||
47
at.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"atmosphere": {
|
||||
"name": "at",
|
||||
"repo": "https://github.com/bluesky-social/atproto",
|
||||
"uri": "https://atproto.com/ja/guides/glossary",
|
||||
"exosphere": {
|
||||
"km":[{ "min": 700, "max": 10000 }],
|
||||
"tag": [ "universe" ]
|
||||
},
|
||||
"thermosphere": {
|
||||
"km":[{ "min": 80, "max": 700 }],
|
||||
"tag": [ "aurora" ]
|
||||
},
|
||||
"mesosphere": {
|
||||
"km":[{ "min": 50, "max": 80 }],
|
||||
"tag": [ "meteor" ]
|
||||
},
|
||||
"stratosphere": {
|
||||
"km":[{ "min": 12, "max": 50 }],
|
||||
"tag": [ "ozone", "bigsky" ],
|
||||
"service":[
|
||||
{ "name":"ozone", "repo":"https://github.com/bluesky-social/atproto/tree/main/services/ozone" },
|
||||
{ "name":"bgs", "repo":"https://github.com/bluesky-social/indigo/tree/main/cmd/bigsky" }
|
||||
]
|
||||
},
|
||||
"troposphere": {
|
||||
"km":[{ "min": 0, "max": 12 }],
|
||||
"tag": [ "bluesky"],
|
||||
"service":[
|
||||
{ "name":"bsky", "repo":"https://github.com/bluesky-social/atproto/tree/main/services/bsky", "tag":[ "api", "appview" ] },
|
||||
{ "name":"bsync","repo":"https://github.com/bluesky-social/atproto/tree/main/services/bsync" },
|
||||
{ "name":"pds", "repo":"https://github.com/bluesky-social/atproto/tree/main/services/pds" }
|
||||
]
|
||||
},
|
||||
"other": {
|
||||
"tag": [ "plc", "feed", "oauth", "social-app", "stream" ],
|
||||
"service":[
|
||||
{ "name":"plc", "repo":"https://github.com/did-method-plc/did-method-plc/tree/main/packages/server", "tag" : [ "did" ] },
|
||||
{ "name":"social-app", "repo":"https://github.com/bluesky-social/social-app", "tag": [ "web" ] },
|
||||
{ "name":"oauth", "repo":"https://github.com/bluesky-social/cookbook/tree/main/python-oauth-web-app" },
|
||||
{ "name":"feed", "repo":"https://github.com/bluesky-social/feed-generator" },
|
||||
{ "name":"stream", "repo":"https://github.com/bluesky-social/jetstream" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"ref": "https://en.wikipedia.org/wiki/Atmosphere_of_Earth"
|
||||
}
|
||||
129
compose.yml
@@ -48,11 +48,36 @@ services:
|
||||
- ./envs/pds
|
||||
volumes:
|
||||
- ./data/pds/:/data/
|
||||
command: node --enable-source-maps index.js
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
|
||||
bgs:
|
||||
ports:
|
||||
- 2470:2470
|
||||
build:
|
||||
context: ./repos/indigo/
|
||||
dockerfile: cmd/bigsky/Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/bgs
|
||||
volumes:
|
||||
- ./data/bgs/:/data/
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
|
||||
social-app:
|
||||
ports:
|
||||
- 8100:8100
|
||||
build:
|
||||
context: ./repos/social-app/
|
||||
dockerfile: Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/social-app
|
||||
command: "/usr/bin/bskyweb serve"
|
||||
|
||||
bsky:
|
||||
ports:
|
||||
- 2584:2584
|
||||
@@ -72,67 +97,6 @@ services:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
bgs:
|
||||
ports:
|
||||
- 2470:2470
|
||||
build:
|
||||
context: ./repos/indigo/
|
||||
dockerfile: cmd/relay/Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/bgs
|
||||
volumes:
|
||||
- ./data/bgs/:/data/
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
#command: ["/bigsky", "--crawl-insecure-ws"]
|
||||
|
||||
social-app:
|
||||
ports:
|
||||
- 8100:8100
|
||||
build:
|
||||
context: ./repos/social-app/
|
||||
dockerfile: Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/social-app
|
||||
command: "/usr/bin/bskyweb serve"
|
||||
|
||||
ozone:
|
||||
ports:
|
||||
- 2585:3000
|
||||
build:
|
||||
context: ./repos/atproto/
|
||||
dockerfile: services/ozone/Dockerfile
|
||||
restart: always
|
||||
command: node --enable-source-maps api.js
|
||||
volumes:
|
||||
- ./data/ozone/:/data/
|
||||
env_file:
|
||||
- ./envs/ozone
|
||||
healthcheck:
|
||||
test: "wget -q --spider http://localhost:3000/xrpc/_health"
|
||||
interval: 5s
|
||||
retries: 20
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
|
||||
ozone-web:
|
||||
ports:
|
||||
- 2586:3000
|
||||
build:
|
||||
context: ./repos/ozone/
|
||||
restart: always
|
||||
volumes:
|
||||
- ./data/ozone/:/data/
|
||||
env_file:
|
||||
- ./envs/ozone
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
|
||||
jetstream:
|
||||
build:
|
||||
context: ./repos/jetstream/
|
||||
@@ -145,15 +109,40 @@ services:
|
||||
env_file:
|
||||
- ./envs/jetstream
|
||||
|
||||
feed:
|
||||
ports:
|
||||
- 2587:3000
|
||||
ozone-web:
|
||||
build:
|
||||
context: ./repos/feed-generator/
|
||||
context: ./repos/ozone/
|
||||
ports:
|
||||
- 2586:3000
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/feed
|
||||
volumes:
|
||||
- ./data/feed:/data/
|
||||
- ./data/ozone/:/data/
|
||||
env_file:
|
||||
- ./envs/ozone
|
||||
depends_on:
|
||||
- jetstream
|
||||
database:
|
||||
condition: service_healthy
|
||||
|
||||
ozone:
|
||||
build:
|
||||
context: ./repos/atproto/
|
||||
dockerfile: services/ozone/Dockerfile
|
||||
ports:
|
||||
- 2585:3000
|
||||
restart: always
|
||||
command: node --enable-source-maps api.js
|
||||
volumes:
|
||||
- ./data/ozone/:/data/
|
||||
env_file:
|
||||
- ./envs/ozone
|
||||
|
||||
ozone-daemon:
|
||||
build:
|
||||
context: ./repos/atproto/
|
||||
dockerfile: services/ozone/Dockerfile
|
||||
restart: always
|
||||
command: node --enable-source-maps daemon.js
|
||||
volumes:
|
||||
- ./data/ozone/:/data/
|
||||
env_file:
|
||||
- ./envs/ozone
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies for better-sqlite3
|
||||
RUN apk add --no-cache python3 make g++
|
||||
|
||||
# Copy package files and install
|
||||
COPY package.json yarn.lock ./
|
||||
RUN yarn install
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Build TypeScript
|
||||
RUN yarn build
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["node", "dist/index.js"]
|
||||
4
envs/bgs
@@ -2,5 +2,5 @@ DATABASE_URL=postgres://postgres:postgres@database/bgs
|
||||
CARSTORE_DATABASE_URL=postgres://postgres:postgres@database/carstore
|
||||
DATA_DIR=/data
|
||||
ATP_PLC_HOST=https://plc.${host}
|
||||
BGS_NEW_PDS_PER_DAY_LIMIT=1000
|
||||
BGS_ADMIN_KEY=
|
||||
|
||||
BGS_ADMIN_KEY
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
FEEDGEN_PORT=3000
|
||||
FEEDGEN_LISTENHOST=0.0.0.0
|
||||
FEEDGEN_SQLITE_LOCATION=/data/db.sqlite
|
||||
FEEDGEN_HOSTNAME=feed.syu.is
|
||||
FEEDGEN_PUBLISHER_DID=did:plc:6qyecktefllvenje24fcxnie
|
||||
FEEDGEN_SERVICE_DID=did:web:feed.syu.is
|
||||
FEEDGEN_JETSTREAM_URL=ws://jetstream:6008/subscribe
|
||||
@@ -1,4 +1,4 @@
|
||||
JETSTREAM_WS_URL=ws://bgs.${host}/xrpc/com.atproto.sync.subscribeRepos
|
||||
JETSTREAM_WS_URL=wss://bgs.${host}/xrpc/com.atproto.sync.subscribeRepos
|
||||
JETSTREAM_DATA_DIR=/data
|
||||
JETSTREAM_LISTEN_ADDR=:6008
|
||||
JETSTREAM_METRICS_LISTEN_ADDR=:6009
|
||||
|
||||
@@ -7,8 +7,8 @@ OZONE_DB_POSTGRES_URL=postgres://postgres:postgres@database/ozone
|
||||
OZONE_DID_PLC_URL=https://plc.${host}
|
||||
NEXT_PUBLIC_PLC_DIRECTORY_URL=https://plc.${host}
|
||||
NEXT_PUBLIC_OZONE_SERVICE_DID=did:web:ozone.${host}
|
||||
NEXT_PUBLIC_SOCIAL_APP_DOMAIN=${host}
|
||||
NEXT_PUBLIC_SOCIAL_APP_URL=https://${host}
|
||||
NEXT_PUBLIC_SOCIAL_APP_DOMAIN=mod.${host}
|
||||
NEXT_PUBLIC_SOCIAL_APP_URL=https://mod.${host}
|
||||
OZONE_APPVIEW_DID=did:web:bsky.${host}
|
||||
OZONE_APPVIEW_URL=https://bsky.${host}
|
||||
OZONE_APPVIEW_PUSH_EVENTS=false
|
||||
@@ -25,5 +25,3 @@ OZONE_VERIFIER_DID
|
||||
OZONE_VERIFIER_PASSWORD
|
||||
OZONE_VERIFIER_ISSUERS_TO_INDEX
|
||||
OZONE_VERIFIER_JETSTREAM_URL
|
||||
|
||||
OZONE_APPVIEW_PUSH_EVENTS=true
|
||||
|
||||
2
envs/pds
@@ -6,8 +6,6 @@ PDS_BLOBSTORE_DISK_LOCATION=/data/img/static
|
||||
PDS_BSKY_APP_VIEW_DID=did:web:bsky.${host}
|
||||
PDS_BSKY_APP_VIEW_URL=https://bsky.${host}
|
||||
PDS_CRAWLERS=https://bgs.${host}
|
||||
PDS_SEQUENCER_ENABLED=true
|
||||
PDS_SEQUENCER_DB_LOCATION=/data/sequencer.sqlite
|
||||
PDS_DEV_MODE=true
|
||||
PDS_DID_PLC_URL=https://plc.${host}
|
||||
PDS_ENABLE_DID_DOC_WITH_SESSION=true
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
ATP_APPVIEW_HOST=https://public.api.bsky.app
|
||||
EXPO_PUBLIC_BLUESKY_PROXY_DID=did:web:api.bsky.app
|
||||
EXPO_PUBLIC_ENV=production
|
||||
ATP_APPVIEW_HOST=https://bsky.${host}
|
||||
|
||||
52
icons/Logotype.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import React from 'react'
|
||||
import Svg, {Path, SvgProps, PathProps} from 'react-native-svg'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
|
||||
const ratio = 17 / 64
|
||||
|
||||
export function Logotype({
|
||||
fill,
|
||||
...rest
|
||||
}: {fill?: PathProps['fill']} & SvgProps) {
|
||||
const pal = usePalette('default')
|
||||
// @ts-ignore it's fiiiiine
|
||||
const size = parseInt(rest.width || 32)
|
||||
|
||||
return (
|
||||
<Svg
|
||||
fill="none"
|
||||
viewBox="0 0 2821.6379 794.29016"
|
||||
{...rest}
|
||||
width={size}
|
||||
height={Number(size) * ratio}>
|
||||
<g
|
||||
transform="matrix(0.1,0,0,-0.1,-282.80153,1445)"
|
||||
fill="#000000"
|
||||
stroke="none"
|
||||
>
|
||||
<path
|
||||
d="m 24787,14443 c -4,-3 -7,-224 -7,-490 v -483 h 545 545 v 490 490 h -538 c -296,0 -542,-3 -545,-7 z"
|
||||
/>
|
||||
<path
|
||||
d="m 5190,13285 c -8,-3 -96,-12 -195,-20 -199,-16 -296,-32 -430,-70 -49,-14 -115,-32 -145,-40 -153,-39 -504,-198 -662,-301 -21,-13 -57,-36 -80,-51 -24,-16 -72,-50 -109,-78 -241,-182 -377,-315 -528,-517 -119,-158 -120,-160 -106,-188 23,-45 140,-140 560,-457 110,-84 319,-242 465,-353 146,-110 369,-279 495,-375 791,-600 723,-549 1049,-799 269,-207 398,-307 524,-403 l 114,-86 -49,-49 c -128,-131 -378,-258 -588,-299 -66,-13 -357,-13 -420,0 -115,23 -172,39 -202,54 -18,10 -37,17 -43,17 -24,0 -171,81 -255,141 -50,35 -146,121 -215,192 -69,70 -133,127 -142,127 -19,0 -153,-63 -177,-83 -9,-7 -54,-35 -101,-62 -47,-26 -110,-64 -140,-85 -30,-20 -97,-61 -148,-91 -51,-30 -107,-62 -124,-72 -18,-10 -57,-38 -87,-61 -70,-53 -252,-168 -446,-281 -82,-49 -158,-95 -168,-104 -16,-16 -14,-21 34,-106 165,-289 544,-666 867,-860 9,-6 35,-22 58,-37 36,-23 267,-138 349,-173 108,-47 160,-67 240,-93 150,-48 201,-62 228,-62 14,0 64,-9 109,-19 197,-46 302,-56 573,-56 197,1 281,5 345,17 47,9 110,19 141,22 31,3 75,13 99,21 23,8 56,15 72,15 17,0 51,7 77,15 25,8 80,24 121,36 41,12 125,41 185,66 61,25 124,50 140,56 17,7 89,42 160,78 113,58 177,98 395,246 82,56 273,232 403,371 127,136 237,271 237,291 0,12 -208,179 -425,342 -186,140 -1121,843 -1720,1294 -264,199 -589,444 -723,546 -134,101 -274,208 -312,237 -39,29 -70,58 -70,66 0,21 107,115 203,179 95,64 237,133 295,143 20,4 49,12 63,20 96,48 519,48 619,-1 14,-7 41,-16 60,-20 65,-13 262,-118 360,-191 99,-74 250,-230 372,-384 34,-44 70,-80 80,-80 9,0 39,15 67,33 28,17 70,44 94,58 23,15 121,76 217,136 96,60 254,156 350,213 96,56 272,160 390,230 118,70 230,135 248,144 41,21 41,45 -3,116 -18,30 -46,75 -61,100 -64,106 -252,348 -352,454 -106,112 -169,171 -293,274 -197,164 -310,235 -594,376 -215,106 -519,205 -735,240 -137,22 -574,51 -610,41 z"
|
||||
/>
|
||||
<path
|
||||
d="m 29095,12736 c -421,-44 -744,-157 -975,-342 -259,-207 -396,-446 -465,-809 -16,-84 -23,-301 -14,-425 36,-518 257,-859 694,-1070 166,-80 284,-116 716,-215 449,-103 514,-121 646,-186 218,-107 308,-253 306,-494 -2,-303 -188,-477 -588,-551 -140,-26 -640,-27 -825,-1 -275,38 -486,94 -776,203 -94,35 -174,64 -178,64 -3,0 -6,-175 -6,-389 v -388 l 88,-41 c 404,-187 905,-282 1486,-282 675,0 1154,150 1465,459 196,194 311,434 362,756 20,121 17,476 -5,600 -89,517 -358,800 -945,994 -130,43 -241,71 -616,156 -137,31 -299,73 -360,92 -331,106 -455,246 -455,511 1,249 127,412 387,501 272,92 801,76 1269,-39 116,-28 326,-96 432,-138 l 52,-22 -2,406 -3,406 -66,28 c -154,66 -413,140 -604,174 -279,49 -756,69 -1020,42 z"
|
||||
/>
|
||||
<path
|
||||
d="m 9630,12676 c 0,-2 403,-996 896,-2208 493,-1211 898,-2211 901,-2220 6,-21 -135,-386 -193,-499 -104,-202 -256,-324 -471,-380 -118,-30 -340,-43 -516,-29 -84,6 -185,17 -225,24 -40,7 -75,10 -77,7 -3,-2 -5,-163 -5,-357 v -353 l 63,-30 c 194,-93 493,-138 801,-120 414,23 683,115 937,319 174,140 357,402 474,680 26,62 1945,5159 1945,5167 0,2 -232,2 -516,1 l -517,-3 -556,-1550 c -485,-1350 -560,-1550 -578,-1553 -18,-3 -26,11 -62,105 -23,59 -295,758 -605,1553 l -562,1445 -567,3 c -312,1 -567,0 -567,-2 z"
|
||||
/>
|
||||
<path
|
||||
d="m 15690,10867 c 0,-1970 -1,-1936 56,-2153 128,-497 461,-787 1014,-885 147,-26 440,-36 605,-20 413,40 834,200 1181,447 35,25 73,44 88,44 14,0 26,-1 26,-3 0,-2 20,-94 45,-205 25,-111 45,-204 45,-207 0,-3 209,-5 465,-5 h 465 v 2400 2400 h -535 -535 l -2,-1866 -3,-1866 -115,-50 c -425,-185 -743,-252 -1088,-227 -302,21 -472,109 -562,293 -79,161 -74,11 -77,1969 l -3,1747 h -535 -535 z"
|
||||
/>
|
||||
<path
|
||||
d="m 24785,12668 c -3,-7 -4,-1086 -3,-2398 l 3,-2385 538,-3 537,-2 v 2400 2400 h -535 c -419,0 -537,-3 -540,-12 z"
|
||||
/>
|
||||
<path
|
||||
d="m 21660,8275 v -545 h 565 565 v 545 545 h -565 -565 z"
|
||||
/>
|
||||
</g>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
32
icons/title.svg
Normal file
@@ -0,0 +1,32 @@
|
||||
<svg
|
||||
viewBox="0 0 2821.6379 794.29016"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<g
|
||||
transform="matrix(0.1,0,0,-0.1,-282.80153,1445)"
|
||||
fill="#000000"
|
||||
stroke="none"
|
||||
>
|
||||
<path
|
||||
d="m 24787,14443 c -4,-3 -7,-224 -7,-490 v -483 h 545 545 v 490 490 h -538 c -296,0 -542,-3 -545,-7 z"
|
||||
/>
|
||||
<path
|
||||
d="m 5190,13285 c -8,-3 -96,-12 -195,-20 -199,-16 -296,-32 -430,-70 -49,-14 -115,-32 -145,-40 -153,-39 -504,-198 -662,-301 -21,-13 -57,-36 -80,-51 -24,-16 -72,-50 -109,-78 -241,-182 -377,-315 -528,-517 -119,-158 -120,-160 -106,-188 23,-45 140,-140 560,-457 110,-84 319,-242 465,-353 146,-110 369,-279 495,-375 791,-600 723,-549 1049,-799 269,-207 398,-307 524,-403 l 114,-86 -49,-49 c -128,-131 -378,-258 -588,-299 -66,-13 -357,-13 -420,0 -115,23 -172,39 -202,54 -18,10 -37,17 -43,17 -24,0 -171,81 -255,141 -50,35 -146,121 -215,192 -69,70 -133,127 -142,127 -19,0 -153,-63 -177,-83 -9,-7 -54,-35 -101,-62 -47,-26 -110,-64 -140,-85 -30,-20 -97,-61 -148,-91 -51,-30 -107,-62 -124,-72 -18,-10 -57,-38 -87,-61 -70,-53 -252,-168 -446,-281 -82,-49 -158,-95 -168,-104 -16,-16 -14,-21 34,-106 165,-289 544,-666 867,-860 9,-6 35,-22 58,-37 36,-23 267,-138 349,-173 108,-47 160,-67 240,-93 150,-48 201,-62 228,-62 14,0 64,-9 109,-19 197,-46 302,-56 573,-56 197,1 281,5 345,17 47,9 110,19 141,22 31,3 75,13 99,21 23,8 56,15 72,15 17,0 51,7 77,15 25,8 80,24 121,36 41,12 125,41 185,66 61,25 124,50 140,56 17,7 89,42 160,78 113,58 177,98 395,246 82,56 273,232 403,371 127,136 237,271 237,291 0,12 -208,179 -425,342 -186,140 -1121,843 -1720,1294 -264,199 -589,444 -723,546 -134,101 -274,208 -312,237 -39,29 -70,58 -70,66 0,21 107,115 203,179 95,64 237,133 295,143 20,4 49,12 63,20 96,48 519,48 619,-1 14,-7 41,-16 60,-20 65,-13 262,-118 360,-191 99,-74 250,-230 372,-384 34,-44 70,-80 80,-80 9,0 39,15 67,33 28,17 70,44 94,58 23,15 121,76 217,136 96,60 254,156 350,213 96,56 272,160 390,230 118,70 230,135 248,144 41,21 41,45 -3,116 -18,30 -46,75 -61,100 -64,106 -252,348 -352,454 -106,112 -169,171 -293,274 -197,164 -310,235 -594,376 -215,106 -519,205 -735,240 -137,22 -574,51 -610,41 z"
|
||||
/>
|
||||
<path
|
||||
d="m 29095,12736 c -421,-44 -744,-157 -975,-342 -259,-207 -396,-446 -465,-809 -16,-84 -23,-301 -14,-425 36,-518 257,-859 694,-1070 166,-80 284,-116 716,-215 449,-103 514,-121 646,-186 218,-107 308,-253 306,-494 -2,-303 -188,-477 -588,-551 -140,-26 -640,-27 -825,-1 -275,38 -486,94 -776,203 -94,35 -174,64 -178,64 -3,0 -6,-175 -6,-389 v -388 l 88,-41 c 404,-187 905,-282 1486,-282 675,0 1154,150 1465,459 196,194 311,434 362,756 20,121 17,476 -5,600 -89,517 -358,800 -945,994 -130,43 -241,71 -616,156 -137,31 -299,73 -360,92 -331,106 -455,246 -455,511 1,249 127,412 387,501 272,92 801,76 1269,-39 116,-28 326,-96 432,-138 l 52,-22 -2,406 -3,406 -66,28 c -154,66 -413,140 -604,174 -279,49 -756,69 -1020,42 z"
|
||||
/>
|
||||
<path
|
||||
d="m 9630,12676 c 0,-2 403,-996 896,-2208 493,-1211 898,-2211 901,-2220 6,-21 -135,-386 -193,-499 -104,-202 -256,-324 -471,-380 -118,-30 -340,-43 -516,-29 -84,6 -185,17 -225,24 -40,7 -75,10 -77,7 -3,-2 -5,-163 -5,-357 v -353 l 63,-30 c 194,-93 493,-138 801,-120 414,23 683,115 937,319 174,140 357,402 474,680 26,62 1945,5159 1945,5167 0,2 -232,2 -516,1 l -517,-3 -556,-1550 c -485,-1350 -560,-1550 -578,-1553 -18,-3 -26,11 -62,105 -23,59 -295,758 -605,1553 l -562,1445 -567,3 c -312,1 -567,0 -567,-2 z"
|
||||
/>
|
||||
<path
|
||||
d="m 15690,10867 c 0,-1970 -1,-1936 56,-2153 128,-497 461,-787 1014,-885 147,-26 440,-36 605,-20 413,40 834,200 1181,447 35,25 73,44 88,44 14,0 26,-1 26,-3 0,-2 20,-94 45,-205 25,-111 45,-204 45,-207 0,-3 209,-5 465,-5 h 465 v 2400 2400 h -535 -535 l -2,-1866 -3,-1866 -115,-50 c -425,-185 -743,-252 -1088,-227 -302,21 -472,109 -562,293 -79,161 -74,11 -77,1969 l -3,1747 h -535 -535 z"
|
||||
/>
|
||||
<path
|
||||
d="m 24785,12668 c -3,-7 -4,-1086 -3,-2398 l 3,-2385 538,-3 537,-2 v 2400 2400 h -535 c -419,0 -537,-3 -540,-12 z"
|
||||
/>
|
||||
<path
|
||||
d="m 21660,8275 v -545 h 565 565 v 545 545 h -565 -565 z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
978
install.zsh
@@ -1,17 +0,0 @@
|
||||
APP_NAME="Aiat"
|
||||
REPO_DIR="../repos/social-app"
|
||||
APP_SLUG="aiat"
|
||||
APP_SCHEME="syui"
|
||||
APP_GROUP="group.ai.syui.at"
|
||||
APP_MAIL=user@example.com
|
||||
APP_KEYCHAIN=@keychain:KEYCHAIN_NAME
|
||||
BUNDLE_ID="ai.syui.at"
|
||||
SERVICE_URL="https://syu.is"
|
||||
HELP_URL="https://syu.is/about/support/help"
|
||||
PRIVACY_URL="https://syu.is/about/support/privacy-policy"
|
||||
TERMS_URL="https://syu.is/about/support/tos"
|
||||
REPO_DIR="../repos/social-app"
|
||||
CONFIG_FILE="$REPO_DIR/app.config.js"
|
||||
CONSTANTS_FILE="$REPO_DIR/src/lib/constants.ts"
|
||||
IOS_CERTIFICATE_NAME="Apple Distribution: $TEAM($TEAM_ID)"
|
||||
PDS_HOST=syu.is
|
||||
@@ -1,7 +0,0 @@
|
||||
This document summarizes the key points for the ./ios (social-app) development.
|
||||
|
||||
1. Comply with the MIT license and ensure it can be published as an iOS app without issues
|
||||
2. Do not use the "Bluesky" name. Change icons and links accordingly
|
||||
3. Must work with self-hosted instances
|
||||
|
||||
https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/LICENSE
|
||||
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 821 B |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 821 B |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"fill" : {
|
||||
"automatic-gradient" : "srgb:0.00000,0.41569,1.00000,1.00000"
|
||||
},
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"fill" : "none",
|
||||
"glass" : false,
|
||||
"image-name" : "iOS transparent.png",
|
||||
"name" : "iOS transparent"
|
||||
}
|
||||
],
|
||||
"shadow" : {
|
||||
"kind" : "neutral",
|
||||
"opacity" : 0.5
|
||||
},
|
||||
"translucency" : {
|
||||
"enabled" : true,
|
||||
"value" : 0.5
|
||||
}
|
||||
}
|
||||
],
|
||||
"supported-platforms" : {
|
||||
"circles" : [
|
||||
"watchOS"
|
||||
],
|
||||
"squares" : "shared"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 536 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M237.9 461.4C237.9 463.4 235.6 465 232.7 465C229.4 465.3 227.1 463.7 227.1 461.4C227.1 459.4 229.4 457.8 232.3 457.8C235.3 457.5 237.9 459.1 237.9 461.4zM206.8 456.9C206.1 458.9 208.1 461.2 211.1 461.8C213.7 462.8 216.7 461.8 217.3 459.8C217.9 457.8 216 455.5 213 454.6C210.4 453.9 207.5 454.9 206.8 456.9zM251 455.2C248.1 455.9 246.1 457.8 246.4 460.1C246.7 462.1 249.3 463.4 252.3 462.7C255.2 462 257.2 460.1 256.9 458.1C256.6 456.2 253.9 454.9 251 455.2zM316.8 72C178.1 72 72 177.3 72 316C72 426.9 141.8 521.8 241.5 555.2C254.3 557.5 258.8 549.6 258.8 543.1C258.8 536.9 258.5 502.7 258.5 481.7C258.5 481.7 188.5 496.7 173.8 451.9C173.8 451.9 162.4 422.8 146 415.3C146 415.3 123.1 399.6 147.6 399.9C147.6 399.9 172.5 401.9 186.2 425.7C208.1 464.3 244.8 453.2 259.1 446.6C261.4 430.6 267.9 419.5 275.1 412.9C219.2 406.7 162.8 398.6 162.8 302.4C162.8 274.9 170.4 261.1 186.4 243.5C183.8 237 175.3 210.2 189 175.6C209.9 169.1 258 202.6 258 202.6C278 197 299.5 194.1 320.8 194.1C342.1 194.1 363.6 197 383.6 202.6C383.6 202.6 431.7 169 452.6 175.6C466.3 210.3 457.8 237 455.2 243.5C471.2 261.2 481 275 481 302.4C481 398.9 422.1 406.6 366.2 412.9C375.4 420.8 383.2 435.8 383.2 459.3C383.2 493 382.9 534.7 382.9 542.9C382.9 549.4 387.5 557.3 400.2 555C500.2 521.8 568 426.9 568 316C568 177.3 455.5 72 316.8 72zM169.2 416.9C167.9 417.9 168.2 420.2 169.9 422.1C171.5 423.7 173.8 424.4 175.1 423.1C176.4 422.1 176.1 419.8 174.4 417.9C172.8 416.3 170.5 415.6 169.2 416.9zM158.4 408.8C157.7 410.1 158.7 411.7 160.7 412.7C162.3 413.7 164.3 413.4 165 412C165.7 410.7 164.7 409.1 162.7 408.1C160.7 407.5 159.1 407.8 158.4 408.8zM190.8 444.4C189.2 445.7 189.8 448.7 192.1 450.6C194.4 452.9 197.3 453.2 198.6 451.6C199.9 450.3 199.3 447.3 197.3 445.4C195.1 443.1 192.1 442.8 190.8 444.4zM179.4 429.7C177.8 430.7 177.8 433.3 179.4 435.6C181 437.9 183.7 438.9 185 437.9C186.6 436.6 186.6 434 185 431.7C183.6 429.4 181 428.4 179.4 429.7z"/></svg>
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M453.2 112L523.8 112L369.6 288.2L551 528L409 528L297.7 382.6L170.5 528L99.8 528L264.7 339.5L90.8 112L236.4 112L336.9 244.9L453.2 112zM428.4 485.8L467.5 485.8L215.1 152L173.1 152L428.4 485.8z"/></svg>
|
||||
|
Before Width: | Height: | Size: 421 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M581.7 188.1C575.5 164.4 556.9 145.8 533.4 139.5C490.9 128 320.1 128 320.1 128C320.1 128 149.3 128 106.7 139.5C83.2 145.8 64.7 164.4 58.4 188.1C47 231 47 320.4 47 320.4C47 320.4 47 409.8 58.4 452.7C64.7 476.3 83.2 494.2 106.7 500.5C149.3 512 320.1 512 320.1 512C320.1 512 490.9 512 533.5 500.5C557 494.2 575.5 476.3 581.8 452.7C593.2 409.8 593.2 320.4 593.2 320.4C593.2 320.4 593.2 231 581.8 188.1zM264.2 401.6L264.2 239.2L406.9 320.4L264.2 401.6z"/></svg>
|
||||
|
Before Width: | Height: | Size: 678 B |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.7 MiB |
212
ios/build.zsh
@@ -1,212 +0,0 @@
|
||||
#!/bin/zsh
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR=${0:a:h}
|
||||
cd "$SCRIPT_DIR"
|
||||
source .env
|
||||
|
||||
function sediment() {
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' "$@"
|
||||
else
|
||||
sed -i "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# 絶対パスに変換
|
||||
REPO_DIR="$SCRIPT_DIR/../repos/social-app"
|
||||
APP_NAME="Aiat"
|
||||
WORKSPACE="$REPO_DIR/ios/${APP_NAME}.xcworkspace"
|
||||
SCHEME="$APP_NAME"
|
||||
BUILD_DIR="$REPO_DIR/build"
|
||||
MOBILEPROVISION="$REPO_DIR/embedded.mobileprovision"
|
||||
ASSETS_DIR="$SCRIPT_DIR/assets"
|
||||
|
||||
echo "Running iOS preview workflow..."
|
||||
cd "$REPO_DIR"
|
||||
|
||||
# 0. Environment Setup (Fix Node Version)
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
|
||||
echo "Checking Node version..."
|
||||
if command -v nvm >/dev/null; then
|
||||
nvm use 22 || nvm use 20 || echo "Warning: Could not switch to Node 22/20. Current: $(node -v)"
|
||||
else
|
||||
echo "nvm not found, using system node: $(node -v)"
|
||||
fi
|
||||
|
||||
# 1. Install dependencies
|
||||
echo "1. Installing dependencies (yarn)..."
|
||||
yarn install
|
||||
|
||||
# 1.5. Copy assets
|
||||
echo "1.5. Copying assets..."
|
||||
if [ -d "$ASSETS_DIR" ]; then
|
||||
cp -rf "$ASSETS_DIR/"* "$REPO_DIR/assets/"
|
||||
echo "✅ Copied all assets (including logo.png, logo-1024.png)"
|
||||
else
|
||||
echo "⚠️ Warning: $ASSETS_DIR not found"
|
||||
fi
|
||||
|
||||
function cleanup_build {
|
||||
# 1.8. Update package.json version (prevent App Store version conflict)
|
||||
echo "1.8. Updating package.json version..."
|
||||
if [ -n "$APP_VERSION" ]; then
|
||||
# Use node to update version in package.json (already in REPO_DIR)
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
||||
pkg.version = '$APP_VERSION';
|
||||
fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\n');
|
||||
"
|
||||
echo " ✅ Set version to $APP_VERSION"
|
||||
else
|
||||
echo " ⚠️ APP_VERSION not set in .env"
|
||||
fi
|
||||
|
||||
# 1.9. Update buildNumber (CFBundleVersion) with current timestamp
|
||||
echo "1.9. Updating buildNumber..."
|
||||
local build_number=$(date +%y%m%d%H%M%S)
|
||||
sediment "s/buildNumber: '[0-9]*'/buildNumber: '${build_number}'/" "./app.config.js"
|
||||
echo " ✅ Set buildNumber to $build_number"
|
||||
|
||||
# 2. Prebuild (Generate ios directory)
|
||||
echo "2. Running Expo Prebuild..."
|
||||
# Clean old ios folder to remove old entitlements/AppClip targets
|
||||
rm -rf ios
|
||||
npx expo prebuild --platform ios --clean
|
||||
|
||||
# 3. CocoaPods
|
||||
echo "3. Installing CocoaPods..."
|
||||
if [ -z "$1" ];then
|
||||
cd ios
|
||||
pod install
|
||||
cd ..
|
||||
fi
|
||||
|
||||
# 4. Signing (Automated)
|
||||
echo "4. Configuring Xcode Signing..."
|
||||
XCODE_PROJ="ios/${APP_NAME}.xcodeproj"
|
||||
if [ ! -d "$XCODE_PROJ" ]; then
|
||||
XCODE_PROJ=$(find ios -name "*.xcodeproj" | head -n 1)
|
||||
fi
|
||||
PBXPROJ="$XCODE_PROJ/project.pbxproj"
|
||||
|
||||
# Set DEVELOPMENT_TEAM in pbxproj
|
||||
if [ -n "$DEVELOPMENT_TEAM" ]; then
|
||||
echo " Setting DEVELOPMENT_TEAM=$DEVELOPMENT_TEAM"
|
||||
sediment "s/PRODUCT_BUNDLE_IDENTIFIER = /DEVELOPMENT_TEAM = $DEVELOPMENT_TEAM; PRODUCT_BUNDLE_IDENTIFIER = /g" "$PBXPROJ"
|
||||
sediment "s/DEVELOPMENT_TEAM = \"\";/DEVELOPMENT_TEAM = $DEVELOPMENT_TEAM;/g" "$PBXPROJ"
|
||||
sediment "s/DEVELOPMENT_TEAM = ;/DEVELOPMENT_TEAM = $DEVELOPMENT_TEAM;/g" "$PBXPROJ"
|
||||
fi
|
||||
|
||||
# Create/Update entitlements file with App Group
|
||||
ENTITLEMENTS_FILE="ios/${APP_NAME}/${APP_NAME}.entitlements"
|
||||
if [ -n "$APP_GROUP" ]; then
|
||||
echo " Setting APP_GROUP=$APP_GROUP"
|
||||
cat > "$ENTITLEMENTS_FILE" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>production</string>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>${APP_GROUP}</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
if ! grep -q "CODE_SIGN_ENTITLEMENTS" "$PBXPROJ"; then
|
||||
sediment "s/DEVELOPMENT_TEAM = $DEVELOPMENT_TEAM;/DEVELOPMENT_TEAM = $DEVELOPMENT_TEAM; CODE_SIGN_ENTITLEMENTS = ${APP_NAME}\\/${APP_NAME}.entitlements;/g" "$PBXPROJ"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✅ Signing configured automatically"
|
||||
|
||||
# (Old manual step - commented out)
|
||||
# open "$XCODE_PROJ"
|
||||
# read
|
||||
}
|
||||
|
||||
case $1 in
|
||||
i)
|
||||
echo "Skipping cleanup_build..."
|
||||
;;
|
||||
*)
|
||||
cleanup_build
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Building $APP_NAME for App Store upload..."
|
||||
|
||||
# ビルドディレクトリ作成
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
||||
# アーカイブ(詳細ログ出力)
|
||||
xcodebuild -workspace "$WORKSPACE" \
|
||||
-scheme "$SCHEME" \
|
||||
-configuration Release \
|
||||
-archivePath "$BUILD_DIR/${APP_NAME}.xcarchive" \
|
||||
-allowProvisioningUpdates \
|
||||
DEVELOPMENT_TEAM="$DEVELOPMENT_TEAM" \
|
||||
archive 2>&1 | tee "$BUILD_DIR/build.log"
|
||||
|
||||
# アーカイブ成功確認
|
||||
if [ ! -d "$BUILD_DIR/${APP_NAME}.xcarchive" ]; then
|
||||
echo "Error: Archive failed. Check $BUILD_DIR/build.log for details"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
|
||||
# IPA作成
|
||||
rm -rf Payload ${APP_NAME}.ipa
|
||||
mkdir -p Payload
|
||||
cp -R ${APP_NAME}.xcarchive/Products/Applications/${APP_NAME}.app Payload/
|
||||
|
||||
# store.mobileprovisionの存在確認とコピー
|
||||
# https://developer.apple.com/account/resources/profiles/list
|
||||
if [ ! -f "$MOBILEPROVISION" ]; then
|
||||
# 親ディレクトリからコピーを試みる
|
||||
PARENT_MOBILEPROVISION="$SCRIPT_DIR/../embedded.mobileprovision"
|
||||
if [ -f "$PARENT_MOBILEPROVISION" ]; then
|
||||
echo "Copying mobileprovision from $PARENT_MOBILEPROVISION to $MOBILEPROVISION"
|
||||
cp "$PARENT_MOBILEPROVISION" "$MOBILEPROVISION"
|
||||
else
|
||||
echo "Error: store.mobileprovision not found at $MOBILEPROVISION or $PARENT_MOBILEPROVISION"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cp "$MOBILEPROVISION" Payload/${APP_NAME}.app/embedded.mobileprovision
|
||||
|
||||
# entitlements抽出
|
||||
security cms -D -i Payload/${APP_NAME}.app/embedded.mobileprovision > /tmp/profile.plist
|
||||
/usr/libexec/PlistBuddy -x -c "Print :Entitlements" /tmp/profile.plist > /tmp/entitlements.plist
|
||||
|
||||
# 署名
|
||||
CERT="$IOS_CERTIFICATE_NAME"
|
||||
|
||||
# Frameworksディレクトリが存在する場合のみ署名
|
||||
if [ -d "Payload/${APP_NAME}.app/Frameworks" ]; then
|
||||
for framework in Payload/${APP_NAME}.app/Frameworks/*.framework; do
|
||||
if [ -e "$framework" ]; then
|
||||
echo "Signing $framework"
|
||||
codesign -f -s "$CERT" "$framework"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# アプリ本体に署名
|
||||
codesign -f -s "$CERT" --entitlements /tmp/entitlements.plist Payload/${APP_NAME}.app
|
||||
|
||||
# IPA作成
|
||||
zip -r ${APP_NAME}.ipa Payload
|
||||
|
||||
# アップロード
|
||||
xcrun altool --upload-app -f ${APP_NAME}.ipa -t ios -u "${APP_MAIL}" -p "${APP_KEYCHAIN}"
|
||||
|
||||
echo "Upload complete: ${APP_NAME}.ipa"
|
||||
BIN
ios/icon.png
|
Before Width: | Height: | Size: 26 KiB |
@@ -1,133 +0,0 @@
|
||||
--- a/app.config.js
|
||||
+++ b/app.config.js
|
||||
@@ -23,10 +23,7 @@
|
||||
const IS_DEV = !IS_TESTFLIGHT && !IS_PRODUCTION
|
||||
|
||||
const ASSOCIATED_DOMAINS = [
|
||||
- 'applinks:bsky.app',
|
||||
- 'applinks:staging.bsky.app',
|
||||
- 'appclips:bsky.app',
|
||||
- 'appclips:go.bsky.app', // Allows App Clip to work when scanning QR codes
|
||||
+ 'applinks:syu.is',
|
||||
// When testing local services, enter an ngrok (et al) domain here. It must use a standard HTTP/HTTPS port.
|
||||
...(IS_DEV || IS_TESTFLIGHT ? [] : []),
|
||||
]
|
||||
@@ -38,27 +35,25 @@
|
||||
return {
|
||||
expo: {
|
||||
version: VERSION,
|
||||
- name: 'Bluesky',
|
||||
- slug: 'bluesky',
|
||||
- scheme: 'bluesky',
|
||||
+ name: 'Aiat',
|
||||
+ slug: 'aiat',
|
||||
+ scheme: 'syui',
|
||||
owner: 'blueskysocial',
|
||||
runtimeVersion: {
|
||||
policy: 'appVersion',
|
||||
},
|
||||
- icon: './assets/app-icons/ios_icon_default_next.png',
|
||||
+ icon: './assets/app-icon.png',
|
||||
userInterfaceStyle: 'automatic',
|
||||
primaryColor: '#1083fe',
|
||||
newArchEnabled: false,
|
||||
ios: {
|
||||
supportsTablet: false,
|
||||
- bundleIdentifier: 'xyz.blueskyweb.app',
|
||||
+ bundleIdentifier: 'ai.syui.at',
|
||||
+ buildNumber: '__BUILD_NUMBER__',
|
||||
config: {
|
||||
usesNonExemptEncryption: false,
|
||||
},
|
||||
- icon:
|
||||
- PLATFORM === 'web' // web build doesn't like .icon files
|
||||
- ? './assets/app-icons/ios_icon_default_next.png'
|
||||
- : './assets/app-icons/ios_icon_default.icon',
|
||||
+ icon: './assets/app-icon.png',
|
||||
infoPlist: {
|
||||
UIBackgroundModes: ['remote-notification'],
|
||||
NSCameraUsageDescription:
|
||||
@@ -118,7 +113,7 @@
|
||||
entitlements: {
|
||||
'com.apple.developer.kernel.increased-memory-limit': true,
|
||||
'com.apple.developer.kernel.extended-virtual-addressing': true,
|
||||
- 'com.apple.security.application-groups': 'group.app.bsky',
|
||||
+ 'com.apple.security.application-groups': 'group.ai.syui.at',
|
||||
// 'com.apple.developer.device-information.user-assigned-device-name': true,
|
||||
},
|
||||
privacyManifests: {
|
||||
@@ -181,14 +176,14 @@
|
||||
barStyle: 'light-content',
|
||||
},
|
||||
android: {
|
||||
- icon: './assets/app-icons/android_icon_default_next.png',
|
||||
+ icon: './assets/app-icon.png',
|
||||
adaptiveIcon: {
|
||||
foregroundImage: './assets/icon-android-foreground.png',
|
||||
monochromeImage: './assets/icon-android-monochrome.png',
|
||||
backgroundColor: '#006AFF',
|
||||
},
|
||||
googleServicesFile: './google-services.json',
|
||||
- package: 'xyz.blueskyweb.app',
|
||||
+ package: 'ai.syui.at',
|
||||
intentFilters: [
|
||||
{
|
||||
action: 'VIEW',
|
||||
@@ -196,7 +191,7 @@
|
||||
data: [
|
||||
{
|
||||
scheme: 'https',
|
||||
- host: 'bsky.app',
|
||||
+ host: 'syu.is',
|
||||
},
|
||||
...(IS_DEV
|
||||
? [
|
||||
@@ -280,7 +275,6 @@
|
||||
networkInstrumentation: true,
|
||||
},
|
||||
],
|
||||
- './plugins/starterPackAppClipExtension/withStarterPackAppClip.js',
|
||||
'./plugins/withGradleJVMHeapSizeIncrease.js',
|
||||
'./plugins/withAndroidManifestLargeHeapPlugin.js',
|
||||
'./plugins/withAndroidManifestFCMIconPlugin.js',
|
||||
@@ -288,8 +282,6 @@
|
||||
'./plugins/withAndroidStylesAccentColorPlugin.js',
|
||||
'./plugins/withAndroidDayNightThemePlugin.js',
|
||||
'./plugins/withAndroidNoJitpackPlugin.js',
|
||||
- './plugins/shareExtension/withShareExtensions.js',
|
||||
- './plugins/notificationsExtension/withNotificationsExtension.js',
|
||||
[
|
||||
'expo-font',
|
||||
{
|
||||
@@ -417,30 +409,7 @@
|
||||
build: {
|
||||
experimental: {
|
||||
ios: {
|
||||
- appExtensions: [
|
||||
- {
|
||||
- targetName: 'Share-with-Bluesky',
|
||||
- bundleIdentifier: 'xyz.blueskyweb.app.Share-with-Bluesky',
|
||||
- entitlements: {
|
||||
- 'com.apple.security.application-groups': [
|
||||
- 'group.app.bsky',
|
||||
- ],
|
||||
- },
|
||||
- },
|
||||
- {
|
||||
- targetName: 'BlueskyNSE',
|
||||
- bundleIdentifier: 'xyz.blueskyweb.app.BlueskyNSE',
|
||||
- entitlements: {
|
||||
- 'com.apple.security.application-groups': [
|
||||
- 'group.app.bsky',
|
||||
- ],
|
||||
- },
|
||||
- },
|
||||
- {
|
||||
- targetName: 'BlueskyClip',
|
||||
- bundleIdentifier: 'xyz.blueskyweb.app.AppClip',
|
||||
- },
|
||||
- ],
|
||||
+ appExtensions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1,217 +0,0 @@
|
||||
diff --git a/src/lib/api/feed/home.ts b/src/lib/api/feed/home.ts
|
||||
index 7a0d72d91..93554dc3e 100644
|
||||
--- a/src/lib/api/feed/home.ts
|
||||
+++ b/src/lib/api/feed/home.ts
|
||||
@@ -45,7 +45,7 @@ export class HomeFeedAPI implements FeedAPI {
|
||||
this.following = new FollowingFeedAPI({agent})
|
||||
this.discover = new CustomFeedAPI({
|
||||
agent,
|
||||
- feedParams: {feed: PROD_DEFAULT_FEED('whats-hot')},
|
||||
+ feedParams: {feed: PROD_DEFAULT_FEED('app')},
|
||||
})
|
||||
this.userInterests = userInterests
|
||||
}
|
||||
@@ -54,7 +54,7 @@ export class HomeFeedAPI implements FeedAPI {
|
||||
this.following = new FollowingFeedAPI({agent: this.agent})
|
||||
this.discover = new CustomFeedAPI({
|
||||
agent: this.agent,
|
||||
- feedParams: {feed: PROD_DEFAULT_FEED('whats-hot')},
|
||||
+ feedParams: {feed: PROD_DEFAULT_FEED('app')},
|
||||
userInterests: this.userInterests,
|
||||
})
|
||||
this.usingDiscover = false
|
||||
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
|
||||
index 231447b4f..a44b3da05 100644
|
||||
--- a/src/lib/constants.ts
|
||||
+++ b/src/lib/constants.ts
|
||||
@@ -7,12 +7,12 @@ import {BLUESKY_PROXY_DID, CHAT_PROXY_DID} from '#/env'
|
||||
export const LOCAL_DEV_SERVICE =
|
||||
Platform.OS === 'android' ? 'http://10.0.2.2:2583' : 'http://localhost:2583'
|
||||
export const STAGING_SERVICE = 'https://staging.bsky.dev'
|
||||
-export const BSKY_SERVICE = 'https://bsky.social'
|
||||
-export const BSKY_SERVICE_DID = 'did:web:bsky.social'
|
||||
-export const PUBLIC_BSKY_SERVICE = 'https://public.api.bsky.app'
|
||||
+export const BSKY_SERVICE = 'https://syu.is'
|
||||
+export const BSKY_SERVICE_DID = 'did:web:syu.is'
|
||||
+export const PUBLIC_BSKY_SERVICE = 'https://bsky.syu.is'
|
||||
export const DEFAULT_SERVICE = BSKY_SERVICE
|
||||
-const HELP_DESK_LANG = 'en-us'
|
||||
-export const HELP_DESK_URL = `https://blueskyweb.zendesk.com/hc/${HELP_DESK_LANG}`
|
||||
+const HELP_DESK_LANG = 'ja-jp'
|
||||
+export const HELP_DESK_URL = '/support/license'
|
||||
export const EMBED_SERVICE = 'https://embed.bsky.app'
|
||||
export const EMBED_SCRIPT = `${EMBED_SERVICE}/static/embed.js`
|
||||
export const BSKY_DOWNLOAD_URL = 'https://bsky.app/download'
|
||||
@@ -79,19 +79,17 @@ export function IS_PROD_SERVICE(url?: string) {
|
||||
}
|
||||
|
||||
export const PROD_DEFAULT_FEED = (rkey: string) =>
|
||||
- `at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/${rkey}`
|
||||
+ `at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/${rkey}`
|
||||
|
||||
export const STAGING_DEFAULT_FEED = (rkey: string) =>
|
||||
`at://did:plc:yofh3kx63drvfljkibw5zuxo/app.bsky.feed.generator/${rkey}`
|
||||
|
||||
export const PROD_FEEDS = [
|
||||
- `feedgen|${PROD_DEFAULT_FEED('whats-hot')}`,
|
||||
- `feedgen|${PROD_DEFAULT_FEED('thevids')}`,
|
||||
+ `feedgen|${PROD_DEFAULT_FEED('app')}`,
|
||||
]
|
||||
|
||||
export const STAGING_FEEDS = [
|
||||
- `feedgen|${STAGING_DEFAULT_FEED('whats-hot')}`,
|
||||
- `feedgen|${STAGING_DEFAULT_FEED('thevids')}`,
|
||||
+ `feedgen|${STAGING_DEFAULT_FEED('app')}`,
|
||||
]
|
||||
|
||||
export const POST_IMG_MAX = {
|
||||
@@ -129,7 +127,7 @@ export const LANG_DROPDOWN_HITSLOP = {top: 10, bottom: 10, left: 4, right: 4}
|
||||
export const BACK_HITSLOP = HITSLOP_30
|
||||
export const MAX_POST_LINES = 25
|
||||
|
||||
-export const BSKY_APP_ACCOUNT_DID = 'did:plc:z72i7hdynmk6r22z27h6tvur'
|
||||
+export const BSKY_APP_ACCOUNT_DID = 'did:plc:6qyecktefllvenje24fcxnie'
|
||||
|
||||
export const BSKY_FEED_OWNER_DIDS = [
|
||||
BSKY_APP_ACCOUNT_DID,
|
||||
@@ -138,9 +136,9 @@ export const BSKY_FEED_OWNER_DIDS = [
|
||||
]
|
||||
|
||||
export const DISCOVER_FEED_URI =
|
||||
- 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot'
|
||||
+ 'at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/app'
|
||||
export const VIDEO_FEED_URI =
|
||||
'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/thevids'
|
||||
export const STAGING_VIDEO_FEED_URI =
|
||||
'at://did:plc:yofh3kx63drvfljkibw5zuxo/app.bsky.feed.generator/thevids'
|
||||
export const VIDEO_FEED_URIS = [VIDEO_FEED_URI, STAGING_VIDEO_FEED_URI]
|
||||
@@ -209,8 +207,8 @@ export const urls = {
|
||||
},
|
||||
}
|
||||
|
||||
-export const PUBLIC_APPVIEW = 'https://api.bsky.app'
|
||||
-export const PUBLIC_APPVIEW_DID = 'did:web:api.bsky.app'
|
||||
+export const PUBLIC_APPVIEW = 'https://bsky.syu.is'
|
||||
+export const PUBLIC_APPVIEW_DID = 'did:web:bsky.syu.is'
|
||||
export const PUBLIC_STAGING_APPVIEW_DID = 'did:web:api.staging.bsky.dev'
|
||||
|
||||
export const DEV_ENV_APPVIEW = `http://localhost:2584` // always the same
|
||||
@@ -236,8 +234,8 @@ export const BLUESKY_MOD_SERVICE_HEADERS = {
|
||||
}
|
||||
|
||||
export const webLinks = {
|
||||
- tos: `https://bsky.social/about/support/tos`,
|
||||
- privacy: `https://bsky.social/about/support/privacy-policy`,
|
||||
+ tos: `/support/tos`,
|
||||
+ privacy: `/support/privacy-policy`,
|
||||
community: `https://bsky.social/about/support/community-guidelines`,
|
||||
communityDeprecated: `https://bsky.social/about/support/community-guidelines-deprecated`,
|
||||
}
|
||||
diff --git a/src/lib/demo.ts b/src/lib/demo.ts
|
||||
index 5ead62c9d..7c80dfe15 100644
|
||||
--- a/src/lib/demo.ts
|
||||
+++ b/src/lib/demo.ts
|
||||
@@ -1,7 +1,7 @@
|
||||
import {type AppBskyFeedGetFeed} from '@atproto/api'
|
||||
import {subDays, subMinutes} from 'date-fns'
|
||||
|
||||
-const DID = `did:plc:z72i7hdynmk6r22z27h6tvur`
|
||||
+const DID = `did:plc:6qyecktefllvenje24fcxnie`
|
||||
const NOW = new Date()
|
||||
const POST_1_DATE = subMinutes(NOW, 2).toISOString()
|
||||
const POST_2_DATE = subMinutes(NOW, 4).toISOString()
|
||||
diff --git a/src/lib/strings/url-helpers.ts b/src/lib/strings/url-helpers.ts
|
||||
index 6088e2806..0f6787a4d 100644
|
||||
--- a/src/lib/strings/url-helpers.ts
|
||||
+++ b/src/lib/strings/url-helpers.ts
|
||||
@@ -53,7 +53,7 @@ export function toNiceDomain(url: string): string {
|
||||
try {
|
||||
const urlp = new URL(url)
|
||||
if (`https://${urlp.host}` === BSKY_SERVICE) {
|
||||
- return 'Bluesky Social'
|
||||
+ return 'syu.is'
|
||||
}
|
||||
return urlp.host ? urlp.host : url
|
||||
} catch (e) {
|
||||
@@ -338,7 +338,7 @@ export function createProxiedUrl(url: string): string {
|
||||
return url
|
||||
}
|
||||
|
||||
- return `https://go.bsky.app/redirect?u=${encodeURIComponent(url)}`
|
||||
+ return url
|
||||
}
|
||||
|
||||
export function isShortLink(url: string): boolean {
|
||||
diff --git a/src/state/queries/feed.ts b/src/state/queries/feed.ts
|
||||
index de1e92533..3d1566800 100644
|
||||
--- a/src/state/queries/feed.ts
|
||||
+++ b/src/state/queries/feed.ts
|
||||
@@ -201,14 +201,6 @@ export function useFeedSourceInfoQuery({uri}: {uri: string}) {
|
||||
// for the ones we know need it
|
||||
// -prf
|
||||
export const KNOWN_AUTHED_ONLY_FEEDS = [
|
||||
- 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/with-friends', // popular with friends, by bsky.app
|
||||
- 'at://did:plc:tenurhgjptubkk5zf5qhi3og/app.bsky.feed.generator/mutuals', // mutuals, by skyfeed
|
||||
- 'at://did:plc:tenurhgjptubkk5zf5qhi3og/app.bsky.feed.generator/only-posts', // only posts, by skyfeed
|
||||
- 'at://did:plc:wzsilnxf24ehtmmc3gssy5bu/app.bsky.feed.generator/mentions', // mentions, by flicknow
|
||||
- 'at://did:plc:q6gjnaw2blty4crticxkmujt/app.bsky.feed.generator/bangers', // my bangers, by jaz
|
||||
- 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/mutuals', // mutuals, by bluesky
|
||||
- 'at://did:plc:q6gjnaw2blty4crticxkmujt/app.bsky.feed.generator/my-followers', // followers, by jaz
|
||||
- 'at://did:plc:vpkhqolt662uhesyj6nxm7ys/app.bsky.feed.generator/followpics', // the gram, by why
|
||||
]
|
||||
|
||||
type GetPopularFeedsOptions = {limit?: number; enabled?: boolean}
|
||||
diff --git a/src/state/queries/preferences/index.ts b/src/state/queries/preferences/index.ts
|
||||
index 0cf6ab546..399e592bc 100644
|
||||
--- a/src/state/queries/preferences/index.ts
|
||||
+++ b/src/state/queries/preferences/index.ts
|
||||
@@ -270,7 +270,7 @@ export function useReplaceForYouWithDiscoverFeedMutation() {
|
||||
await agent.addSavedFeeds([
|
||||
{
|
||||
type: 'feed',
|
||||
- value: PROD_DEFAULT_FEED('whats-hot'),
|
||||
+ value: PROD_DEFAULT_FEED('app'),
|
||||
pinned: true,
|
||||
},
|
||||
])
|
||||
diff --git a/src/view/com/posts/FeedShutdownMsg.tsx b/src/view/com/posts/FeedShutdownMsg.tsx
|
||||
index 620382175..928480da2 100644
|
||||
--- a/src/view/com/posts/FeedShutdownMsg.tsx
|
||||
+++ b/src/view/com/posts/FeedShutdownMsg.tsx
|
||||
@@ -32,7 +32,7 @@ export function FeedShutdownMsg({feedUri}: {feedUri: string}) {
|
||||
f => f.value === feedUri && f.pinned,
|
||||
)
|
||||
const discoverFeedConfig = preferences?.savedFeeds?.find(
|
||||
- f => f.value === PROD_DEFAULT_FEED('whats-hot'),
|
||||
+ f => f.value === PROD_DEFAULT_FEED('app'),
|
||||
)
|
||||
const hasFeedPinned = Boolean(feedConfig)
|
||||
const hasDiscoverPinned = Boolean(discoverFeedConfig?.pinned)
|
||||
@@ -44,7 +44,7 @@ export function FeedShutdownMsg({feedUri}: {feedUri: string}) {
|
||||
Toast.show(_(msg`Removed from your feeds`))
|
||||
}
|
||||
if (hasDiscoverPinned) {
|
||||
- setSelectedFeed(`feedgen|${PROD_DEFAULT_FEED('whats-hot')}`)
|
||||
+ setSelectedFeed(`feedgen|${PROD_DEFAULT_FEED('app')}`)
|
||||
}
|
||||
} catch (err: any) {
|
||||
Toast.show(
|
||||
@@ -63,7 +63,7 @@ export function FeedShutdownMsg({feedUri}: {feedUri: string}) {
|
||||
forYouFeedConfig: feedConfig,
|
||||
discoverFeedConfig,
|
||||
})
|
||||
- setSelectedFeed(`feedgen|${PROD_DEFAULT_FEED('whats-hot')}`)
|
||||
+ setSelectedFeed(`feedgen|${PROD_DEFAULT_FEED('app')}`)
|
||||
Toast.show(_(msg`The feed has been replaced with Discover.`))
|
||||
} catch (err: any) {
|
||||
Toast.show(
|
||||
@@ -100,7 +100,7 @@ export function FeedShutdownMsg({feedUri}: {feedUri: string}) {
|
||||
This feed is no longer online. We are showing{' '}
|
||||
<InlineLinkText
|
||||
label={_(msg`The Discover feed`)}
|
||||
- to="/profile/bsky.app/feed/whats-hot"
|
||||
+ to="/profile/did:plc:6qyecktefllvenje24fcxnie/feed/app"
|
||||
style={[a.text_md]}>
|
||||
Discover
|
||||
</InlineLinkText>{' '}
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
diff --git a/src/Splash.tsx b/src/Splash.tsx
|
||||
index 47e70b375..616f351ed 100644
|
||||
--- a/src/Splash.tsx
|
||||
+++ b/src/Splash.tsx
|
||||
@@ -15,8 +15,8 @@ import Animated, {
|
||||
withTiming,
|
||||
} from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
-import Svg, {Path, type SvgProps} from 'react-native-svg'
|
||||
import {Image} from 'expo-image'
|
||||
+import {type SvgProps} from 'react-native-svg'
|
||||
import * as SplashScreen from 'expo-splash-screen'
|
||||
|
||||
import {Logotype} from '#/view/icons/Logotype'
|
||||
@@ -29,21 +29,18 @@ const darkSplashImageUri = RNImage.resolveAssetSource(
|
||||
darkSplashImagePointer,
|
||||
).uri
|
||||
|
||||
-export const Logo = React.forwardRef(function LogoImpl(props: SvgProps, ref) {
|
||||
- const width = 1000
|
||||
- const height = width * (67 / 64)
|
||||
+export const Logo = React.forwardRef(function LogoImpl(props: SvgProps & {fill?: string}, ref) {
|
||||
+ const size = 1000
|
||||
+ // @ts-ignore
|
||||
return (
|
||||
- <Svg
|
||||
- fill="none"
|
||||
- // @ts-ignore it's fiiiiine
|
||||
+ <Image
|
||||
+ // @ts-ignore
|
||||
ref={ref}
|
||||
- viewBox="0 0 64 66"
|
||||
- style={[{width, height}, props.style]}>
|
||||
- <Path
|
||||
- fill={props.fill || '#fff'}
|
||||
- d="M13.873 3.77C21.21 9.243 29.103 20.342 32 26.3v15.732c0-.335-.13.043-.41.858-1.512 4.414-7.418 21.642-20.923 7.87-7.111-7.252-3.819-14.503 9.125-16.692-7.405 1.252-15.73-.817-18.014-8.93C1.12 22.804 0 8.431 0 6.488 0-3.237 8.579-.18 13.873 3.77ZM50.127 3.77C42.79 9.243 34.897 20.342 32 26.3v15.732c0-.335.13.043.41.858 1.512 4.414 7.418 21.642 20.923 7.87 7.111-7.252 3.819-14.503-9.125-16.692 7.405 1.252 15.73-.817 18.014-8.93C62.88 22.804 64 8.431 64 6.488 64-3.237 55.422-.18 50.127 3.77Z"
|
||||
- />
|
||||
- </Svg>
|
||||
+ source={require('../assets/logo.png')}
|
||||
+ style={[{width: size, height: size}, props.style]}
|
||||
+ contentFit="contain"
|
||||
+ accessibilityLabel="Logo"
|
||||
+ />
|
||||
)
|
||||
})
|
||||
|
||||
diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx
|
||||
index 8a9e51a33..65d643b89 100644
|
||||
--- a/src/view/com/util/UserAvatar.tsx
|
||||
+++ b/src/view/com/util/UserAvatar.tsx
|
||||
@@ -444,7 +444,7 @@ let EditableUserAvatar = ({
|
||||
<HighPriorityImage
|
||||
testID="userAvatarImage"
|
||||
style={aviStyle}
|
||||
- source={{uri: avatar}}
|
||||
+ source={{ uri: hackModifyThumbnailPath(avatar, 1 > 0), }}
|
||||
accessibilityRole="image"
|
||||
/>
|
||||
) : (
|
||||
@@ -618,9 +618,8 @@ export {PreviewableUserAvatar}
|
||||
// manually string-replace to use the smaller ones
|
||||
// -prf
|
||||
function hackModifyThumbnailPath(uri: string, isEnabled: boolean): string {
|
||||
- return isEnabled
|
||||
- ? uri.replace('/img/avatar/plain/', '/img/avatar_thumbnail/plain/')
|
||||
- : uri
|
||||
+ // syu.is: avatars are served directly from bsky.syu.is, no CDN transformation needed
|
||||
+ return uri
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
diff --git a/src/view/icons/Logo.tsx b/src/view/icons/Logo.tsx
|
||||
index d7208df13..2763800ac 100644
|
||||
--- a/src/view/icons/Logo.tsx
|
||||
+++ b/src/view/icons/Logo.tsx
|
||||
@@ -1,75 +1,17 @@
|
||||
import React from 'react'
|
||||
-import {type TextProps} from 'react-native'
|
||||
-import Svg, {
|
||||
- Defs,
|
||||
- LinearGradient,
|
||||
- Path,
|
||||
- type PathProps,
|
||||
- Stop,
|
||||
- type SvgProps,
|
||||
-} from 'react-native-svg'
|
||||
import {Image} from 'expo-image'
|
||||
+import {flatten} from '#/alf'
|
||||
|
||||
-import {useKawaiiMode} from '#/state/preferences/kawaii'
|
||||
-import {flatten, useTheme} from '#/alf'
|
||||
-
|
||||
-const ratio = 57 / 64
|
||||
-
|
||||
-type Props = {
|
||||
- fill?: PathProps['fill']
|
||||
- style?: TextProps['style']
|
||||
-} & Omit<SvgProps, 'style'>
|
||||
-
|
||||
-export const Logo = React.forwardRef(function LogoImpl(props: Props, ref) {
|
||||
- const t = useTheme()
|
||||
- const {fill, ...rest} = props
|
||||
- const gradient = fill === 'sky'
|
||||
- const styles = flatten(props.style)
|
||||
- const _fill = gradient
|
||||
- ? 'url(#sky)'
|
||||
- : fill || styles?.color || t.palette.primary_500
|
||||
- // @ts-ignore it's fiiiiine
|
||||
- const size = parseInt(rest.width || 32, 10)
|
||||
-
|
||||
- const isKawaii = useKawaiiMode()
|
||||
-
|
||||
- if (isKawaii) {
|
||||
- return (
|
||||
- <Image
|
||||
- source={
|
||||
- size > 100
|
||||
- ? require('../../../assets/kawaii.png')
|
||||
- : require('../../../assets/kawaii_smol.png')
|
||||
- }
|
||||
- accessibilityLabel="Bluesky"
|
||||
- accessibilityHint=""
|
||||
- accessibilityIgnoresInvertColors
|
||||
- style={[{height: size, aspectRatio: 1.4}]}
|
||||
- />
|
||||
- )
|
||||
- }
|
||||
-
|
||||
+export const Logo = React.forwardRef(function LogoImpl(props: any, ref) {
|
||||
+ const {width, style} = props
|
||||
+ // @ts-ignore
|
||||
+ const size = parseInt(width || 32, 10)
|
||||
return (
|
||||
- <Svg
|
||||
- fill="none"
|
||||
- // @ts-ignore it's fiiiiine
|
||||
- ref={ref}
|
||||
- viewBox="0 0 64 57"
|
||||
- {...rest}
|
||||
- style={[{width: size, height: size * ratio}, styles]}>
|
||||
- {gradient && (
|
||||
- <Defs>
|
||||
- <LinearGradient id="sky" x1="0" y1="0" x2="0" y2="1">
|
||||
- <Stop offset="0" stopColor="#0A7AFF" stopOpacity="1" />
|
||||
- <Stop offset="1" stopColor="#59B9FF" stopOpacity="1" />
|
||||
- </LinearGradient>
|
||||
- </Defs>
|
||||
- )}
|
||||
-
|
||||
- <Path
|
||||
- fill={_fill}
|
||||
- d="M13.873 3.805C21.21 9.332 29.103 20.537 32 26.55v15.882c0-.338-.13.044-.41.867-1.512 4.456-7.418 21.847-20.923 7.944-7.111-7.32-3.819-14.64 9.125-16.85-7.405 1.264-15.73-.825-18.014-9.015C1.12 23.022 0 8.51 0 6.55 0-3.268 8.579-.182 13.873 3.805ZM50.127 3.805C42.79 9.332 34.897 20.537 32 26.55v15.882c0-.338.13.044.41.867 1.512 4.456 7.418 21.847 20.923 7.944 7.111-7.32 3.819-14.64-9.125-16.85 7.405 1.264 15.73-.825 18.014-9.015C62.88 23.022 64 8.51 64 6.55c0-9.818-8.578-6.732-13.873-2.745Z"
|
||||
- />
|
||||
- </Svg>
|
||||
+ <Image
|
||||
+ source={require('../../../assets/logo.png')}
|
||||
+ style={[{width: size, height: size}, flatten(style)]}
|
||||
+ contentFit="contain"
|
||||
+ accessibilityLabel="Logo"
|
||||
+ />
|
||||
)
|
||||
})
|
||||
diff --git a/src/view/icons/Logotype.tsx b/src/view/icons/Logotype.tsx
|
||||
index 270c913fc..a60ffe07c 100644
|
||||
--- a/src/view/icons/Logotype.tsx
|
||||
+++ b/src/view/icons/Logotype.tsx
|
||||
@@ -1,28 +1,22 @@
|
||||
-import Svg, {Path, type PathProps, type SvgProps} from 'react-native-svg'
|
||||
-
|
||||
-import {usePalette} from '#/lib/hooks/usePalette'
|
||||
-
|
||||
-const ratio = 17 / 64
|
||||
-
|
||||
-export function Logotype({
|
||||
- fill,
|
||||
- ...rest
|
||||
-}: {fill?: PathProps['fill']} & SvgProps) {
|
||||
- const pal = usePalette('default')
|
||||
- // @ts-ignore it's fiiiiine
|
||||
- const size = parseInt(rest.width || 32)
|
||||
+import React from 'react'
|
||||
+import {Text} from 'react-native'
|
||||
+import {useTheme, atoms as a} from '#/alf'
|
||||
|
||||
+export function Logotype({width, fill, style}: any) {
|
||||
+ const t = useTheme()
|
||||
+ const fontSize = width ? parseInt(width) / 3.5 : 22
|
||||
+
|
||||
return (
|
||||
- <Svg
|
||||
- fill="none"
|
||||
- viewBox="0 0 64 17"
|
||||
- {...rest}
|
||||
- width={size}
|
||||
- height={Number(size) * ratio}>
|
||||
- <Path
|
||||
- fill={fill || pal.text.color}
|
||||
- d="M8.478 6.252c1.503.538 2.3 1.78 2.3 3.172 0 2.356-1.576 3.785-4.6 3.785H0V0h5.974c2.875 0 4.267 1.466 4.267 3.413 0 1.3-.594 2.245-1.763 2.839Zm-2.69-4.193H2.504v3.45h3.284c1.28 0 1.967-.667 1.967-1.78 0-1.02-.705-1.67-1.967-1.67Zm-3.284 9.072h3.544c1.41 0 2.17-.65 2.17-1.818 0-1.224-.723-1.837-2.17-1.837H2.504v3.655ZM14.251 13.209h-2.337V0h2.337v13.209ZM22.001 8.998V3.636h2.338v9.573h-2.263v-1.392c-.724 1.076-1.726 1.614-3.006 1.614-2.022 0-3.34-1.224-3.34-3.45V3.636h2.338v5.955c0 1.206.594 1.818 1.8 1.818 1.132 0 2.133-.835 2.133-2.411ZM34.979 8.59v.556h-7.161c.167 1.651 1.076 2.467 2.486 2.467 1.076 0 1.8-.463 2.189-1.372h2.244c-.5 1.947-2.17 3.19-4.452 3.19-1.428 0-2.579-.463-3.45-1.372-.872-.91-1.318-2.115-1.318-3.637 0-1.502.427-2.708 1.299-3.636.872-.909 2.004-1.372 3.432-1.372 1.447 0 2.597.482 3.45 1.428.854.946 1.28 2.208 1.28 3.747Zm-4.75-3.358c-1.28 0-2.17.742-2.393 2.281h4.805c-.204-1.391-1.057-2.281-2.411-2.281ZM40.16 13.469c-2.783 0-4.249-1.095-4.379-3.303h2.282c.13 1.188.724 1.633 2.134 1.633 1.261 0 1.892-.39 1.892-1.15 0-.687-.445-1.02-1.874-1.262l-1.094-.185c-2.097-.353-3.136-1.318-3.136-2.894 0-1.8 1.429-2.894 3.97-2.894 2.728 0 4.138 1.075 4.23 3.246h-2.207c-.056-1.169-.742-1.577-2.023-1.577-1.113 0-1.67.371-1.67 1.113 0 .668.483.965 1.596 1.169l1.206.186c2.32.426 3.32 1.28 3.32 2.912 0 1.93-1.557 3.006-4.247 3.006ZM54.667 13.209h-2.671l-2.783-4.453-1.447 1.447v3.006h-2.3V0h2.3v7.606l3.896-3.97h2.783l-3.618 3.618 3.84 5.955ZM60.772 6.048l.78-2.412H64l-3.692 10.352c-.39 1.057-.872 1.818-1.484 2.245-.612.426-1.484.63-2.634.63-.39 0-.724-.018-1.02-.055V14.97h.89c1.057 0 1.577-.65 1.577-1.54 0-.445-.149-1.094-.446-1.929l-2.746-7.866h2.487l.779 2.393c.575 1.8 1.076 3.58 1.521 5.343.408-1.521.928-3.302 1.54-5.324Z"
|
||||
- />
|
||||
- </Svg>
|
||||
+ <Text style={[
|
||||
+ a.font_bold,
|
||||
+ {
|
||||
+ fontSize,
|
||||
+ color: fill || t.palette.primary_500,
|
||||
+ letterSpacing: -0.5
|
||||
+ },
|
||||
+ style
|
||||
+ ]}>
|
||||
+ Aiat
|
||||
+ </Text>
|
||||
)
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
diff --git a/src/App.native.tsx b/src/App.native.tsx
|
||||
index 2c4d6fa41..b69e2b18d 100644
|
||||
--- a/src/App.native.tsx
|
||||
+++ b/src/App.native.tsx
|
||||
@@ -95,7 +95,7 @@ if (isAndroid) {
|
||||
* Begin geolocation ASAP
|
||||
*/
|
||||
Geo.resolve()
|
||||
-prefetchAgeAssuranceConfig()
|
||||
+// // // prefetchAgeAssuranceConfig()
|
||||
prefetchLiveEvents()
|
||||
|
||||
function InnerApp() {
|
||||
diff --git a/src/routes.ts b/src/routes.ts
|
||||
index f325539c7..3e2c7b3eb 100644
|
||||
--- a/src/routes.ts
|
||||
+++ b/src/routes.ts
|
||||
@@ -72,9 +72,11 @@ export const router = new Router<AllNavigatableRoutes>({
|
||||
FindContactsSettings: '/settings/find-contacts',
|
||||
// support
|
||||
Support: '/support',
|
||||
- PrivacyPolicy: '/support/privacy',
|
||||
- TermsOfService: '/support/tos',
|
||||
+ PrivacyPolicy: ['/support/privacy-policy', '/about/support/privacy-policy'],
|
||||
+ TermsOfService: ['/support/tos', '/about/support/tos'],
|
||||
CommunityGuidelines: '/support/community-guidelines',
|
||||
+ License: ['/support/license', '/about/support/license'],
|
||||
+ AppInfo: '/support/app',
|
||||
CopyrightPolicy: '/support/copyright',
|
||||
// hashtags
|
||||
Hashtag: '/hashtag/:tag',
|
||||
diff --git a/src/state/session/agent.ts b/src/state/session/agent.ts
|
||||
index 5c8ce3b97..ee85beb08 100644
|
||||
--- a/src/state/session/agent.ts
|
||||
+++ b/src/state/session/agent.ts
|
||||
@@ -47,7 +47,8 @@ export function createPublicAgent() {
|
||||
configureModerationForGuest() // Side effect but only relevant for tests
|
||||
|
||||
const agent = new BskyAppAgent({service: PUBLIC_BSKY_SERVICE})
|
||||
- agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Disable proxy for self-hosted environments
|
||||
+ // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
return agent
|
||||
}
|
||||
|
||||
@@ -88,7 +89,8 @@ export async function createAgentAndResume(
|
||||
// after session is attached
|
||||
const aa = prefetchAgeAssuranceData({agent})
|
||||
|
||||
- agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Disable proxy for self-hosted environments
|
||||
+ // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
|
||||
return agent.prepare({
|
||||
resolvers: [gates, moderation, aa],
|
||||
@@ -127,7 +129,8 @@ export async function createAgentAndLogin(
|
||||
const moderation = configureModerationForAccount(agent, account)
|
||||
const aa = prefetchAgeAssuranceData({agent})
|
||||
|
||||
- agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Disable proxy for self-hosted environments
|
||||
+ // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
|
||||
return agent.prepare({
|
||||
resolvers: [gates, moderation, aa],
|
||||
@@ -299,7 +302,8 @@ export async function createAgentAndCreateAccount(
|
||||
logger.error(e, {message: `session: failed snoozeEmailConfirmationPrompt`})
|
||||
}
|
||||
|
||||
- agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Disable proxy for self-hosted environments
|
||||
+ // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
|
||||
return agent.prepare({
|
||||
resolvers: [gates, moderation, aa],
|
||||
@@ -1,224 +0,0 @@
|
||||
--- a/src/screens/Settings/AboutSettings.tsx
|
||||
+++ b/src/screens/Settings/AboutSettings.tsx
|
||||
@@ -79,7 +79,7 @@
|
||||
<Layout.Content>
|
||||
<SettingsList.Container>
|
||||
<SettingsList.LinkItem
|
||||
- to="https://bsky.social/about/support/tos"
|
||||
+ to="/support/tos"
|
||||
label={_(msg`Terms of Service`)}>
|
||||
<SettingsList.ItemIcon icon={NewspaperIcon} />
|
||||
<SettingsList.ItemText>
|
||||
@@ -87,7 +87,7 @@
|
||||
</SettingsList.ItemText>
|
||||
</SettingsList.LinkItem>
|
||||
<SettingsList.LinkItem
|
||||
- to="https://bsky.social/about/support/privacy-policy"
|
||||
+ to="/support/privacy-policy"
|
||||
label={_(msg`Privacy Policy`)}>
|
||||
<SettingsList.ItemIcon icon={NewspaperIcon} />
|
||||
<SettingsList.ItemText>
|
||||
--- a/src/screens/Takendown.tsx
|
||||
+++ b/src/screens/Takendown.tsx
|
||||
@@ -210,10 +210,10 @@
|
||||
<Trans>
|
||||
Your account was found to be in violation of the{' '}
|
||||
<SimpleInlineLinkText
|
||||
- label={_(msg`Bluesky Social Terms of Service`)}
|
||||
- to="https://bsky.social/about/support/tos"
|
||||
+ label={_(msg`syu.is Terms of Service`)}
|
||||
+ to="/support/tos"
|
||||
style={[a.text_md, a.leading_snug]}>
|
||||
- Bluesky Social Terms of Service
|
||||
+ syu.is Terms of Service
|
||||
</SimpleInlineLinkText>
|
||||
. You have been sent an email outlining the specific violation
|
||||
and suspension period, if applicable. You can appeal this
|
||||
--- a/src/view/screens/PrivacyPolicy.tsx
|
||||
+++ b/src/view/screens/PrivacyPolicy.tsx
|
||||
@@ -1,52 +1,49 @@
|
||||
import React from 'react'
|
||||
-import {View} from 'react-native'
|
||||
-import {msg} from '@lingui/core/macro'
|
||||
-import {useLingui} from '@lingui/react'
|
||||
-import {Trans} from '@lingui/react/macro'
|
||||
-import {useFocusEffect} from '@react-navigation/native'
|
||||
-
|
||||
-import {usePalette} from '#/lib/hooks/usePalette'
|
||||
-import {
|
||||
- type CommonNavigatorParams,
|
||||
- type NativeStackScreenProps,
|
||||
-} from '#/lib/routes/types'
|
||||
-import {s} from '#/lib/styles'
|
||||
-import {useSetMinimalShellMode} from '#/state/shell'
|
||||
-import {TextLink} from '#/view/com/util/Link'
|
||||
-import {Text} from '#/view/com/util/text/Text'
|
||||
-import {ScrollView} from '#/view/com/util/Views'
|
||||
+import {ScrollView} from 'react-native'
|
||||
import * as Layout from '#/components/Layout'
|
||||
-import {ViewHeader} from '../com/util/ViewHeader'
|
||||
+import {useSetTitle} from '#/lib/hooks/useSetTitle'
|
||||
+import {atoms as a, useTheme} from '#/alf'
|
||||
+import {Text} from '#/components/Typography'
|
||||
|
||||
-type Props = NativeStackScreenProps<CommonNavigatorParams, 'PrivacyPolicy'>
|
||||
-export const PrivacyPolicyScreen = (_props: Props) => {
|
||||
- const pal = usePalette('default')
|
||||
- const {_} = useLingui()
|
||||
- const setMinimalShellMode = useSetMinimalShellMode()
|
||||
+export function PrivacyPolicyScreen() {
|
||||
+ useSetTitle('Privacy Policy')
|
||||
+ const t = useTheme()
|
||||
|
||||
- useFocusEffect(
|
||||
- React.useCallback(() => {
|
||||
- setMinimalShellMode(false)
|
||||
- }, [setMinimalShellMode]),
|
||||
- )
|
||||
-
|
||||
return (
|
||||
<Layout.Screen>
|
||||
- <ViewHeader title={_(msg`Privacy Policy`)} />
|
||||
- <ScrollView style={[s.hContentRegion, pal.view]}>
|
||||
- <View style={[s.p20]}>
|
||||
- <Text style={pal.text}>
|
||||
- <Trans>
|
||||
- The Privacy Policy has been moved to{' '}
|
||||
- <TextLink
|
||||
- style={pal.link}
|
||||
- href="https://bsky.social/about/support/privacy-policy"
|
||||
- text="bsky.social/about/support/privacy-policy"
|
||||
- />
|
||||
- </Trans>
|
||||
- </Text>
|
||||
- </View>
|
||||
- <View style={s.footerSpacer} />
|
||||
+ <ScrollView
|
||||
+ style={[a.flex_1, {backgroundColor: t.palette.white}]}
|
||||
+ contentContainerStyle={[a.p_lg, a.pt_5xl, a.pb_5xl]}>
|
||||
+ <Text style={[a.text_2xl, a.font_bold, a.mb_lg]}>Privacy Policy</Text>
|
||||
+
|
||||
+ <Text style={[a.text_lg, a.font_bold, a.mt_lg, a.mb_md]}>Data Collection</Text>
|
||||
+ <Text style={[a.mb_md]}>
|
||||
+ syu.is collects minimal data necessary to provide the service. This includes your account information, posts, and interactions on the AT Protocol network.
|
||||
+ </Text>
|
||||
+
|
||||
+ <Text style={[a.text_lg, a.font_bold, a.mt_lg, a.mb_md]}>Data Storage</Text>
|
||||
+ <Text style={[a.mb_md]}>
|
||||
+ Your data is stored on the AT Protocol network. Posts and profile information are public by default as part of the decentralized social network.
|
||||
+ </Text>
|
||||
+
|
||||
+ <Text style={[a.text_lg, a.font_bold, a.mt_lg, a.mb_md]}>Third Parties</Text>
|
||||
+ <Text style={[a.mb_md]}>
|
||||
+ We do not sell your personal information to third parties. Your data may be visible to other users and services on the AT Protocol network.
|
||||
+ </Text>
|
||||
+
|
||||
+ <Text style={[a.text_lg, a.font_bold, a.mt_lg, a.mb_md]}>Contact</Text>
|
||||
+ <Text style={[a.mb_md]}>
|
||||
+ For privacy-related questions, please contact the administrator.
|
||||
+ </Text>
|
||||
+
|
||||
+ <Text style={[a.text_lg, a.font_bold, a.mt_xl, a.mb_md]}>日本語</Text>
|
||||
+ <Text style={[a.mb_md]}>
|
||||
+ syu.isはサービス提供に必要な最小限のデータのみを収集します。投稿やプロフィール情報はAT Protocolネットワーク上で公開されます。個人情報を第三者に販売することはありません。
|
||||
+ </Text>
|
||||
+
|
||||
+ <Text style={[a.text_sm, a.mt_xl, {color: t.palette.contrast_500}]}>
|
||||
+ Last updated: 2026
|
||||
+ </Text>
|
||||
</ScrollView>
|
||||
</Layout.Screen>
|
||||
)
|
||||
--- a/src/view/screens/TermsOfService.tsx
|
||||
+++ b/src/view/screens/TermsOfService.tsx
|
||||
@@ -1,50 +1,49 @@
|
||||
import React from 'react'
|
||||
-import {View} from 'react-native'
|
||||
-import {msg} from '@lingui/core/macro'
|
||||
-import {useLingui} from '@lingui/react'
|
||||
-import {Trans} from '@lingui/react/macro'
|
||||
-import {useFocusEffect} from '@react-navigation/native'
|
||||
-
|
||||
-import {usePalette} from '#/lib/hooks/usePalette'
|
||||
-import {
|
||||
- type CommonNavigatorParams,
|
||||
- type NativeStackScreenProps,
|
||||
-} from '#/lib/routes/types'
|
||||
-import {s} from '#/lib/styles'
|
||||
-import {useSetMinimalShellMode} from '#/state/shell'
|
||||
-import {TextLink} from '#/view/com/util/Link'
|
||||
-import {Text} from '#/view/com/util/text/Text'
|
||||
-import {ScrollView} from '#/view/com/util/Views'
|
||||
+import {ScrollView} from 'react-native'
|
||||
import * as Layout from '#/components/Layout'
|
||||
-import {ViewHeader} from '../com/util/ViewHeader'
|
||||
+import {useSetTitle} from '#/lib/hooks/useSetTitle'
|
||||
+import {atoms as a, useTheme} from '#/alf'
|
||||
+import {Text} from '#/components/Typography'
|
||||
|
||||
-type Props = NativeStackScreenProps<CommonNavigatorParams, 'TermsOfService'>
|
||||
-export const TermsOfServiceScreen = (_props: Props) => {
|
||||
- const pal = usePalette('default')
|
||||
- const setMinimalShellMode = useSetMinimalShellMode()
|
||||
- const {_} = useLingui()
|
||||
+export function TermsOfServiceScreen() {
|
||||
+ useSetTitle('Terms of Service')
|
||||
+ const t = useTheme()
|
||||
|
||||
- useFocusEffect(
|
||||
- React.useCallback(() => {
|
||||
- setMinimalShellMode(false)
|
||||
- }, [setMinimalShellMode]),
|
||||
- )
|
||||
-
|
||||
return (
|
||||
<Layout.Screen>
|
||||
- <ViewHeader title={_(msg`Terms of Service`)} />
|
||||
- <ScrollView style={[s.hContentRegion, pal.view]}>
|
||||
- <View style={[s.p20]}>
|
||||
- <Text style={pal.text}>
|
||||
- <Trans>The Terms of Service have been moved to</Trans>{' '}
|
||||
- <TextLink
|
||||
- style={pal.link}
|
||||
- href="https://bsky.social/about/support/tos"
|
||||
- text="bsky.social/about/support/tos"
|
||||
- />
|
||||
- </Text>
|
||||
- </View>
|
||||
- <View style={s.footerSpacer} />
|
||||
+ <ScrollView
|
||||
+ style={[a.flex_1, {backgroundColor: t.palette.white}]}
|
||||
+ contentContainerStyle={[a.p_lg, a.pt_5xl, a.pb_5xl]}>
|
||||
+ <Text style={[a.text_2xl, a.font_bold, a.mb_lg]}>Terms of Service</Text>
|
||||
+
|
||||
+ <Text style={[a.text_lg, a.font_bold, a.mt_lg, a.mb_md]}>Acceptance</Text>
|
||||
+ <Text style={[a.mb_md]}>
|
||||
+ By using syu.is, you agree to these terms. If you do not agree, please do not use the service.
|
||||
+ </Text>
|
||||
+
|
||||
+ <Text style={[a.text_lg, a.font_bold, a.mt_lg, a.mb_md]}>Prohibited Content</Text>
|
||||
+ <Text style={[a.mb_md]}>
|
||||
+ Do not post illegal content, spam, or harass others. Do not impersonate others or spread misinformation.
|
||||
+ </Text>
|
||||
+
|
||||
+ <Text style={[a.text_lg, a.font_bold, a.mt_lg, a.mb_md]}>Account Termination</Text>
|
||||
+ <Text style={[a.mb_md]}>
|
||||
+ The administrator reserves the right to suspend or terminate accounts that violate these terms.
|
||||
+ </Text>
|
||||
+
|
||||
+ <Text style={[a.text_lg, a.font_bold, a.mt_lg, a.mb_md]}>Disclaimer</Text>
|
||||
+ <Text style={[a.mb_md]}>
|
||||
+ This service is provided "as is" without warranty of any kind.
|
||||
+ </Text>
|
||||
+
|
||||
+ <Text style={[a.text_lg, a.font_bold, a.mt_xl, a.mb_md]}>日本語</Text>
|
||||
+ <Text style={[a.mb_md]}>
|
||||
+ syu.isを利用することで、これらの利用規約に同意したものとみなします。違法なコンテンツの投稿、スパム、他者への嫌がらせは禁止です。管理者は規約違反のアカウントを停止する権利を有します。本サービスは現状のまま提供され、いかなる保証もありません。
|
||||
+ </Text>
|
||||
+
|
||||
+ <Text style={[a.text_sm, a.mt_xl, {color: t.palette.contrast_500}]}>
|
||||
+ Last updated: 2026
|
||||
+ </Text>
|
||||
</ScrollView>
|
||||
</Layout.Screen>
|
||||
)
|
||||
@@ -1,65 +0,0 @@
|
||||
diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx
|
||||
index 42a5fe417..8e7963512 100644
|
||||
--- a/src/view/shell/Drawer.tsx
|
||||
+++ b/src/view/shell/Drawer.tsx
|
||||
@@ -294,17 +294,11 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
|
||||
<>
|
||||
<SearchMenuItem isActive={isAtSearch} onPress={onPressSearch} />
|
||||
<HomeMenuItem isActive={isAtHome} onPress={onPressHome} />
|
||||
- <ChatMenuItem isActive={isAtMessages} onPress={onPressMessages} />
|
||||
<NotificationsMenuItem
|
||||
isActive={isAtNotifications}
|
||||
onPress={onPressNotifications}
|
||||
/>
|
||||
<FeedsMenuItem isActive={isAtFeeds} onPress={onPressMyFeeds} />
|
||||
- <ListsMenuItem onPress={onPressLists} />
|
||||
- <BookmarksMenuItem
|
||||
- isActive={isAtBookmarks}
|
||||
- onPress={onPressBookmarks}
|
||||
- />
|
||||
<ProfileMenuItem
|
||||
isActive={isAtMyProfile}
|
||||
onPress={onPressProfile}
|
||||
@@ -359,17 +353,7 @@ let DrawerFooter = ({
|
||||
),
|
||||
},
|
||||
]}>
|
||||
- <Button
|
||||
- label={_(msg`Send feedback`)}
|
||||
- size="small"
|
||||
- variant="solid"
|
||||
- color="secondary"
|
||||
- onPress={onPressFeedback}>
|
||||
- <ButtonIcon icon={Message} position="left" />
|
||||
- <ButtonText>
|
||||
- <Trans>Feedback</Trans>
|
||||
- </ButtonText>
|
||||
- </Button>
|
||||
+{/* Feedback button removed for syu.is */}
|
||||
<Button
|
||||
label={_(msg`Get help`)}
|
||||
size="small"
|
||||
@@ -697,15 +681,21 @@ function ExtraLinks() {
|
||||
<InlineLinkText
|
||||
style={[a.text_md]}
|
||||
label={_(msg`Terms of Service`)}
|
||||
- to="https://bsky.social/about/support/tos">
|
||||
+ to="/support/tos">
|
||||
<Trans>Terms of Service</Trans>
|
||||
</InlineLinkText>
|
||||
<InlineLinkText
|
||||
style={[a.text_md]}
|
||||
- to="https://bsky.social/about/support/privacy-policy"
|
||||
+ to="/support/privacy-policy"
|
||||
label={_(msg`Privacy Policy`)}>
|
||||
<Trans>Privacy Policy</Trans>
|
||||
</InlineLinkText>
|
||||
+ <InlineLinkText
|
||||
+ style={[a.text_md]}
|
||||
+ to="/support/license"
|
||||
+ label="License">
|
||||
+ License
|
||||
+ </InlineLinkText>
|
||||
{kawaii && (
|
||||
<Text style={t.atoms.text_contrast_medium}>
|
||||
<Trans>
|
||||
@@ -1,32 +0,0 @@
|
||||
diff --git a/plugins/notificationsExtension/withNotificationsExtension.js b/plugins/notificationsExtension/withNotificationsExtension.js
|
||||
index 6a00cfd23..f91decc08 100644
|
||||
--- a/plugins/notificationsExtension/withNotificationsExtension.js
|
||||
+++ b/plugins/notificationsExtension/withNotificationsExtension.js
|
||||
@@ -10,7 +10,7 @@ const EXTENSION_NAME = 'BlueskyNSE'
|
||||
const EXTENSION_CONTROLLER_NAME = 'NotificationService'
|
||||
|
||||
const withNotificationsExtension = config => {
|
||||
- const soundFiles = ['dm.aiff']
|
||||
+ const soundFiles = []
|
||||
|
||||
return withPlugins(config, [
|
||||
// IOS
|
||||
diff --git a/src/components/PolicyUpdateOverlay/updates/202508/index.tsx b/src/components/PolicyUpdateOverlay/updates/202508/index.tsx
|
||||
index 8365057e8..59c8506a2 100644
|
||||
--- a/src/components/PolicyUpdateOverlay/updates/202508/index.tsx
|
||||
+++ b/src/components/PolicyUpdateOverlay/updates/202508/index.tsx
|
||||
@@ -26,12 +26,12 @@ export function Content({state}: {state: PolicyUpdateState}) {
|
||||
const links = {
|
||||
terms: {
|
||||
overridePresentation: false,
|
||||
- to: `https://bsky.social/about/support/tos`,
|
||||
+ to: `/support/tos`,
|
||||
label: _(msg`Terms of Service`),
|
||||
},
|
||||
privacy: {
|
||||
overridePresentation: false,
|
||||
- to: `https://bsky.social/about/support/privacy-policy`,
|
||||
+ to: `/support/privacy-policy`,
|
||||
label: _(msg`Privacy Policy`),
|
||||
},
|
||||
copyright: {
|
||||
@@ -1,43 +0,0 @@
|
||||
diff --git a/src/Navigation.tsx b/src/Navigation.tsx
|
||||
index fde223bd0..0e57c27a6 100644
|
||||
--- a/src/Navigation.tsx
|
||||
+++ b/src/Navigation.tsx
|
||||
@@ -66,6 +66,8 @@ import {NotFoundScreen} from '#/view/screens/NotFound'
|
||||
import {NotificationsScreen} from '#/view/screens/Notifications'
|
||||
import {PostThreadScreen} from '#/view/screens/PostThread'
|
||||
import {PrivacyPolicyScreen} from '#/view/screens/PrivacyPolicy'
|
||||
+import {LicenseScreen} from '#/view/screens/License'
|
||||
+import {AppInfoScreen} from '#/view/screens/AppInfo'
|
||||
import {ProfileScreen} from '#/view/screens/Profile'
|
||||
import {ProfileFeedLikedByScreen} from '#/view/screens/ProfileFeedLikedBy'
|
||||
import {StorybookScreen} from '#/view/screens/Storybook'
|
||||
@@ -337,6 +339,16 @@ function commonScreens(Stack: typeof Flat, unreadCountLabel?: string) {
|
||||
getComponent={() => TermsOfServiceScreen}
|
||||
options={{title: title(msg`Terms of Service`)}}
|
||||
/>
|
||||
+ <Stack.Screen
|
||||
+ name="License"
|
||||
+ getComponent={() => LicenseScreen}
|
||||
+ options={{title: title(msg`License`)}}
|
||||
+ />
|
||||
+ <Stack.Screen
|
||||
+ name="AppInfo"
|
||||
+ getComponent={() => AppInfoScreen}
|
||||
+ options={{title: title(msg`App Info`)}}
|
||||
+ />
|
||||
<Stack.Screen
|
||||
name="CommunityGuidelines"
|
||||
getComponent={() => CommunityGuidelinesScreen}
|
||||
diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts
|
||||
index 0a3a0d545..ec6c43ff5 100644
|
||||
--- a/src/lib/routes/types.ts
|
||||
+++ b/src/lib/routes/types.ts
|
||||
@@ -39,6 +39,8 @@ export type CommonNavigatorParams = {
|
||||
Support: undefined
|
||||
PrivacyPolicy: undefined
|
||||
TermsOfService: undefined
|
||||
+ License: undefined
|
||||
+ AppInfo: undefined
|
||||
CommunityGuidelines: undefined
|
||||
CopyrightPolicy: undefined
|
||||
LanguageSettings: undefined
|
||||
@@ -1,25 +0,0 @@
|
||||
diff --git a/src/screens/Signup/index.tsx b/src/screens/Signup/index.tsx
|
||||
index aa6cd4156..37c7a38b0 100644
|
||||
--- a/src/screens/Signup/index.tsx
|
||||
+++ b/src/screens/Signup/index.tsx
|
||||
@@ -211,20 +211,6 @@ export function Signup({onPressBack}: {onPressBack: () => void}) {
|
||||
a.align_center,
|
||||
]}>
|
||||
<AppLanguageDropdown />
|
||||
- <Text
|
||||
- style={[
|
||||
- a.flex_1,
|
||||
- t.atoms.text_contrast_medium,
|
||||
- !gtMobile && a.text_md,
|
||||
- ]}>
|
||||
- <Trans>Having trouble?</Trans>{' '}
|
||||
- <InlineLinkText
|
||||
- label={_(msg`Contact support`)}
|
||||
- to={FEEDBACK_FORM_URL({email: state.email})}
|
||||
- style={[!gtMobile && a.text_md]}>
|
||||
- <Trans>Contact support</Trans>
|
||||
- </InlineLinkText>
|
||||
- </Text>
|
||||
</View>
|
||||
</View>
|
||||
</ScreenTransition>
|
||||
@@ -1,19 +0,0 @@
|
||||
diff --git a/src/view/com/auth/SplashScreen.web.tsx b/src/view/com/auth/SplashScreen.web.tsx
|
||||
index d9185d778..504f521a4 100644
|
||||
--- a/src/view/com/auth/SplashScreen.web.tsx
|
||||
+++ b/src/view/com/auth/SplashScreen.web.tsx
|
||||
@@ -94,14 +94,6 @@ export const SplashScreen = ({
|
||||
</View>
|
||||
)}
|
||||
|
||||
- <Text
|
||||
- style={[
|
||||
- a.text_md,
|
||||
- a.font_semi_bold,
|
||||
- t.atoms.text_contrast_medium,
|
||||
- ]}>
|
||||
- <Trans>What's up?</Trans>
|
||||
- </Text>
|
||||
</View>
|
||||
|
||||
<View
|
||||
@@ -1,50 +0,0 @@
|
||||
diff --git a/src/screens/Settings/Settings.tsx b/src/screens/Settings/Settings.tsx
|
||||
index 2fa5aa7de..3faf6a7b3 100644
|
||||
--- a/src/screens/Settings/Settings.tsx
|
||||
+++ b/src/screens/Settings/Settings.tsx
|
||||
@@ -203,26 +203,8 @@ export function SettingsScreen({}: Props) {
|
||||
<Trans>Notifications</Trans>
|
||||
</SettingsList.ItemText>
|
||||
</SettingsList.LinkItem>
|
||||
- <SettingsList.LinkItem
|
||||
- to="/settings/content-and-media"
|
||||
- label={_(msg`Content and media`)}>
|
||||
- <SettingsList.ItemIcon icon={WindowIcon} />
|
||||
- <SettingsList.ItemText>
|
||||
- <Trans>Content and media</Trans>
|
||||
- </SettingsList.ItemText>
|
||||
- </SettingsList.LinkItem>
|
||||
- {IS_NATIVE &&
|
||||
- findContactsEnabled &&
|
||||
- !ax.features.enabled(ax.features.ImportContactsSettingsDisable) && (
|
||||
- <SettingsList.LinkItem
|
||||
- to="/settings/find-contacts"
|
||||
- label={_(msg`Find friends from contacts`)}>
|
||||
- <SettingsList.ItemIcon icon={ContactsIcon} />
|
||||
- <SettingsList.ItemText>
|
||||
- <Trans>Find friends from contacts</Trans>
|
||||
- </SettingsList.ItemText>
|
||||
- </SettingsList.LinkItem>
|
||||
- )}
|
||||
+ {/* Content and media removed for syu.is */}
|
||||
+ {/* Find friends from contacts removed for syu.is */}
|
||||
<SettingsList.LinkItem
|
||||
to="/settings/appearance"
|
||||
label={_(msg`Appearance`)}>
|
||||
@@ -247,16 +229,6 @@ export function SettingsScreen({}: Props) {
|
||||
<Trans>Languages</Trans>
|
||||
</SettingsList.ItemText>
|
||||
</SettingsList.LinkItem>
|
||||
- <SettingsList.PressableItem
|
||||
- onPress={() => Linking.openURL(HELP_DESK_URL)}
|
||||
- label={_(msg`Help`)}
|
||||
- accessibilityHint={_(msg`Opens helpdesk in browser`)}>
|
||||
- <SettingsList.ItemIcon icon={CircleQuestionIcon} />
|
||||
- <SettingsList.ItemText>
|
||||
- <Trans>Help</Trans>
|
||||
- </SettingsList.ItemText>
|
||||
- <SettingsList.Chevron />
|
||||
- </SettingsList.PressableItem>
|
||||
<SettingsList.LinkItem to="/settings/about" label={_(msg`About`)}>
|
||||
<SettingsList.ItemIcon icon={BubbleInfoIcon} />
|
||||
<SettingsList.ItemText>
|
||||
@@ -1,31 +0,0 @@
|
||||
diff --git a/plugins/withCodeSignEntitlements.js b/plugins/withCodeSignEntitlements.js
|
||||
new file mode 100644
|
||||
index 000000000..b03b6bd68
|
||||
--- /dev/null
|
||||
+++ b/plugins/withCodeSignEntitlements.js
|
||||
@@ -0,0 +1,25 @@
|
||||
+/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
+const { withXcodeProject } = require('@expo/config-plugins')
|
||||
+
|
||||
+const withCodeSignEntitlements = (config) => {
|
||||
+ return withXcodeProject(config, (config) => {
|
||||
+ const xcodeProject = config.modResults
|
||||
+ const configurations = xcodeProject.pbxXCBuildConfigurationSection()
|
||||
+
|
||||
+ for (const key in configurations) {
|
||||
+ const configuration = configurations[key]
|
||||
+ if (
|
||||
+ configuration.buildSettings &&
|
||||
+ configuration.comment &&
|
||||
+ !configuration.comment.includes('TEST')
|
||||
+ ) {
|
||||
+ configuration.buildSettings.CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION =
|
||||
+ 'YES'
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return config
|
||||
+ })
|
||||
+}
|
||||
+
|
||||
+module.exports = withCodeSignEntitlements
|
||||
@@ -1,39 +0,0 @@
|
||||
diff --git a/src/ageAssurance/index.tsx b/src/ageAssurance/index.tsx
|
||||
--- a/src/ageAssurance/index.tsx
|
||||
+++ b/src/ageAssurance/index.tsx
|
||||
@@ -90,25 +90,16 @@ function InnerProvider({children}: {children: React.ReactNode}) {
|
||||
return (
|
||||
<AgeAssuranceStateContext.Provider
|
||||
value={useMemo(() => {
|
||||
- const chatDisabled = state.access !== AgeAssuranceAccess.Full
|
||||
- const isUnderAdultAge = data?.birthdate
|
||||
- ? isUnderAge(data.birthdate, 18)
|
||||
- : true
|
||||
- const isOverRegionMinAccessAge = data?.birthdate
|
||||
- ? !isUnderAge(data.birthdate, config.minAccessAge)
|
||||
- : false
|
||||
- const isOverAppMinAccessAge = data?.birthdate
|
||||
- ? !isUnderAge(data.birthdate, MIN_ACCESS_AGE)
|
||||
- : false
|
||||
- const adultContentDisabled =
|
||||
- state.access !== AgeAssuranceAccess.Full || isUnderAdultAge
|
||||
return {
|
||||
Access: AgeAssuranceAccess,
|
||||
Status: AgeAssuranceStatus,
|
||||
- state,
|
||||
+ state: {
|
||||
+ ...state,
|
||||
+ access: AgeAssuranceAccess.Full,
|
||||
+ },
|
||||
flags: {
|
||||
- adultContentDisabled,
|
||||
- chatDisabled,
|
||||
- isOverRegionMinAccessAge,
|
||||
- isOverAppMinAccessAge,
|
||||
+ adultContentDisabled: false,
|
||||
+ chatDisabled: false,
|
||||
+ isOverRegionMinAccessAge: true,
|
||||
+ isOverAppMinAccessAge: true,
|
||||
},
|
||||
}
|
||||
}, [state, data, config])}>
|
||||
@@ -1,241 +0,0 @@
|
||||
--- a/src/view/com/posts/DiscoverFallbackHeader.tsx
|
||||
+++ b/src/view/com/posts/DiscoverFallbackHeader.tsx
|
||||
@@ -7,37 +7,5 @@
|
||||
import {Text} from '../util/text/Text'
|
||||
|
||||
export function DiscoverFallbackHeader() {
|
||||
- const pal = usePalette('default')
|
||||
- return (
|
||||
- <View
|
||||
- style={[
|
||||
- {
|
||||
- flexDirection: 'row',
|
||||
- alignItems: 'center',
|
||||
- paddingVertical: 12,
|
||||
- paddingHorizontal: 12,
|
||||
- borderTopWidth: 1,
|
||||
- },
|
||||
- pal.border,
|
||||
- pal.viewLight,
|
||||
- ]}>
|
||||
- <View style={{width: 68, paddingLeft: 12}}>
|
||||
- <InfoCircleIcon size={36} style={pal.textLight} strokeWidth={1.5} />
|
||||
- </View>
|
||||
- <View style={{flex: 1}}>
|
||||
- <Text type="md" style={pal.text}>
|
||||
- <Trans>
|
||||
- We ran out of posts from your follows. Here's the latest from{' '}
|
||||
- <TextLink
|
||||
- type="md-medium"
|
||||
- href="/profile/bsky.app/feed/whats-hot"
|
||||
- text="Discover"
|
||||
- style={pal.link}
|
||||
- />
|
||||
- .
|
||||
- </Trans>
|
||||
- </Text>
|
||||
- </View>
|
||||
- </View>
|
||||
- )
|
||||
+ return null
|
||||
}
|
||||
--- a/src/view/com/posts/FollowingEmptyState.tsx
|
||||
+++ b/src/view/com/posts/FollowingEmptyState.tsx
|
||||
@@ -1,38 +1,15 @@
|
||||
import React from 'react'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
-import {
|
||||
- FontAwesomeIcon,
|
||||
- type FontAwesomeIconStyle,
|
||||
-} from '@fortawesome/react-native-fontawesome'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
-import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {MagnifyingGlassIcon} from '#/lib/icons'
|
||||
-import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {s} from '#/lib/styles'
|
||||
-import {IS_WEB} from '#/env'
|
||||
-import {Button} from '../util/forms/Button'
|
||||
import {Text} from '../util/text/Text'
|
||||
|
||||
export function FollowingEmptyState() {
|
||||
const pal = usePalette('default')
|
||||
- const palInverted = usePalette('inverted')
|
||||
- const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
- const onPressFindAccounts = React.useCallback(() => {
|
||||
- if (IS_WEB) {
|
||||
- navigation.navigate('Search', {})
|
||||
- } else {
|
||||
- navigation.navigate('SearchTab')
|
||||
- navigation.popToTop()
|
||||
- }
|
||||
- }, [navigation])
|
||||
-
|
||||
- const onPressDiscoverFeeds = React.useCallback(() => {
|
||||
- navigation.navigate('Feeds')
|
||||
- }, [navigation])
|
||||
-
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.inner}>
|
||||
@@ -45,36 +22,6 @@
|
||||
happening.
|
||||
</Trans>
|
||||
</Text>
|
||||
- <Button
|
||||
- type="inverted"
|
||||
- style={styles.emptyBtn}
|
||||
- onPress={onPressFindAccounts}>
|
||||
- <Text type="lg-medium" style={palInverted.text}>
|
||||
- <Trans>Find accounts to follow</Trans>
|
||||
- </Text>
|
||||
- <FontAwesomeIcon
|
||||
- icon="angle-right"
|
||||
- style={palInverted.text as FontAwesomeIconStyle}
|
||||
- size={14}
|
||||
- />
|
||||
- </Button>
|
||||
-
|
||||
- <Text type="xl-medium" style={[s.textCenter, pal.text, s.mt20]}>
|
||||
- <Trans>You can also discover new Custom Feeds to follow.</Trans>
|
||||
- </Text>
|
||||
- <Button
|
||||
- type="inverted"
|
||||
- style={[styles.emptyBtn, s.mt10]}
|
||||
- onPress={onPressDiscoverFeeds}>
|
||||
- <Text type="lg-medium" style={palInverted.text}>
|
||||
- <Trans>Discover new custom feeds</Trans>
|
||||
- </Text>
|
||||
- <FontAwesomeIcon
|
||||
- icon="angle-right"
|
||||
- style={palInverted.text as FontAwesomeIconStyle}
|
||||
- size={14}
|
||||
- />
|
||||
- </Button>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
@@ -98,13 +45,4 @@
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
- emptyBtn: {
|
||||
- marginVertical: 20,
|
||||
- flexDirection: 'row',
|
||||
- alignItems: 'center',
|
||||
- justifyContent: 'space-between',
|
||||
- paddingVertical: 18,
|
||||
- paddingHorizontal: 24,
|
||||
- borderRadius: 30,
|
||||
- },
|
||||
})
|
||||
--- a/src/view/com/posts/FollowingEndOfFeed.tsx
|
||||
+++ b/src/view/com/posts/FollowingEndOfFeed.tsx
|
||||
@@ -1,37 +1,14 @@
|
||||
import React from 'react'
|
||||
import {Dimensions, StyleSheet, View} from 'react-native'
|
||||
-import {
|
||||
- FontAwesomeIcon,
|
||||
- type FontAwesomeIconStyle,
|
||||
-} from '@fortawesome/react-native-fontawesome'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
-import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
-import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {s} from '#/lib/styles'
|
||||
-import {IS_WEB} from '#/env'
|
||||
-import {Button} from '../util/forms/Button'
|
||||
import {Text} from '../util/text/Text'
|
||||
|
||||
export function FollowingEndOfFeed() {
|
||||
const pal = usePalette('default')
|
||||
- const palInverted = usePalette('inverted')
|
||||
- const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
- const onPressFindAccounts = React.useCallback(() => {
|
||||
- if (IS_WEB) {
|
||||
- navigation.navigate('Search', {})
|
||||
- } else {
|
||||
- navigation.navigate('SearchTab')
|
||||
- navigation.popToTop()
|
||||
- }
|
||||
- }, [navigation])
|
||||
-
|
||||
- const onPressDiscoverFeeds = React.useCallback(() => {
|
||||
- navigation.navigate('Feeds')
|
||||
- }, [navigation])
|
||||
-
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
@@ -41,41 +18,8 @@
|
||||
]}>
|
||||
<View style={styles.inner}>
|
||||
<Text type="xl-medium" style={[s.textCenter, pal.text]}>
|
||||
- <Trans>
|
||||
- You've reached the end of your feed! Find some more accounts to
|
||||
- follow.
|
||||
- </Trans>
|
||||
+ <Trans>You've reached the end of your feed!</Trans>
|
||||
</Text>
|
||||
- <Button
|
||||
- type="inverted"
|
||||
- style={styles.emptyBtn}
|
||||
- onPress={onPressFindAccounts}>
|
||||
- <Text type="lg-medium" style={palInverted.text}>
|
||||
- <Trans>Find accounts to follow</Trans>
|
||||
- </Text>
|
||||
- <FontAwesomeIcon
|
||||
- icon="angle-right"
|
||||
- style={palInverted.text as FontAwesomeIconStyle}
|
||||
- size={14}
|
||||
- />
|
||||
- </Button>
|
||||
-
|
||||
- <Text type="xl-medium" style={[s.textCenter, pal.text, s.mt20]}>
|
||||
- <Trans>You can also discover new Custom Feeds to follow.</Trans>
|
||||
- </Text>
|
||||
- <Button
|
||||
- type="inverted"
|
||||
- style={[styles.emptyBtn, s.mt10]}
|
||||
- onPress={onPressDiscoverFeeds}>
|
||||
- <Text type="lg-medium" style={palInverted.text}>
|
||||
- <Trans>Discover new custom feeds</Trans>
|
||||
- </Text>
|
||||
- <FontAwesomeIcon
|
||||
- icon="angle-right"
|
||||
- style={palInverted.text as FontAwesomeIconStyle}
|
||||
- size={14}
|
||||
- />
|
||||
- </Button>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
@@ -93,13 +37,4 @@
|
||||
width: '100%',
|
||||
maxWidth: 460,
|
||||
},
|
||||
- emptyBtn: {
|
||||
- marginVertical: 20,
|
||||
- flexDirection: 'row',
|
||||
- alignItems: 'center',
|
||||
- justifyContent: 'space-between',
|
||||
- paddingVertical: 18,
|
||||
- paddingHorizontal: 24,
|
||||
- borderRadius: 30,
|
||||
- },
|
||||
})
|
||||
--- a/src/view/com/posts/PostFeed.tsx
|
||||
+++ b/src/view/com/posts/PostFeed.tsx
|
||||
@@ -765,7 +765,7 @@
|
||||
} else if (row.type === 'feedShutdownMsg') {
|
||||
return <FeedShutdownMsg feedUri={feedUriOrActorDid} />
|
||||
} else if (row.type === 'interstitialFollows') {
|
||||
- return <SuggestedFollows feed={feed} />
|
||||
+ return null
|
||||
} else if (row.type === 'interstitialProgressGuide') {
|
||||
return <ProgressGuide />
|
||||
} else if (row.type === 'ageAssuranceBanner') {
|
||||
@@ -1,17 +0,0 @@
|
||||
--- a/bskyweb/cmd/bskyweb/server.go
|
||||
+++ b/bskyweb/cmd/bskyweb/server.go
|
||||
@@ -317,6 +317,14 @@ func serve(cctx *cli.Context) error {
|
||||
e.GET("/support/tos", server.WebGeneric)
|
||||
e.GET("/support/community-guidelines", server.WebGeneric)
|
||||
e.GET("/support/copyright", server.WebGeneric)
|
||||
+ e.GET("/support/privacy-policy", server.WebGeneric)
|
||||
+ e.GET("/support/license", server.WebGeneric)
|
||||
+ e.GET("/support/app", server.WebGeneric)
|
||||
+ e.GET("/support/help", server.WebGeneric)
|
||||
+ // /about/support/ paths (for web compatibility)
|
||||
+ e.GET("/about/support/tos", server.WebGeneric)
|
||||
+ e.GET("/about/support/privacy-policy", server.WebGeneric)
|
||||
+ e.GET("/about/support/license", server.WebGeneric)
|
||||
e.GET("/intent/compose", server.WebGeneric)
|
||||
e.GET("/intent/verify-email", server.WebGeneric)
|
||||
e.GET("/intent/age-assurance", server.WebGeneric)
|
||||
@@ -1,75 +0,0 @@
|
||||
--- a/src/view/shell/bottom-bar/BottomBar.tsx
|
||||
+++ b/src/view/shell/bottom-bar/BottomBar.tsx
|
||||
@@ -196,38 +196,40 @@
|
||||
accessibilityLabel={_(msg`Search`)}
|
||||
accessibilityHint=""
|
||||
/>
|
||||
- <Btn
|
||||
- testID="bottomBarMessagesBtn"
|
||||
- icon={
|
||||
- isAtMessages ? (
|
||||
- <MessageFilled
|
||||
- width={iconWidth - 1}
|
||||
- style={[styles.ctrlIcon, t.atoms.text, styles.feedsIcon]}
|
||||
- />
|
||||
- ) : (
|
||||
- <Message
|
||||
- width={iconWidth - 1}
|
||||
- style={[styles.ctrlIcon, t.atoms.text, styles.feedsIcon]}
|
||||
- />
|
||||
- )
|
||||
- }
|
||||
- onPress={onPressMessages}
|
||||
- notificationCount={numUnreadMessages.numUnread}
|
||||
- hasNew={numUnreadMessages.hasNew}
|
||||
- accessible={true}
|
||||
- accessibilityRole="tab"
|
||||
- accessibilityLabel={_(msg`Chat`)}
|
||||
- accessibilityHint={
|
||||
- numUnreadMessages.count > 0
|
||||
- ? _(
|
||||
- plural(numUnreadMessages.numUnread ?? 0, {
|
||||
- one: '# unread item',
|
||||
- other: '# unread items',
|
||||
- }),
|
||||
- )
|
||||
- : ''
|
||||
- }
|
||||
- />
|
||||
+ {currentAccount?.isSelfHosted && (
|
||||
+ <Btn
|
||||
+ testID="bottomBarMessagesBtn"
|
||||
+ icon={
|
||||
+ isAtMessages ? (
|
||||
+ <MessageFilled
|
||||
+ width={iconWidth - 1}
|
||||
+ style={[styles.ctrlIcon, t.atoms.text, styles.feedsIcon]}
|
||||
+ />
|
||||
+ ) : (
|
||||
+ <Message
|
||||
+ width={iconWidth - 1}
|
||||
+ style={[styles.ctrlIcon, t.atoms.text, styles.feedsIcon]}
|
||||
+ />
|
||||
+ )
|
||||
+ }
|
||||
+ onPress={onPressMessages}
|
||||
+ notificationCount={numUnreadMessages.numUnread}
|
||||
+ hasNew={numUnreadMessages.hasNew}
|
||||
+ accessible={true}
|
||||
+ accessibilityRole="tab"
|
||||
+ accessibilityLabel={_(msg`Chat`)}
|
||||
+ accessibilityHint={
|
||||
+ numUnreadMessages.count > 0
|
||||
+ ? _(
|
||||
+ plural(numUnreadMessages.numUnread ?? 0, {
|
||||
+ one: '# unread item',
|
||||
+ other: '# unread items',
|
||||
+ }),
|
||||
+ )
|
||||
+ : ''
|
||||
+ }
|
||||
+ />
|
||||
+ )}
|
||||
<Btn
|
||||
testID="bottomBarNotificationsBtn"
|
||||
icon={
|
||||
@@ -1,41 +0,0 @@
|
||||
--- a/src/env/common.ts
|
||||
+++ b/src/env/common.ts
|
||||
@@ -88,7 +88,7 @@
|
||||
* Metrics API host
|
||||
*/
|
||||
export const METRICS_API_HOST: string =
|
||||
- process.env.EXPO_PUBLIC_METRICS_API_HOST || 'https://events.bsky.app'
|
||||
+ process.env.EXPO_PUBLIC_METRICS_API_HOST || ''
|
||||
|
||||
/**
|
||||
* Growthbook API host
|
||||
@@ -128,9 +128,7 @@
|
||||
*/
|
||||
export const GEOLOCATION_DEV_URL = process.env.GEOLOCATION_DEV_URL
|
||||
export const GEOLOCATION_PROD_URL = `https://ip.bsky.app`
|
||||
-export const GEOLOCATION_URL = IS_DEV
|
||||
- ? (GEOLOCATION_DEV_URL ?? GEOLOCATION_PROD_URL)
|
||||
- : GEOLOCATION_PROD_URL
|
||||
+export const GEOLOCATION_URL = null
|
||||
|
||||
/**
|
||||
* URLs for the live-event config web worker. Can be a
|
||||
@@ -138,9 +136,7 @@
|
||||
*/
|
||||
export const LIVE_EVENTS_DEV_URL = process.env.LIVE_EVENTS_DEV_URL
|
||||
export const LIVE_EVENTS_PROD_URL = `https://live-events.workers.bsky.app`
|
||||
-export const LIVE_EVENTS_URL = IS_DEV
|
||||
- ? (LIVE_EVENTS_DEV_URL ?? LIVE_EVENTS_PROD_URL)
|
||||
- : LIVE_EVENTS_PROD_URL
|
||||
+export const LIVE_EVENTS_URL = null
|
||||
|
||||
/**
|
||||
* URLs for the app-config web worker. Can be a
|
||||
@@ -148,6 +144,4 @@
|
||||
*/
|
||||
export const APP_CONFIG_DEV_URL = process.env.APP_CONFIG_DEV_URL
|
||||
export const APP_CONFIG_PROD_URL = `https://app-config.workers.bsky.app`
|
||||
-export const APP_CONFIG_URL = IS_DEV
|
||||
- ? (APP_CONFIG_DEV_URL ?? APP_CONFIG_PROD_URL)
|
||||
- : APP_CONFIG_PROD_URL
|
||||
+export const APP_CONFIG_URL = null
|
||||
@@ -1,91 +0,0 @@
|
||||
diff --git a/bskyweb/templates/base.html b/bskyweb/templates/base.html
|
||||
--- a/bskyweb/templates/base.html
|
||||
+++ b/bskyweb/templates/base.html
|
||||
@@ -7,9 +7,9 @@
|
||||
<!--
|
||||
Preconnect to essential domains
|
||||
-->
|
||||
- <link rel="preconnect" href="https://bsky.social">
|
||||
- <link rel="preconnect" href="https://go.bsky.app">
|
||||
- <title>{%- block head_title -%}Bluesky{%- endblock -%}</title>
|
||||
+ <link rel="preconnect" href="https://syu.is">
|
||||
+ <link rel="preconnect" href="https://bsky.syu.is">
|
||||
+ <title>{%- block head_title -%}syu.is{%- endblock -%}</title>
|
||||
|
||||
<!-- Hello Humans! API docs at https://atproto.com -->
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
<noscript>
|
||||
<h1 lang="en">JavaScript Required</h1>
|
||||
<p lang="en">This is a heavily interactive web application, and JavaScript is required. Simple HTML interfaces are possible, but that is not what this is.
|
||||
- <p lang="en">Learn more about Bluesky at <a href="https://bsky.social">bsky.social</a> and <a href="https://atproto.com">atproto.com</a>.
|
||||
+ <p lang="en">Learn more at <a href="https://syu.is">syu.is</a> and <a href="https://atproto.com">atproto.com</a>.
|
||||
{% block noscript_extra %}{% endblock %}
|
||||
</noscript>
|
||||
{% endblock -%}
|
||||
diff --git a/bskyweb/templates/home.html b/bskyweb/templates/home.html
|
||||
--- a/bskyweb/templates/home.html
|
||||
+++ b/bskyweb/templates/home.html
|
||||
@@ -1,17 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
-{% block head_title %}Bluesky{% endblock %}
|
||||
+{% block head_title %}syu.is{% endblock %}
|
||||
|
||||
{% block html_head_extra -%}
|
||||
- <meta property="og:title" content="Bluesky" />
|
||||
- <meta name="twitter:title" content="Bluesky" />
|
||||
+ <meta property="og:title" content="syu.is" />
|
||||
+ <meta name="twitter:title" content="syu.is" />
|
||||
|
||||
<meta name="description" content="Social media as it should be. Find your community among millions of users, unleash your creativity, and have some fun again." />
|
||||
<meta name="og:description" content="Social media as it should be. Find your community among millions of users, unleash your creativity, and have some fun again." />
|
||||
<meta name="twitter:description" content="Social media as it should be. Find your community among millions of users, unleash your creativity, and have some fun again." />
|
||||
|
||||
- <meta property="og:url" content="https://bsky.app" />
|
||||
- <meta name="twitter:url" content="https://bsky.app" />
|
||||
- <link rel="canonical" href="https://bsky.app" />
|
||||
+ <meta property="og:url" content="https://syu.is" />
|
||||
+ <meta name="twitter:url" content="https://syu.is" />
|
||||
+ <link rel="canonical" href="https://syu.is" />
|
||||
|
||||
<meta property="og:image" content="https://bsky.app/static/social-card-default-gradient.png" />
|
||||
diff --git a/bskyweb/templates/error.html b/bskyweb/templates/error.html
|
||||
--- a/bskyweb/templates/error.html
|
||||
+++ b/bskyweb/templates/error.html
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
-{% block head_title %}Error {{ statusCode }} - Bluesky{% endblock %}
|
||||
+{% block head_title %}Error {{ statusCode }} - syu.is{% endblock %}
|
||||
|
||||
{% block noscript_extra %}
|
||||
{%- if statusCode == 404 %}
|
||||
diff --git a/bskyweb/templates/starterpack.html b/bskyweb/templates/starterpack.html
|
||||
--- a/bskyweb/templates/starterpack.html
|
||||
+++ b/bskyweb/templates/starterpack.html
|
||||
@@ -17,8 +17,8 @@
|
||||
<meta property="og:title" content="{{ title }}" />
|
||||
<meta name="twitter:title" content="{{ title }}" />
|
||||
{%- else -%}
|
||||
- <meta property="og:title" content="Bluesky" />
|
||||
- <meta name="twitter:title" content="Bluesky" />
|
||||
+ <meta property="og:title" content="syu.is" />
|
||||
+ <meta name="twitter:title" content="syu.is" />
|
||||
{% endif -%}
|
||||
<meta name="description" content="Join the conversation" />
|
||||
<meta name="og:description" content="Join the conversation" />
|
||||
diff --git a/web/index.html b/web/index.html
|
||||
--- a/web/index.html
|
||||
+++ b/web/index.html
|
||||
@@ -14,8 +14,8 @@
|
||||
<!--
|
||||
Preconnect to essential domains
|
||||
-->
|
||||
- <link rel="preconnect" href="https://bsky.social">
|
||||
- <link rel="preconnect" href="https://go.bsky.app">
|
||||
+ <link rel="preconnect" href="https://syu.is">
|
||||
+ <link rel="preconnect" href="https://bsky.syu.is">
|
||||
<title>%WEB_TITLE%</title>
|
||||
|
||||
<link rel="preload" as="font" type="font/woff2" href="/static/media/InterVariable.c504db5c06caaf7cdfba.woff2" crossorigin>
|
||||
@@ -1,193 +0,0 @@
|
||||
--- a/src/screens/Signup/StepInfo/index.tsx
|
||||
+++ b/src/screens/Signup/StepInfo/index.tsx
|
||||
@@ -8,46 +8,18 @@
|
||||
import {isEmailMaybeInvalid} from '#/lib/strings/email'
|
||||
import {logger} from '#/logger'
|
||||
import {useSignupContext} from '#/screens/Signup/state'
|
||||
-import {Policies} from '#/screens/Signup/StepInfo/Policies'
|
||||
import {atoms as a, native} from '#/alf'
|
||||
-import * as Admonition from '#/components/Admonition'
|
||||
-import * as Dialog from '#/components/Dialog'
|
||||
-import {DeviceLocationRequestDialog} from '#/components/dialogs/DeviceLocationRequestDialog'
|
||||
-import * as DateField from '#/components/forms/DateField'
|
||||
-import {type DateFieldRef} from '#/components/forms/DateField/types'
|
||||
import {FormError} from '#/components/forms/FormError'
|
||||
import {HostingProvider} from '#/components/forms/HostingProvider'
|
||||
import * as TextField from '#/components/forms/TextField'
|
||||
import {Envelope_Stroke2_Corner0_Rounded as Envelope} from '#/components/icons/Envelope'
|
||||
import {Lock_Stroke2_Corner0_Rounded as Lock} from '#/components/icons/Lock'
|
||||
import {Ticket_Stroke2_Corner0_Rounded as Ticket} from '#/components/icons/Ticket'
|
||||
-import {createStaticClick, SimpleInlineLinkText} from '#/components/Link'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {usePreemptivelyCompleteActivePolicyUpdate} from '#/components/PolicyUpdateOverlay/usePreemptivelyCompleteActivePolicyUpdate'
|
||||
-import * as Toast from '#/components/Toast'
|
||||
-import {
|
||||
- isUnderAge,
|
||||
- MIN_ACCESS_AGE,
|
||||
- useAgeAssuranceRegionConfigWithFallback,
|
||||
-} from '#/ageAssurance/util'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
-import {IS_NATIVE} from '#/env'
|
||||
-import {
|
||||
- useDeviceGeolocationApi,
|
||||
- useIsDeviceGeolocationGranted,
|
||||
-} from '#/geolocation'
|
||||
import {BackNextButtons} from '../BackNextButtons'
|
||||
|
||||
-function sanitizeDate(date: Date): Date {
|
||||
- if (!date || date.toString() === 'Invalid Date') {
|
||||
- logger.error(`Create account: handled invalid date for birthDate`, {
|
||||
- hasDate: !!date,
|
||||
- })
|
||||
- return new Date()
|
||||
- }
|
||||
- return date
|
||||
-}
|
||||
-
|
||||
export function StepInfo({
|
||||
onPressBack,
|
||||
isServerError,
|
||||
@@ -72,22 +44,7 @@
|
||||
|
||||
const emailInputRef = useRef<TextInput>(null)
|
||||
const passwordInputRef = useRef<TextInput>(null)
|
||||
- const birthdateInputRef = useRef<DateFieldRef>(null)
|
||||
|
||||
- const aaRegionConfig = useAgeAssuranceRegionConfigWithFallback()
|
||||
- const {setDeviceGeolocation} = useDeviceGeolocationApi()
|
||||
- const locationControl = Dialog.useDialogControl()
|
||||
- const isOverRegionMinAccessAge = state.dateOfBirth
|
||||
- ? !isUnderAge(state.dateOfBirth.toISOString(), aaRegionConfig.minAccessAge)
|
||||
- : true
|
||||
- const isOverAppMinAccessAge = state.dateOfBirth
|
||||
- ? !isUnderAge(state.dateOfBirth.toISOString(), MIN_ACCESS_AGE)
|
||||
- : true
|
||||
- const isOverMinAdultAge = state.dateOfBirth
|
||||
- ? !isUnderAge(state.dateOfBirth.toISOString(), 18)
|
||||
- : true
|
||||
- const isDeviceGeolocationGranted = useIsDeviceGeolocationGranted()
|
||||
-
|
||||
const [hasWarnedEmail, setHasWarnedEmail] = React.useState<boolean>(false)
|
||||
|
||||
const tldtsRef = React.useRef<typeof tldts>(undefined)
|
||||
@@ -107,10 +64,6 @@
|
||||
const emailChanged = prevEmailValueRef.current !== email
|
||||
const password = passwordValueRef.current
|
||||
|
||||
- if (!isOverRegionMinAccessAge) {
|
||||
- return
|
||||
- }
|
||||
-
|
||||
if (state.serviceDescription?.inviteCodeRequired && !inviteCode) {
|
||||
return dispatch({
|
||||
type: 'setError',
|
||||
@@ -273,107 +226,16 @@
|
||||
secureTextEntry
|
||||
autoComplete="new-password"
|
||||
autoCapitalize="none"
|
||||
- returnKeyType="next"
|
||||
- submitBehavior={native('blurAndSubmit')}
|
||||
- onSubmitEditing={native(() =>
|
||||
- birthdateInputRef.current?.focus(),
|
||||
- )}
|
||||
+ returnKeyType="done"
|
||||
passwordRules="minlength: 8;"
|
||||
/>
|
||||
</TextField.Root>
|
||||
- </View>
|
||||
- <View>
|
||||
- <DateField.LabelText>
|
||||
- <Trans>Your birth date</Trans>
|
||||
- </DateField.LabelText>
|
||||
- <DateField.DateField
|
||||
- testID="date"
|
||||
- inputRef={birthdateInputRef}
|
||||
- value={state.dateOfBirth}
|
||||
- onChangeDate={date => {
|
||||
- dispatch({
|
||||
- type: 'setDateOfBirth',
|
||||
- value: sanitizeDate(new Date(date)),
|
||||
- })
|
||||
- }}
|
||||
- label={_(msg`Date of birth`)}
|
||||
- accessibilityHint={_(msg`Select your date of birth`)}
|
||||
- maximumDate={new Date()}
|
||||
- />
|
||||
</View>
|
||||
-
|
||||
- <View style={[a.gap_sm]}>
|
||||
- <Policies serviceDescription={state.serviceDescription} />
|
||||
-
|
||||
- {!isOverRegionMinAccessAge || !isOverAppMinAccessAge ? (
|
||||
- <Admonition.Outer type="error">
|
||||
- <Admonition.Row>
|
||||
- <Admonition.Icon />
|
||||
- <Admonition.Content>
|
||||
- <Admonition.Text>
|
||||
- {!isOverAppMinAccessAge ? (
|
||||
- <Plural
|
||||
- value={MIN_ACCESS_AGE}
|
||||
- other="You must be # years of age or older to create an account."
|
||||
- />
|
||||
- ) : (
|
||||
- <Plural
|
||||
- value={aaRegionConfig.minAccessAge}
|
||||
- other="You must be # years of age or older to create an account in your region."
|
||||
- />
|
||||
- )}
|
||||
- </Admonition.Text>
|
||||
- {IS_NATIVE &&
|
||||
- !isDeviceGeolocationGranted &&
|
||||
- isOverAppMinAccessAge && (
|
||||
- <Admonition.Text>
|
||||
- <Trans>
|
||||
- Have we got your location wrong?{' '}
|
||||
- <SimpleInlineLinkText
|
||||
- label={_(
|
||||
- msg`Tap here to confirm your location with GPS.`,
|
||||
- )}
|
||||
- {...createStaticClick(() => {
|
||||
- locationControl.open()
|
||||
- })}>
|
||||
- Tap here to confirm your location with GPS.
|
||||
- </SimpleInlineLinkText>
|
||||
- </Trans>
|
||||
- </Admonition.Text>
|
||||
- )}
|
||||
- </Admonition.Content>
|
||||
- </Admonition.Row>
|
||||
- </Admonition.Outer>
|
||||
- ) : !isOverMinAdultAge ? (
|
||||
- <Admonition.Admonition type="warning">
|
||||
- <Trans>
|
||||
- If you are not yet an adult according to the laws of your
|
||||
- country, your parent or legal guardian must read these Terms
|
||||
- on your behalf.
|
||||
- </Trans>
|
||||
- </Admonition.Admonition>
|
||||
- ) : undefined}
|
||||
- </View>
|
||||
-
|
||||
- {IS_NATIVE && (
|
||||
- <DeviceLocationRequestDialog
|
||||
- control={locationControl}
|
||||
- onLocationAcquired={props => {
|
||||
- props.closeDialog(() => {
|
||||
- // set this after close!
|
||||
- setDeviceGeolocation(props.geolocation)
|
||||
- Toast.show(_(msg`Your location has been updated.`), {
|
||||
- type: 'success',
|
||||
- })
|
||||
- })
|
||||
- }}
|
||||
- />
|
||||
- )}
|
||||
</>
|
||||
) : undefined}
|
||||
</View>
|
||||
<BackNextButtons
|
||||
- hideNext={!isOverRegionMinAccessAge}
|
||||
+ hideNext={false}
|
||||
showRetry={isServerError}
|
||||
isLoading={state.isLoading}
|
||||
onBackPress={onPressBack}
|
||||
@@ -1,16 +0,0 @@
|
||||
diff --git a/src/screens/Search/Explore.tsx b/src/screens/Search/Explore.tsx
|
||||
--- a/src/screens/Search/Explore.tsx
|
||||
+++ b/src/screens/Search/Explore.tsx
|
||||
@@ -687,12 +687,7 @@ export function Explore({
|
||||
|
||||
if (useFullExperience) {
|
||||
i.push(trendingTopicsModule)
|
||||
- i.push(...suggestedFeedsModule)
|
||||
- i.push(...suggestedFollowsModule)
|
||||
- i.push(...suggestedStarterPacksModule)
|
||||
i.push(...feedPreviewsModule)
|
||||
- } else {
|
||||
- i.push(...suggestedFollowsModule)
|
||||
}
|
||||
|
||||
return i
|
||||
@@ -1,84 +0,0 @@
|
||||
diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx
|
||||
--- a/src/view/screens/Feeds.tsx
|
||||
+++ b/src/view/screens/Feeds.tsx
|
||||
@@ -288,80 +288,7 @@ export function FeedsScreen(_props: Props) {
|
||||
}
|
||||
}
|
||||
|
||||
- if (!hasSession || (hasSession && canShowDiscoverSection)) {
|
||||
- slices.push({
|
||||
- key: 'popularFeedsHeader',
|
||||
- type: 'popularFeedsHeader',
|
||||
- })
|
||||
|
||||
- if (popularFeedsError || searchError) {
|
||||
- slices.push({
|
||||
- key: 'popularFeedsError',
|
||||
- type: 'error',
|
||||
- error: cleanError(
|
||||
- popularFeedsError?.toString() ?? searchError?.toString() ?? '',
|
||||
- ),
|
||||
- })
|
||||
- } else {
|
||||
- if (isUserSearching) {
|
||||
- if (isSearchPending || !searchResults) {
|
||||
- slices.push({
|
||||
- key: 'popularFeedsLoading',
|
||||
- type: 'popularFeedsLoading',
|
||||
- })
|
||||
- } else {
|
||||
- if (!searchResults || searchResults?.length === 0) {
|
||||
- slices.push({
|
||||
- key: 'popularFeedsNoResults',
|
||||
- type: 'popularFeedsNoResults',
|
||||
- })
|
||||
- } else {
|
||||
- slices = slices.concat(
|
||||
- searchResults.map(feed => ({
|
||||
- key: `popularFeed:${feed.uri}`,
|
||||
- type: 'popularFeed',
|
||||
- feedUri: feed.uri,
|
||||
- feed,
|
||||
- })),
|
||||
- )
|
||||
- }
|
||||
- }
|
||||
- } else {
|
||||
- if (isPopularFeedsFetching && !popularFeeds?.pages) {
|
||||
- slices.push({
|
||||
- key: 'popularFeedsLoading',
|
||||
- type: 'popularFeedsLoading',
|
||||
- })
|
||||
- } else {
|
||||
- if (!popularFeeds?.pages) {
|
||||
- slices.push({
|
||||
- key: 'popularFeedsNoResults',
|
||||
- type: 'popularFeedsNoResults',
|
||||
- })
|
||||
- } else {
|
||||
- for (const page of popularFeeds.pages || []) {
|
||||
- slices = slices.concat(
|
||||
- page.feeds.map(feed => ({
|
||||
- key: `popularFeed:${feed.uri}`,
|
||||
- type: 'popularFeed',
|
||||
- feedUri: feed.uri,
|
||||
- feed,
|
||||
- })),
|
||||
- )
|
||||
- }
|
||||
-
|
||||
- if (isPopularFeedsFetchingNextPage) {
|
||||
- slices.push({
|
||||
- key: 'popularFeedsLoadingMore',
|
||||
- type: 'popularFeedsLoadingMore',
|
||||
- })
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
return slices
|
||||
}, [
|
||||
hasSession,
|
||||
@@ -1,71 +0,0 @@
|
||||
diff --git a/src/lib/api/feed/custom.ts b/src/lib/api/feed/custom.ts
|
||||
index 18bb8c8f0..bab286d7a 100644
|
||||
--- a/src/lib/api/feed/custom.ts
|
||||
+++ b/src/lib/api/feed/custom.ts
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
jsonStringToLex,
|
||||
} from '@atproto/api'
|
||||
|
||||
+import {PUBLIC_APPVIEW} from '#/lib/constants'
|
||||
import {
|
||||
getAppLanguageAsContentLanguage,
|
||||
getContentLanguages,
|
||||
@@ -12,6 +13,17 @@ import {
|
||||
import {type FeedAPI, type FeedAPIResponse} from './types'
|
||||
import {createBskyTopicsHeader, isBlueskyOwnedFeed} from './utils'
|
||||
|
||||
+// Check if the feed is hosted on syu.is network
|
||||
+function isSyuIsFeed(feedUri: string): boolean {
|
||||
+ return feedUri.includes('did:plc:6qyecktefllvenje24fcxnie') || feedUri.includes('syu.is')
|
||||
+}
|
||||
+
|
||||
+// Check if the agent is connected to syu.is
|
||||
+function isAgentOnSyuIs(agent: BskyAgent): boolean {
|
||||
+ const serviceUrl = agent.service?.toString() || ''
|
||||
+ return serviceUrl.includes('syu.is')
|
||||
+}
|
||||
+
|
||||
export class CustomFeedAPI implements FeedAPI {
|
||||
agent: BskyAgent
|
||||
params: GetCustomFeed.QueryParams
|
||||
@@ -54,8 +66,12 @@ export class CustomFeedAPI implements FeedAPI {
|
||||
const agent = this.agent
|
||||
const isBlueskyOwned = isBlueskyOwnedFeed(this.params.feed)
|
||||
|
||||
- const res = agent.did
|
||||
- ? await this.agent.app.bsky.feed.getFeed(
|
||||
+ // For syu.is feeds accessed from non-syu.is accounts, use PUBLIC_APPVIEW
|
||||
+ const needsPublicAppView = isSyuIsFeed(this.params.feed) && !isAgentOnSyuIs(agent)
|
||||
+
|
||||
+ const res = !agent.did || needsPublicAppView
|
||||
+ ? await loggedOutFetch({...this.params, cursor, limit})
|
||||
+ : await this.agent.app.bsky.feed.getFeed(
|
||||
{
|
||||
...this.params,
|
||||
cursor,
|
||||
@@ -70,7 +86,6 @@ export class CustomFeedAPI implements FeedAPI {
|
||||
},
|
||||
},
|
||||
)
|
||||
- : await loggedOutFetch({...this.params, cursor, limit})
|
||||
if (res.success) {
|
||||
// NOTE
|
||||
// some custom feeds fail to enforce the pagination limit
|
||||
@@ -120,7 +135,7 @@ async function loggedOutFetch({
|
||||
|
||||
// manually construct fetch call so we can add the `lang` cache-busting param
|
||||
let res = await fetch(
|
||||
- `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${
|
||||
+ `${PUBLIC_APPVIEW}/xrpc/app.bsky.feed.getFeed?feed=${encodeURIComponent(feed)}${
|
||||
cursor ? `&cursor=${cursor}` : ''
|
||||
}&limit=${limit}&lang=${contentLangs}`,
|
||||
{
|
||||
@@ -140,7 +155,7 @@ async function loggedOutFetch({
|
||||
|
||||
// no data, try again with language headers removed
|
||||
res = await fetch(
|
||||
- `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${
|
||||
+ `${PUBLIC_APPVIEW}/xrpc/app.bsky.feed.getFeed?feed=${encodeURIComponent(feed)}${
|
||||
cursor ? `&cursor=${cursor}` : ''
|
||||
}&limit=${limit}`,
|
||||
{method: 'GET', headers: {'Accept-Language': '', ...labelersHeader}},
|
||||
@@ -1,23 +0,0 @@
|
||||
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
|
||||
index 123456789..987654321 100644
|
||||
--- a/src/view/screens/Profile.tsx
|
||||
+++ b/src/view/screens/Profile.tsx
|
||||
@@ -218,13 +218,13 @@ function ProfileScreenLoaded({
|
||||
const showPostsTab = true
|
||||
const showRepliesTab = hasSession
|
||||
const showMediaTab = !hasLabeler
|
||||
- const showVideosTab = !hasLabeler
|
||||
+ const showVideosTab = false
|
||||
const showLikesTab = isMe
|
||||
const feedGenCount = profile.associated?.feedgens || 0
|
||||
- const showFeedsTab = isMe || feedGenCount > 0
|
||||
+ const showFeedsTab = feedGenCount > 0
|
||||
const starterPackCount = profile.associated?.starterPacks || 0
|
||||
- const showStarterPacksTab = isMe || starterPackCount > 0
|
||||
+ const showStarterPacksTab = false
|
||||
// subtract starterpack count from list count, since starterpacks are a type of list
|
||||
const listCount = (profile.associated?.lists || 0) - starterPackCount
|
||||
- const showListsTab = hasSession && (isMe || listCount > 0)
|
||||
+ const showListsTab = false
|
||||
|
||||
const sectionTitles = [
|
||||
@@ -1,28 +0,0 @@
|
||||
diff --git a/src/view/com/home/HomeHeader.tsx b/src/view/com/home/HomeHeader.tsx
|
||||
--- a/src/view/com/home/HomeHeader.tsx
|
||||
+++ b/src/view/com/home/HomeHeader.tsx
|
||||
@@ -3,7 +3,6 @@ import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {type FeedSourceInfo} from '#/state/queries/feed'
|
||||
-import {useSession} from '#/state/session'
|
||||
import {type RenderTabBarFnProps} from '#/view/com/pager/Pager'
|
||||
import {TabBar} from '../pager/TabBar'
|
||||
import {HomeHeaderLayout} from './HomeHeaderLayout'
|
||||
@@ -16,17 +15,15 @@ export function HomeHeader(
|
||||
) {
|
||||
const {feeds, onSelect: onSelectProp} = props
|
||||
- const {hasSession} = useSession()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
const hasPinnedCustom = React.useMemo<boolean>(() => {
|
||||
- if (!hasSession) return false
|
||||
return feeds.some(tab => {
|
||||
const isFollowing = tab.uri === 'following'
|
||||
return !isFollowing
|
||||
})
|
||||
- }, [feeds, hasSession])
|
||||
+ }, [feeds])
|
||||
|
||||
const items = React.useMemo(() => {
|
||||
const pinnedNames = feeds.map(f => f.displayName)
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx b/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx
|
||||
index 63e11a7f4..70fa993cf 100644
|
||||
--- a/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx
|
||||
+++ b/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx
|
||||
@@ -25,7 +25,7 @@ export const enabled = createIsEnabledCheck(props => {
|
||||
!IS_E2E &&
|
||||
isNative &&
|
||||
isExistingUserAsOf(
|
||||
- '2025-12-16T00:00:00.000Z',
|
||||
+ '2099-12-16T00:00:00.000Z',
|
||||
props.currentProfile.createdAt,
|
||||
) &&
|
||||
isFindContactsFeatureEnabled(props.geolocation.countryCode)
|
||||
@@ -1,132 +0,0 @@
|
||||
--- a/src/screens/Profile/Header/ProfileHeaderStandard.tsx
|
||||
+++ b/src/screens/Profile/Header/ProfileHeaderStandard.tsx
|
||||
@@ -1,5 +1,5 @@
|
||||
import {memo, useMemo, useState} from 'react'
|
||||
-import {View} from 'react-native'
|
||||
+import {Image, Pressable, View} from 'react-native'
|
||||
import {
|
||||
type AppBskyActorDefs,
|
||||
moderateProfile,
|
||||
@@ -11,7 +11,10 @@
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
|
||||
+import {useQuery} from '@tanstack/react-query'
|
||||
+
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
+import {useOpenLink} from '#/lib/hooks/useOpenLink'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {logger} from '#/logger'
|
||||
@@ -47,6 +50,103 @@
|
||||
import {ProfileHeaderShell} from './Shell'
|
||||
import {ProfileHeaderSuggestedFollows} from './SuggestedFollows'
|
||||
|
||||
+const SERVICE_FAVICONS: Record<string, any> = {
|
||||
+ 'syui.ai': require('../../../../assets/favicons/syui.ai.png'),
|
||||
+ 'bsky.app': require('../../../../assets/favicons/bsky.app.png'),
|
||||
+ 'atproto.com': require('../../../../assets/favicons/atproto.com.png'),
|
||||
+}
|
||||
+
|
||||
+async function resolvePds(did: string): Promise<string> {
|
||||
+ if (did.startsWith('did:web:')) {
|
||||
+ const host = did.split(':').slice(2).join(':')
|
||||
+ const res = await fetch(`https://${host}/.well-known/did.json`)
|
||||
+ if (!res.ok) throw new Error('failed to resolve did:web')
|
||||
+ const doc = await res.json()
|
||||
+ const pds = doc.service?.find((s: any) => s.id === '#atproto_pds')?.serviceEndpoint
|
||||
+ if (pds) return pds
|
||||
+ return `https://${host}`
|
||||
+ }
|
||||
+ const res = await fetch(`https://plc.directory/${did}`)
|
||||
+ if (!res.ok) throw new Error('failed to resolve DID')
|
||||
+ const doc = await res.json()
|
||||
+ const pds = doc.service?.find((s: any) => s.id === '#atproto_pds')?.serviceEndpoint
|
||||
+ if (!pds) throw new Error('no PDS found')
|
||||
+ return pds
|
||||
+}
|
||||
+
|
||||
+function ProfileServiceLinks({
|
||||
+ profile,
|
||||
+}: {
|
||||
+ profile: AppBskyActorDefs.ProfileViewDetailed
|
||||
+}) {
|
||||
+ const t = useTheme()
|
||||
+ const openLink = useOpenLink()
|
||||
+
|
||||
+ const {data: services} = useQuery({
|
||||
+ queryKey: ['profile-services', profile.did],
|
||||
+ queryFn: async () => {
|
||||
+ const pds = await resolvePds(profile.did)
|
||||
+ const res = await fetch(
|
||||
+ `${pds}/xrpc/com.atproto.repo.describeRepo?repo=${encodeURIComponent(profile.did)}`,
|
||||
+ )
|
||||
+ if (!res.ok) throw new Error('failed')
|
||||
+ const data = await res.json()
|
||||
+ const collections: string[] = data.collections || []
|
||||
+ const serviceSet = new Set<string>()
|
||||
+ for (const nsid of collections) {
|
||||
+ const parts = nsid.split('.')
|
||||
+ if (parts.length >= 2) {
|
||||
+ const domain = parts.slice(0, 2).reverse().join('.')
|
||||
+ serviceSet.add(domain)
|
||||
+ }
|
||||
+ }
|
||||
+ return Array.from(serviceSet)
|
||||
+ },
|
||||
+ })
|
||||
+
|
||||
+ if (!services || services.length === 0) return null
|
||||
+
|
||||
+ return (
|
||||
+ <View style={[a.flex_row, a.flex_wrap, a.gap_sm, a.pt_xs]}>
|
||||
+ {services.map(service => (
|
||||
+ <Pressable
|
||||
+ key={service}
|
||||
+ onPress={() =>
|
||||
+ openLink(
|
||||
+ `https://at.syu.is/@${profile.handle}/at/service/${service}`,
|
||||
+ )
|
||||
+ }
|
||||
+ style={[
|
||||
+ a.flex_row,
|
||||
+ a.align_center,
|
||||
+ a.gap_xs,
|
||||
+ a.rounded_full,
|
||||
+ t.atoms.bg_contrast_50,
|
||||
+ {paddingVertical: 6, paddingHorizontal: 10},
|
||||
+ ]}>
|
||||
+ <Image
|
||||
+ source={
|
||||
+ SERVICE_FAVICONS[service] || {
|
||||
+ uri: `https://www.google.com/s2/favicons?domain=${service}&sz=32`,
|
||||
+ }
|
||||
+ }
|
||||
+ style={{width: 14, height: 14, borderRadius: 3}}
|
||||
+ accessibilityIgnoresInvertColors
|
||||
+ />
|
||||
+ <Text
|
||||
+ style={[
|
||||
+ a.text_xs,
|
||||
+ a.font_medium,
|
||||
+ t.atoms.text_contrast_medium,
|
||||
+ ]}>
|
||||
+ {service}
|
||||
+ </Text>
|
||||
+ </Pressable>
|
||||
+ ))}
|
||||
+ </View>
|
||||
+ )
|
||||
+}
|
||||
+
|
||||
interface Props {
|
||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||
descriptionRT: RichTextAPI | null
|
||||
@@ -152,6 +252,7 @@
|
||||
{!isPlaceholderProfile && !isBlockedUser && (
|
||||
<View style={a.gap_md}>
|
||||
<ProfileHeaderMetrics profile={profile} />
|
||||
+ <ProfileServiceLinks profile={profile} />
|
||||
{descriptionRT && !moderation.ui('profileView').blur ? (
|
||||
<View pointerEvents="auto">
|
||||
<RichText
|
||||
@@ -1,35 +0,0 @@
|
||||
diff --git a/src/view/com/posts/PostFeedItem.tsx b/src/view/com/posts/PostFeedItem.tsx
|
||||
--- a/src/view/com/posts/PostFeedItem.tsx
|
||||
+++ b/src/view/com/posts/PostFeedItem.tsx
|
||||
@@ -385,17 +385,19 @@
|
||||
threadgateRecord={threadgateRecord}
|
||||
/>
|
||||
- <PostControls
|
||||
- post={post}
|
||||
- record={record}
|
||||
- richText={richText}
|
||||
- onPressReply={onPressReply}
|
||||
- logContext="FeedItem"
|
||||
- feedContext={feedContext}
|
||||
- reqId={reqId}
|
||||
- threadgateRecord={threadgateRecord}
|
||||
- onShowLess={onShowLess}
|
||||
- viaRepost={viaRepost}
|
||||
- />
|
||||
+ {false && (
|
||||
+ <PostControls
|
||||
+ post={post}
|
||||
+ record={record}
|
||||
+ richText={richText}
|
||||
+ onPressReply={onPressReply}
|
||||
+ logContext="FeedItem"
|
||||
+ feedContext={feedContext}
|
||||
+ reqId={reqId}
|
||||
+ threadgateRecord={threadgateRecord}
|
||||
+ onShowLess={onShowLess}
|
||||
+ viaRepost={viaRepost}
|
||||
+ />
|
||||
+ )}
|
||||
</View>
|
||||
|
||||
<DiscoverDebug feedContext={feedContext} />
|
||||
@@ -1,50 +0,0 @@
|
||||
--- a/src/view/com/posts/PostFeed.tsx 2026-02-16 02:19:59
|
||||
+++ b/src/view/com/posts/PostFeed.tsx 2026-02-16 02:20:13
|
||||
@@ -519,16 +519,17 @@
|
||||
key: 'liveEventFeedsAndTrendingBanner-' + sliceIndex,
|
||||
})
|
||||
// Show composer prompt for Discover and Following feeds
|
||||
- if (
|
||||
- hasSession &&
|
||||
- (feedUriOrActorDid === DISCOVER_FEED_URI ||
|
||||
- feed === 'following')
|
||||
- ) {
|
||||
- arr.push({
|
||||
- type: 'composerPrompt',
|
||||
- key: 'composerPrompt-' + sliceIndex,
|
||||
- })
|
||||
- }
|
||||
+ // Disabled: hide composer prompt
|
||||
+ // if (
|
||||
+ // hasSession &&
|
||||
+ // (feedUriOrActorDid === DISCOVER_FEED_URI ||
|
||||
+ // feed === 'following')
|
||||
+ // ) {
|
||||
+ // arr.push({
|
||||
+ // type: 'composerPrompt',
|
||||
+ // key: 'composerPrompt-' + sliceIndex,
|
||||
+ // })
|
||||
+ // }
|
||||
} else if (sliceIndex === 15) {
|
||||
if (areVideoFeedsEnabled && !trendingVideoDisabled) {
|
||||
arr.push({
|
||||
@@ -545,12 +546,13 @@
|
||||
} else if (feedKind === 'following') {
|
||||
if (sliceIndex === 0) {
|
||||
// Show composer prompt for Following feed
|
||||
- if (hasSession) {
|
||||
- arr.push({
|
||||
- type: 'composerPrompt',
|
||||
- key: 'composerPrompt-' + sliceIndex,
|
||||
- })
|
||||
- }
|
||||
+ // Disabled: hide composer prompt
|
||||
+ // if (hasSession) {
|
||||
+ // arr.push({
|
||||
+ // type: 'composerPrompt',
|
||||
+ // key: 'composerPrompt-' + sliceIndex,
|
||||
+ // })
|
||||
+ // }
|
||||
}
|
||||
} else if (feedKind === 'profile') {
|
||||
if (sliceIndex === 5) {
|
||||
@@ -1,14 +0,0 @@
|
||||
--- a/src/view/com/auth/SplashScreen.tsx 2026-02-16 02:55:08
|
||||
+++ b/src/view/com/auth/SplashScreen.tsx 2026-02-16 02:55:16
|
||||
@@ -118,8 +118,9 @@
|
||||
accessibilityHint={_(
|
||||
msg`Opens flow to sign in to your existing Bluesky account`,
|
||||
)}
|
||||
- size="large">
|
||||
- <ButtonText style={{color: 'white'}}>
|
||||
+ size="large"
|
||||
+ color="primary">
|
||||
+ <ButtonText>
|
||||
<Trans>Sign in</Trans>
|
||||
</ButtonText>
|
||||
</Button>
|
||||
@@ -1,18 +0,0 @@
|
||||
--- a/src/screens/Profile/Header/ProfileHeaderStandard.tsx
|
||||
+++ b/src/screens/Profile/Header/ProfileHeaderStandard.tsx
|
||||
@@ -48,6 +48,7 @@
|
||||
import {ProfileHeaderHandle} from './Handle'
|
||||
import {ProfileHeaderMetrics} from './Metrics'
|
||||
import {ProfileHeaderShell} from './Shell'
|
||||
+import {ProfileAtLinks} from './ProfileAtLinks'
|
||||
import {ProfileHeaderSuggestedFollows} from './SuggestedFollows'
|
||||
|
||||
const SERVICE_FAVICONS: Record<string, any> = {
|
||||
@@ -253,6 +254,7 @@
|
||||
<View style={a.gap_md}>
|
||||
<ProfileHeaderMetrics profile={profile} />
|
||||
<ProfileServiceLinks profile={profile} />
|
||||
+ <ProfileAtLinks profile={profile} />
|
||||
{descriptionRT && !moderation.ui('profileView').blur ? (
|
||||
<View pointerEvents="auto">
|
||||
<RichText
|
||||
@@ -1,19 +0,0 @@
|
||||
--- a/src/view/shell/desktop/RightNav.tsx
|
||||
+++ b/src/view/shell/desktop/RightNav.tsx
|
||||
@@ -111,14 +111,14 @@
|
||||
</>
|
||||
)}
|
||||
<InlineLinkText
|
||||
- to="https://bsky.social/about/support/privacy-policy"
|
||||
+ to="/support/privacy-policy"
|
||||
style={[t.atoms.text_contrast_medium]}
|
||||
label={_(msg`Privacy`)}>
|
||||
{_(msg`Privacy`)}
|
||||
</InlineLinkText>
|
||||
<Text style={[t.atoms.text_contrast_low]}>{' ∙ '}</Text>
|
||||
<InlineLinkText
|
||||
- to="https://bsky.social/about/support/tos"
|
||||
+ to="/support/tos"
|
||||
style={[t.atoms.text_contrast_medium]}
|
||||
label={_(msg`Terms`)}>
|
||||
{_(msg`Terms`)}
|
||||
@@ -1,60 +0,0 @@
|
||||
--- a/src/view/com/auth/SplashScreen.tsx
|
||||
+++ b/src/view/com/auth/SplashScreen.tsx
|
||||
@@ -2,6 +2,7 @@
|
||||
import {Image as RNImage, View} from 'react-native'
|
||||
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
|
||||
import {Image} from 'expo-image'
|
||||
+import {useVideoPlayer, VideoView} from 'expo-video'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
@@ -15,10 +16,13 @@
|
||||
import splashImagePointer from '../../../../assets/splash/illustration-mobile.png'
|
||||
// @ts-ignore
|
||||
import darkSplashImagePointer from '../../../../assets/splash/illustration-mobile-dark.png'
|
||||
+// @ts-ignore
|
||||
+import splashVideoPointer from '../../../../assets/splash/illustration-mobile.mp4'
|
||||
const splashImageUri = RNImage.resolveAssetSource(splashImagePointer).uri
|
||||
const darkSplashImageUri = RNImage.resolveAssetSource(
|
||||
darkSplashImagePointer,
|
||||
).uri
|
||||
+const splashVideoUri = RNImage.resolveAssetSource(splashVideoPointer).uri
|
||||
|
||||
export const SplashScreen = ({
|
||||
onPressSignin,
|
||||
@@ -53,13 +57,30 @@
|
||||
}
|
||||
}, [t, isDarkMode])
|
||||
|
||||
+ const player = useVideoPlayer(splashVideoUri, p => {
|
||||
+ p.loop = true
|
||||
+ p.muted = true
|
||||
+ p.play()
|
||||
+ })
|
||||
+
|
||||
return (
|
||||
<>
|
||||
- <Image
|
||||
- accessibilityIgnoresInvertColors
|
||||
- source={{uri: isDarkMode ? darkSplashImageUri : splashImageUri}}
|
||||
- style={[a.absolute, a.inset_0]}
|
||||
- />
|
||||
+ {isDarkMode ? (
|
||||
+ <Image
|
||||
+ accessibilityIgnoresInvertColors
|
||||
+ source={{uri: darkSplashImageUri}}
|
||||
+ style={[a.absolute, a.inset_0]}
|
||||
+ />
|
||||
+ ) : (
|
||||
+ <VideoView
|
||||
+ player={player}
|
||||
+ style={[a.absolute, a.inset_0]}
|
||||
+ contentFit="cover"
|
||||
+ nativeControls={false}
|
||||
+ allowsFullscreen={false}
|
||||
+ allowsPictureInPicture={false}
|
||||
+ />
|
||||
+ )}
|
||||
|
||||
<Animated.View
|
||||
entering={FadeIn.duration(90)}
|
||||
@@ -1,40 +0,0 @@
|
||||
--- a/src/view/com/composer/Composer.tsx
|
||||
+++ b/src/view/com/composer/Composer.tsx
|
||||
@@ -717,16 +717,7 @@
|
||||
post.shortenedGraphemeLength > 0 || post.embed.media || post.embed.link,
|
||||
)
|
||||
|
||||
- // Show discard prompt if there's content AND either:
|
||||
- // - No draft is loaded (new composition)
|
||||
- // - Draft is loaded but has been modified
|
||||
- if (hasContent && (!composerState.draftId || composerState.isDirty)) {
|
||||
- closeAllDialogs()
|
||||
- Keyboard.dismiss()
|
||||
- discardPromptControl.open()
|
||||
- } else {
|
||||
- onClose()
|
||||
- }
|
||||
+ onClose()
|
||||
}, [
|
||||
thread,
|
||||
composerState.draftId,
|
||||
@@ -1551,18 +1542,7 @@
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
- {!isReply && (
|
||||
- <DraftsButton
|
||||
- onSelectDraft={onSelectDraft}
|
||||
- onSaveDraft={onSaveDraft}
|
||||
- onDiscard={onDiscard}
|
||||
- isEmpty={isEmpty}
|
||||
- isDirty={isDirty}
|
||||
- isEditingDraft={isEditingDraft}
|
||||
- canSaveDraft={canSaveDraft}
|
||||
- textLength={textLength}
|
||||
- />
|
||||
- )}
|
||||
+ {/* DraftsButton removed */}
|
||||
<Button
|
||||
testID="composerPublishBtn"
|
||||
label={
|
||||
@@ -1,55 +0,0 @@
|
||||
diff --git a/src/features/liveEvents/context.tsx b/src/features/liveEvents/context.tsx
|
||||
index 3de2534a8..e11955f57 100644
|
||||
--- a/src/features/liveEvents/context.tsx
|
||||
+++ b/src/features/liveEvents/context.tsx
|
||||
@@ -24,6 +24,7 @@ export const DEFAULT_LIVE_EVENTS = {
|
||||
|
||||
async function fetchLiveEvents(): Promise<LiveEventsWorkerResponse | null> {
|
||||
try {
|
||||
+ if (!LIVE_EVENTS_URL) return null
|
||||
const res = await fetch(`${LIVE_EVENTS_URL}/config`)
|
||||
if (!res.ok) return null
|
||||
const data = await res.json()
|
||||
diff --git a/src/geolocation/const.ts b/src/geolocation/const.ts
|
||||
index 653e829ba..4992cc870 100644
|
||||
--- a/src/geolocation/const.ts
|
||||
+++ b/src/geolocation/const.ts
|
||||
@@ -1,7 +1,9 @@
|
||||
import {GEOLOCATION_URL} from '#/env'
|
||||
import {type Geolocation} from '#/geolocation/types'
|
||||
|
||||
-export const GEOLOCATION_SERVICE_URL = `${GEOLOCATION_URL}/geolocation`
|
||||
+export const GEOLOCATION_SERVICE_URL = GEOLOCATION_URL
|
||||
+ ? `${GEOLOCATION_URL}/geolocation`
|
||||
+ : null
|
||||
|
||||
/**
|
||||
* Default geolocation config.
|
||||
diff --git a/src/geolocation/service.ts b/src/geolocation/service.ts
|
||||
index 2d9285b67..c7c3d02c0 100644
|
||||
--- a/src/geolocation/service.ts
|
||||
+++ b/src/geolocation/service.ts
|
||||
@@ -26,9 +26,10 @@ const onGeolocationServiceResponseUpdate = (
|
||||
}
|
||||
|
||||
async function fetchGeolocationServiceData(
|
||||
- url: string,
|
||||
+ url: string | null,
|
||||
): Promise<Geolocation | undefined> {
|
||||
if (debug.enabled) return debug.resolve(debug.geolocation)
|
||||
+ if (!url) throw new Error('geolocation service disabled')
|
||||
const res = await fetch(url)
|
||||
if (!res.ok) {
|
||||
throw new Error(`fetchGeolocationServiceData failed ${res.status}`)
|
||||
diff --git a/src/state/appConfig.tsx b/src/state/appConfig.tsx
|
||||
index 67b0e553e..9eacf7ead 100644
|
||||
--- a/src/state/appConfig.tsx
|
||||
+++ b/src/state/appConfig.tsx
|
||||
@@ -30,6 +30,7 @@ let fetchAppConfigPromise: Promise<AppConfigResponse> | undefined
|
||||
|
||||
async function fetchAppConfig(): Promise<AppConfigResponse | null> {
|
||||
try {
|
||||
+ if (!APP_CONFIG_URL) return null
|
||||
if (!fetchAppConfigPromise) {
|
||||
fetchAppConfigPromise = (async () => {
|
||||
const r = await fetch(`${APP_CONFIG_URL}/config`)
|
||||
@@ -1,62 +0,0 @@
|
||||
--- a/src/state/session/agent.ts
|
||||
+++ b/src/state/session/agent.ts
|
||||
@@ -43,12 +43,18 @@
|
||||
|
||||
export type ProxyHeaderValue = `${Did}#${AtprotoServiceType}`
|
||||
|
||||
+// Default Bluesky proxy DID for non-self-hosted accounts (bsky.social etc.)
|
||||
+const DEFAULT_BSKY_PROXY: ProxyHeaderValue = 'did:web:api.bsky.app#bsky_appview'
|
||||
+
|
||||
+function shouldUseProxy(serviceUrl: string): boolean {
|
||||
+ return !serviceUrl.startsWith(BSKY_SERVICE)
|
||||
+}
|
||||
+
|
||||
export function createPublicAgent() {
|
||||
configureModerationForGuest() // Side effect but only relevant for tests
|
||||
|
||||
const agent = new BskyAppAgent({service: PUBLIC_BSKY_SERVICE})
|
||||
- // Disable proxy for self-hosted environments
|
||||
- // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Self-hosted public agent doesn't need proxy
|
||||
return agent
|
||||
}
|
||||
|
||||
@@ -91,8 +97,10 @@
|
||||
// after session is attached
|
||||
const aa = prefetchAgeAssuranceData({agent})
|
||||
|
||||
- // Disable proxy for self-hosted environments
|
||||
- // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Enable proxy only for non-self-hosted accounts (e.g. bsky.social)
|
||||
+ if (shouldUseProxy(storedAccount.service)) {
|
||||
+ agent.configureProxy(DEFAULT_BSKY_PROXY)
|
||||
+ }
|
||||
|
||||
return agent.prepare({
|
||||
resolvers: [gates, moderation, aa],
|
||||
@@ -131,8 +139,10 @@
|
||||
const moderation = configureModerationForAccount(agent, account)
|
||||
const aa = prefetchAgeAssuranceData({agent})
|
||||
|
||||
- // Disable proxy for self-hosted environments
|
||||
- // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Enable proxy only for non-self-hosted accounts (e.g. bsky.social)
|
||||
+ if (shouldUseProxy(service)) {
|
||||
+ agent.configureProxy(DEFAULT_BSKY_PROXY)
|
||||
+ }
|
||||
|
||||
return agent.prepare({
|
||||
resolvers: [gates, moderation, aa],
|
||||
@@ -304,8 +314,10 @@
|
||||
logger.error(e, {message: `session: failed snoozeEmailConfirmationPrompt`})
|
||||
}
|
||||
|
||||
- // Disable proxy for self-hosted environments
|
||||
- // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Enable proxy only for non-self-hosted accounts (e.g. bsky.social)
|
||||
+ if (shouldUseProxy(service)) {
|
||||
+ agent.configureProxy(DEFAULT_BSKY_PROXY)
|
||||
+ }
|
||||
|
||||
return agent.prepare({
|
||||
resolvers: [gates, moderation, aa],
|
||||
@@ -1,310 +0,0 @@
|
||||
import React, {useState} from 'react'
|
||||
import {
|
||||
View,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Pressable,
|
||||
Image,
|
||||
} from 'react-native'
|
||||
import * as Clipboard from 'expo-clipboard'
|
||||
import * as WebBrowser from 'expo-web-browser'
|
||||
import {Trans} from '@lingui/macro'
|
||||
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useSetTitle} from '#/lib/hooks/useSetTitle'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
|
||||
const APP_VERSION = '1.111.0'
|
||||
const APP_NAME = 'Aiat'
|
||||
const BITCOIN_ADDRESS = '3BqHXxraZyBapyNpJmniJDh9zqzuB8aoRr'
|
||||
|
||||
export function AppInfoScreen() {
|
||||
useSetTitle('App Info')
|
||||
const t = useTheme()
|
||||
const [copied, setCopied] = useState(false)
|
||||
|
||||
const copyToClipboard = async (text: string) => {
|
||||
try {
|
||||
await Clipboard.setStringAsync(text)
|
||||
setCopied(true)
|
||||
setTimeout(() => setCopied(false), 2000)
|
||||
} catch (e) {
|
||||
console.log('Clipboard not available')
|
||||
}
|
||||
}
|
||||
|
||||
const openUrl = (url: string) => {
|
||||
WebBrowser.openBrowserAsync(url)
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout.Screen>
|
||||
<Layout.Header.Outer>
|
||||
<Layout.Header.BackButton />
|
||||
<Layout.Header.Content>
|
||||
<Layout.Header.TitleText>
|
||||
<Trans>App Info</Trans>
|
||||
</Layout.Header.TitleText>
|
||||
</Layout.Header.Content>
|
||||
<Layout.Header.Slot />
|
||||
</Layout.Header.Outer>
|
||||
<Layout.Content>
|
||||
<ScrollView
|
||||
style={[a.flex_1]}
|
||||
contentContainerStyle={[a.p_lg, a.pt_xl, a.pb_5xl]}>
|
||||
{/* App Header */}
|
||||
<View style={styles.appHeader}>
|
||||
<View style={[styles.appIconContainer, t.atoms.bg_contrast_25]}>
|
||||
<Image
|
||||
source={require('../../../assets/logo.png')}
|
||||
style={styles.appIcon}
|
||||
resizeMode="cover"
|
||||
/>
|
||||
</View>
|
||||
<Text style={[styles.appName, t.atoms.text]}>
|
||||
{APP_NAME}
|
||||
</Text>
|
||||
<Text style={[styles.appVersion, t.atoms.text_contrast_medium]}>
|
||||
v{APP_VERSION}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Description Section */}
|
||||
<View style={[styles.section, t.atoms.bg_contrast_25]}>
|
||||
<Text style={[styles.description, t.atoms.text]}>
|
||||
{APP_NAME} is a social networking application based on AT Protocol.
|
||||
Connect with your community on syu.is.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* App Information Section */}
|
||||
<View style={[styles.section, t.atoms.bg_contrast_25]}>
|
||||
<Text style={[styles.sectionTitle, t.atoms.text_contrast_medium]}>
|
||||
App Information
|
||||
</Text>
|
||||
<View style={styles.infoGrid}>
|
||||
<View style={[styles.infoItem, t.atoms.bg_contrast_50]}>
|
||||
<Text style={[styles.infoLabel, t.atoms.text_contrast_medium]}>
|
||||
Version
|
||||
</Text>
|
||||
<Text style={[styles.infoValue, t.atoms.text]}>
|
||||
{APP_VERSION}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[styles.infoItem, t.atoms.bg_contrast_50]}>
|
||||
<Text style={[styles.infoLabel, t.atoms.text_contrast_medium]}>
|
||||
Category
|
||||
</Text>
|
||||
<Text style={[styles.infoValue, t.atoms.text]}>
|
||||
Social
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[styles.infoItem, t.atoms.bg_contrast_50]}>
|
||||
<Text style={[styles.infoLabel, t.atoms.text_contrast_medium]}>
|
||||
Supported OS
|
||||
</Text>
|
||||
<Text style={[styles.infoValue, t.atoms.text]}>
|
||||
iOS 26.0+
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[styles.infoItem, t.atoms.bg_contrast_50]}>
|
||||
<Text style={[styles.infoLabel, t.atoms.text_contrast_medium]}>
|
||||
Price
|
||||
</Text>
|
||||
<Text style={[styles.infoValue, t.atoms.text]}>
|
||||
Free
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Developer Section */}
|
||||
<View style={[styles.section, t.atoms.bg_contrast_25]}>
|
||||
<Text style={[styles.sectionTitle, t.atoms.text_contrast_medium]}>
|
||||
Developer
|
||||
</Text>
|
||||
<View style={styles.developerCard}>
|
||||
<Text style={[styles.developerName, t.atoms.text]}>syui</Text>
|
||||
</View>
|
||||
|
||||
<Pressable
|
||||
onPress={() => openUrl('https://git.syui.ai/syui')}
|
||||
style={[styles.linkRow, t.atoms.border_contrast_low]}>
|
||||
<Text style={[styles.linkIcon, t.atoms.text_contrast_medium]}>
|
||||
Git
|
||||
</Text>
|
||||
<Text style={[styles.linkValue, {color: '#0084ff'}]}>
|
||||
git.syui.ai/syui
|
||||
</Text>
|
||||
<Text style={[styles.linkArrow, t.atoms.text_contrast_low]}>→</Text>
|
||||
</Pressable>
|
||||
|
||||
<Pressable
|
||||
onPress={() => openUrl('https://syu.is/syui')}
|
||||
style={[styles.linkRow, t.atoms.border_contrast_low]}>
|
||||
<Text style={[styles.linkIcon, t.atoms.text_contrast_medium]}>
|
||||
ATProto
|
||||
</Text>
|
||||
<Text style={[styles.linkValue, {color: '#0084ff'}]}>
|
||||
syu.is/syui
|
||||
</Text>
|
||||
<Text style={[styles.linkArrow, t.atoms.text_contrast_low]}>→</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
{/* Bitcoin Section */}
|
||||
<View style={[styles.section, t.atoms.bg_contrast_25]}>
|
||||
<Text style={[styles.sectionTitle, t.atoms.text_contrast_medium]}>
|
||||
Bitcoin
|
||||
</Text>
|
||||
<Pressable
|
||||
onPress={() => copyToClipboard(BITCOIN_ADDRESS)}
|
||||
style={styles.bitcoinRow}>
|
||||
<Text style={styles.bitcoinLabel}>₿</Text>
|
||||
<Text style={[styles.bitcoinAddress, t.atoms.text_contrast_medium]}>
|
||||
{BITCOIN_ADDRESS}
|
||||
</Text>
|
||||
<Text style={[styles.copyHint, copied && styles.copiedHint]}>
|
||||
{copied ? 'copied!' : 'copy'}
|
||||
</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
{/* Copyright */}
|
||||
<View style={styles.copyright}>
|
||||
<Text style={[styles.copyrightText, t.atoms.text_contrast_low]}>
|
||||
© syui
|
||||
</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</Layout.Content>
|
||||
</Layout.Screen>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
appHeader: {
|
||||
alignItems: 'center',
|
||||
marginBottom: 24,
|
||||
},
|
||||
appIconContainer: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderRadius: 18,
|
||||
overflow: 'hidden',
|
||||
marginBottom: 12,
|
||||
},
|
||||
appIcon: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
appName: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 4,
|
||||
},
|
||||
appVersion: {
|
||||
fontSize: 14,
|
||||
},
|
||||
section: {
|
||||
marginBottom: 16,
|
||||
borderRadius: 16,
|
||||
padding: 16,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 13,
|
||||
fontWeight: '600',
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 0.5,
|
||||
marginBottom: 12,
|
||||
},
|
||||
description: {
|
||||
fontSize: 15,
|
||||
lineHeight: 22,
|
||||
},
|
||||
infoGrid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 8,
|
||||
},
|
||||
infoItem: {
|
||||
flex: 1,
|
||||
minWidth: '45%',
|
||||
alignItems: 'center',
|
||||
borderRadius: 12,
|
||||
padding: 12,
|
||||
},
|
||||
infoLabel: {
|
||||
fontSize: 11,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 0.5,
|
||||
marginBottom: 4,
|
||||
},
|
||||
infoValue: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
},
|
||||
developerCard: {
|
||||
marginBottom: 12,
|
||||
},
|
||||
developerName: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
},
|
||||
linkRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 12,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
linkIcon: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
width: 70,
|
||||
},
|
||||
linkValue: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
},
|
||||
linkArrow: {
|
||||
fontSize: 16,
|
||||
},
|
||||
bitcoinRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(247, 147, 26, 0.08)',
|
||||
borderRadius: 12,
|
||||
padding: 14,
|
||||
gap: 10,
|
||||
},
|
||||
bitcoinLabel: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: '#f7931a',
|
||||
},
|
||||
bitcoinAddress: {
|
||||
flex: 1,
|
||||
fontSize: 11,
|
||||
fontFamily: 'monospace',
|
||||
},
|
||||
copyHint: {
|
||||
fontSize: 12,
|
||||
color: '#999999',
|
||||
minWidth: 50,
|
||||
textAlign: 'right',
|
||||
},
|
||||
copiedHint: {
|
||||
color: '#4CAF50',
|
||||
fontWeight: '600',
|
||||
},
|
||||
copyright: {
|
||||
alignItems: 'center',
|
||||
marginTop: 20,
|
||||
marginBottom: 20,
|
||||
},
|
||||
copyrightText: {
|
||||
fontSize: 12,
|
||||
},
|
||||
})
|
||||