Skip to content

Commit 8c682b0

Browse files
Merge upstream develop
2 parents deb791d + 7030026 commit 8c682b0

47 files changed

Lines changed: 22037 additions & 11720 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,10 @@ polycentric-blobs/
4343
# Generated files
4444
docker-compose.live*
4545

46+
# Docusaurus (docs site)
47+
.docusaurus
48+
.cache-loader
49+
docs/build
50+
4651
# Secrets
4752
.env

.gitlab-ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ include:
55
- local: '.gitlab/ci/build_rn_sdk.yml'
66
- local: '.gitlab/ci/build_services.yml'
77
- local: '.gitlab/ci/build_app.yml'
8+
- local: '.gitlab/ci/build_docs.yml'
9+
- local: '.gitlab/ci/deploy_docs.yml'
810
- local: '.gitlab/ci/deploy_app.yml'
911
- local: '.gitlab/ci/deploy_services.yml'
1012
- local: '.gitlab/ci/deploy_pages.yml'

.gitlab/ci/build_docs.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Build the Docusaurus documentation site in ./docs.
2+
# Deployment lives in deploy_docs.yml.
3+
4+
.docs-workflow:
5+
image: node:24-slim
6+
rules:
7+
- if: $CI_COMMIT_TAG == "docs"
8+
when: always
9+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
10+
changes:
11+
- docs/**/*
12+
- .gitlab/ci/build_docs.yml
13+
- .gitlab/ci/deploy_docs.yml
14+
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
15+
when: never
16+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
17+
changes:
18+
- docs/**/*
19+
- .gitlab/ci/build_docs.yml
20+
- .gitlab/ci/deploy_docs.yml
21+
22+
.docs-base:
23+
extends: .docs-workflow
24+
before_script:
25+
- npm install -g pnpm@10.19.0
26+
# Only resolve/install the docs package and its dependencies.
27+
- pnpm install --filter=polycentric-docs...
28+
29+
docs-typecheck:
30+
extends: .docs-base
31+
stage: check
32+
script:
33+
- pnpm --filter=polycentric-docs run typecheck
34+
allow_failure: true
35+
36+
docs-build:
37+
extends: .docs-base
38+
stage: build
39+
script:
40+
- pnpm --filter=polycentric-docs run build
41+
artifacts:
42+
paths:
43+
- docs/build
44+
expire_in: 1 week

.gitlab/ci/deploy_docs.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Deploy the Docusaurus documentation site built by build_docs.yml.
2+
# Mirrors the Cloudflare Pages pattern already used in deploy_pages.yml.
3+
#
4+
# Requires the following CI/CD variables to be set (Settings > CI/CD > Variables):
5+
# CLOUDFLARE_API_TOKEN - token with Pages:Edit
6+
# CLOUDFLARE_ACCOUNT_ID - target account
7+
8+
.docs-deploy-workflow:
9+
rules:
10+
- if: $CI_COMMIT_TAG == "docs"
11+
when: always
12+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
13+
changes:
14+
- docs/**/*
15+
- .gitlab/ci/build_docs.yml
16+
- .gitlab/ci/deploy_docs.yml
17+
18+
docs-deploy:
19+
extends: .docs-deploy-workflow
20+
stage: deploy
21+
image: node:24-slim
22+
needs:
23+
- job: docs-build
24+
artifacts: true
25+
before_script:
26+
- npm install -g wrangler
27+
script:
28+
- wrangler pages deploy ./docs/build --project-name=polycentric-docs --branch=production
29+
30+
# Deploy Review Apps on every merge request for the docs.
31+
# We deploy each MR to the branch "mr-$CI_MERGE_REQUEST_IID" of the Cloudflare project name
32+
# "polycentric-docs-cs8" (domain name auto-assigned by Cloudflare), meaning we can hand Gitlab the
33+
# URL "<mr-$CI_MERGE_REQUEST_IID>.polycentric-docs-cs8.pages.dev".
34+
35+
.docs-review-rules:
36+
rules:
37+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
38+
changes:
39+
- docs/**/*
40+
- .gitlab/ci/build_docs.yml
41+
- .gitlab/ci/deploy_docs.yml
42+
43+
docs-review:
44+
extends: .docs-review-rules
45+
stage: deploy
46+
image: node:24-slim
47+
needs:
48+
- job: docs-build
49+
artifacts: true
50+
environment:
51+
name: review/docs/$CI_MERGE_REQUEST_IID
52+
url: https://mr-$CI_MERGE_REQUEST_IID.polycentric-docs-cs8.pages.dev
53+
on_stop: docs-review-stop
54+
auto_stop_in: 1 week
55+
before_script:
56+
- npm install -g wrangler
57+
script:
58+
- wrangler pages deploy ./docs/build --project-name=polycentric-docs --branch="mr-$CI_MERGE_REQUEST_IID"
59+
60+
docs-review-stop:
61+
stage: deploy
62+
image: node:24-slim
63+
rules:
64+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
65+
changes:
66+
- docs/**/*
67+
- .gitlab/ci/build_docs.yml
68+
- .gitlab/ci/deploy_docs.yml
69+
# Should only trigger when `docs-review` triggers it (when stopping)
70+
when: manual
71+
variables:
72+
CF_PAGES_PROJECT: polycentric-docs
73+
CF_PAGES_BRANCH: mr-$CI_MERGE_REQUEST_IID
74+
# Needs a git checkout for the cleanup script below
75+
GIT_STRATEGY: none
76+
environment:
77+
name: review/docs/$CI_MERGE_REQUEST_IID
78+
action: stop
79+
script:
80+
- node .gitlab/ci/scripts/cf-pages-delete-branch.mjs
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Attempt a teardown of all Cloudflare Pages preview deployments for a
2+
// single branch. Used by the docs review-app stop job (deploy_docs.yml) when a
3+
// merge request is merged/closed or its environment is auto-stopped.
4+
5+
const token = process.env.CLOUDFLARE_API_TOKEN;
6+
const account = process.env.CLOUDFLARE_ACCOUNT_ID;
7+
const project = process.env.CF_PAGES_PROJECT;
8+
const branch = process.env.CF_PAGES_BRANCH;
9+
10+
for (const [name, value] of Object.entries({
11+
CLOUDFLARE_API_TOKEN: token,
12+
CLOUDFLARE_ACCOUNT_ID: account,
13+
CF_PAGES_PROJECT: project,
14+
CF_PAGES_BRANCH: branch,
15+
})) {
16+
if (!value) {
17+
console.error(`Missing required env var: ${name}`);
18+
process.exit(1);
19+
}
20+
}
21+
22+
const base = `https://api.cloudflare.com/client/v4/accounts/${account}/pages/projects/${project}`;
23+
const headers = { Authorization: `Bearer ${token}` };
24+
25+
async function cf(path, init) {
26+
const res = await fetch(`${base}${path}`, {
27+
...init,
28+
headers: { ...headers, ...init?.headers },
29+
});
30+
const body = await res.json().catch(() => ({}));
31+
if (!res.ok || body.success === false) {
32+
throw new Error(
33+
`Cloudflare API ${res.status}: ${JSON.stringify(body.errors ?? body)}`,
34+
);
35+
}
36+
return body;
37+
}
38+
39+
// There may be multiple deployments per branch. Wrangler has no function to delete all
40+
// deployments, so we delete one-by-one.
41+
42+
// Deployments are paginated; walk pages until we stop getting results.
43+
async function* deployments() {
44+
for (let page = 1; ; page++) {
45+
const { result } = await cf(`/deployments?per_page=25&page=${page}`);
46+
if (!result || result.length === 0) return;
47+
yield* result;
48+
if (result.length < 25) return;
49+
}
50+
}
51+
52+
let deleted = 0;
53+
let failed = 0;
54+
for await (const d of deployments()) {
55+
const depBranch = d.deployment_trigger?.metadata?.branch;
56+
if (depBranch !== branch) continue;
57+
try {
58+
// force=true also removes deployments that are currently "live" for an alias.
59+
await cf(`/deployments/${d.id}?force=true`, { method: 'DELETE' });
60+
deleted++;
61+
console.log(`Deleted deployment ${d.id} (branch ${branch})`);
62+
} catch (err) {
63+
failed++;
64+
console.error(`Failed to delete deployment ${d.id}: ${err.message}`);
65+
}
66+
}
67+
68+
console.log(`Done: ${deleted} deleted, ${failed} failed for branch ${branch}.`);
69+
process.exit(0);

apps/polycentric/app/(tabs)/_layout.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useTheme } from '@/src/common/theme';
2-
import { isWeb } from '@/src/common/util/platform';
2+
import { isIOS, isWeb } from '@/src/common/util/platform';
33
import { Slot } from 'expo-router';
44
import { NativeTabs } from 'expo-router/unstable-native-tabs';
55

@@ -11,6 +11,7 @@ export default function TabsLayout() {
1111

1212
return (
1313
<NativeTabs
14+
backBehavior="history"
1415
minimizeBehavior="onScrollDown"
1516
backgroundColor={theme.palette.neutral_0}
1617
iconColor={theme.palette.neutral_900}
@@ -21,7 +22,7 @@ export default function TabsLayout() {
2122
>
2223
<NativeTabs.Trigger name="feed">
2324
<NativeTabs.Trigger.Label>Feed</NativeTabs.Trigger.Label>
24-
<NativeTabs.Trigger.Icon sf="house.fill" md="home" />
25+
<NativeTabs.Trigger.Icon sf="house" md="home" />
2526
</NativeTabs.Trigger>
2627

2728
<NativeTabs.Trigger name="explore">
@@ -31,8 +32,23 @@ export default function TabsLayout() {
3132

3233
<NativeTabs.Trigger name="activity">
3334
<NativeTabs.Trigger.Label>Activity</NativeTabs.Trigger.Label>
34-
<NativeTabs.Trigger.Icon sf="bell.fill" md="notifications" />
35+
<NativeTabs.Trigger.Icon sf="bell" md="notifications" />
3536
</NativeTabs.Trigger>
37+
38+
<NativeTabs.Trigger name="trust">
39+
<NativeTabs.Trigger.Label>Trust</NativeTabs.Trigger.Label>
40+
<NativeTabs.Trigger.Icon sf="checkmark.seal" md="key" />
41+
</NativeTabs.Trigger>
42+
43+
{isIOS ? (
44+
<NativeTabs.Trigger name="compose" role="search">
45+
<NativeTabs.Trigger.Label hidden>Compose</NativeTabs.Trigger.Label>
46+
<NativeTabs.Trigger.Icon
47+
sf={{ default: 'square.and.pencil', selected: 'square.and.pencil' }}
48+
md="edit"
49+
/>
50+
</NativeTabs.Trigger>
51+
) : null}
3652
</NativeTabs>
3753
);
3854
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { default } from '@/src/features/composer/ComposeScreen';
1+
export { default } from '@/src/features/composer/ComposeTabScreen';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from '@/src/features/trust/TrustScreen';

apps/polycentric/src/common/components/composites/Fab.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,18 @@ export function Fab({ onPress, icon, title = '' }: FabProps) {
2121
const shadow =
2222
Platform.OS === 'web'
2323
? {
24-
boxShadow: `0 6px 16px ${withHexOpacity(
25-
theme.palette.primary_900,
26-
isLight ? '28' : '40',
27-
)}`,
28-
}
24+
boxShadow: `0 6px 16px ${withHexOpacity(
25+
theme.palette.primary_900,
26+
isLight ? '28' : '40',
27+
)}`,
28+
}
2929
: {
30-
shadowColor: theme.palette.primary_900,
31-
shadowOpacity: isLight ? 0.16 : 0.26,
32-
shadowRadius: isLight ? 14 : 10,
33-
shadowOffset: { width: 0, height: isLight ? 3 : 4 },
34-
elevation: isLight ? 4 : 6,
35-
};
30+
shadowColor: theme.palette.primary_900,
31+
shadowOpacity: isLight ? 0.16 : 0.26,
32+
shadowRadius: isLight ? 14 : 10,
33+
shadowOffset: { width: 0, height: isLight ? 3 : 4 },
34+
elevation: isLight ? 4 : 6,
35+
};
3636

3737
return (
3838
<View style={[Atoms.absolute, { bottom: 0, right: 0 }, Atoms.p_lg]}>

apps/polycentric/src/common/components/layout/Layout.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Atoms, Breakpoints, typography, useTheme } from '@/src/common/theme';
2-
import { isWeb } from '@/src/common/util/platform';
2+
import { isIOS, isWeb } from '@/src/common/util/platform';
33
import { Image } from 'expo-image';
44
import { ExternalPathString, Link } from 'expo-router';
55
import {
@@ -80,6 +80,7 @@ type PrimaryColumnProps = {
8080
function PrimaryColumn({ children }: PrimaryColumnProps) {
8181
const { theme } = useTheme();
8282
const { height: windowHeight } = useWindowDimensions();
83+
const insets = useSafeAreaInsets();
8384

8485
return (
8586
<View

0 commit comments

Comments
 (0)