feat(ios): polish onboarding and native sign-in flow (#15217)

## Summary
- Reworks the iOS onboarding, native sign-in, and paywall flow so
first-install and cold-start entry stay native, adaptive, and aligned
with the current login/subscription gates.
- Removes onboarding swipe paging, refines onboarding/paywall layout
behavior, and keeps AI/paywall entry behavior consistent for logged-in
and subscribed users.
- Adds the new mobile all-docs empty states with localized copy and
dialog entry points, and closes the remaining review follow-ups by
removing the onboarding plan artifact and dropping the iOS AI
subscription bypass.

## Test plan
- Built the iOS app for simulator with `xcodebuild -workspace
App.xcworkspace -scheme App -configuration Debug -sdk iphonesimulator
-destination 'generic/platform=iOS Simulator' ARCHS=arm64
ONLY_ACTIVE_ARCH=YES CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO
build` during the native onboarding/sign-in flow work.
- Let the repo pre-commit hooks run on the latest follow-up commit
(`prettier` + `eslint --fix`).
- Checked diagnostics for the edited TS/TSX files after the review
follow-up changes.
- Manually iterated on onboarding/native sign-in/paywall UI states in
simulator during implementation.

---------

Co-authored-by: DarkSky <darksky2048@gmail.com>
This commit is contained in:
keepClamDown
2026-08-21 08:12:27 +08:00
committed by GitHub
parent c57004ea2c
commit 73e2d10973
130 changed files with 6478 additions and 2268 deletions
@@ -12,12 +12,16 @@ import {
import type { ButtonProps } from '../button';
import { Button } from '../button';
import Input, { type InputProps } from '../input';
import { ModalConfigContext } from './context';
import type { ModalProps } from './modal';
import { Modal } from './modal';
import { desktopStyles, mobileStyles } from './prompt-modal.css';
const styles = BUILD_CONFIG.isMobileEdition ? mobileStyles : desktopStyles;
const getCssLength = (value: string | number) =>
typeof value === 'number' ? `${value}px` : value;
export interface PromptModalProps extends ModalProps {
confirmButtonOptions?: Omit<ButtonProps, 'children'>;
onConfirm?: ((text: string) => void) | ((text: string) => Promise<void>);
@@ -57,8 +61,10 @@ export const PromptModal = ({
autoFocusConfirm = true,
headerClassName,
descriptionClassName,
contentOptions,
...props
}: PromptModalProps) => {
const { dynamicKeyboardHeight } = useContext(ModalConfigContext);
const [value, setValue] = useState(defaultValue ?? '');
const onConfirmClick = useCallback(() => {
Promise.resolve(onConfirm?.(value))
@@ -88,8 +94,21 @@ export const PromptModal = ({
<Modal
preserveEditingFocusOnAction={BUILD_CONFIG.isMobileEdition}
contentOptions={{
className: styles.container,
...contentOptions,
className: clsx(styles.container, contentOptions?.className),
style: {
...contentOptions?.style,
...(BUILD_CONFIG.isMobileEdition
? {
maxHeight: dynamicKeyboardHeight
? `calc(100dvh - ${getCssLength(dynamicKeyboardHeight)} - 32px)`
: 'calc(100dvh - 32px)',
overflowY: 'auto',
}
: null),
},
onPointerDownOutside: e => {
contentOptions?.onPointerDownOutside?.(e);
e.stopPropagation();
onCancel?.();
},