mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-20 09:09:35 +02:00
A phone-only toolbar Attach button hands the agent a photo or a video with the keyboard down. It owns its own file input, positioned over the button so iOS anchors the picker popover to it; the picked paths land on the prompt as unsent text, so Compose adopts them together with anything already typed and Use terminal keyboard hands a single-line draft back the other way. Videos take a second path on the same route: ?kind=video streams the file to disk under MAX_PASTE_VIDEO_BYTES (1GB, env CODEMAN_MAX_PASTE_VIDEO_BYTES) instead of buffering it, sniffs the container from the first bytes as they arrive, drains a mislabeled body unwritten and unlinks on any failure. It draws on its own 3/min per-(IP, session) rate bucket beside the image path's 30/min: at 1GB each, 30/min would be 30GB of disk a minute. Without the flag the route is byte-identical to the image-only version, same 50MB cap and same bucket. One client classifier, _promptAttachKind (MIME first, then the name's extension), drives every pick and paste surface: the Attach button, terminal drop, the tile grid's drop, the Compose and paste-dialog pickers and the clipboard handlers. A pick that lands while the tile grid owns the terminal goes to the PTY rather than the parked main-terminal overlay.
125 lines
3.3 KiB
TypeScript
125 lines
3.3 KiB
TypeScript
// CSS Selectors
|
|
export const SELECTORS = {
|
|
// Header
|
|
HEADER: '.header',
|
|
HEADER_BRAND: '.header-brand',
|
|
CASE_SELECT_GROUP: '.case-select-group',
|
|
VERSION_DISPLAY: '.version-display',
|
|
|
|
// Toolbar
|
|
TOOLBAR: '.toolbar',
|
|
TOOLBAR_RIGHT: '.toolbar-right',
|
|
SETTINGS_MOBILE: '.btn-settings-mobile',
|
|
CASE_MOBILE: '.btn-case-mobile',
|
|
ATTACH_MOBILE: '.btn-attach-mobile',
|
|
// The desktop rule hides the WRAPPER, and assertHidden reads an element's own
|
|
// computed style (an ancestor's display:none is invisible to it).
|
|
ATTACH_MOBILE_WRAP: '.btn-attach-mobile-wrap',
|
|
|
|
// Tabs
|
|
TABS_CONTAINER: '.session-tabs',
|
|
TAB: '.session-tab',
|
|
TAB_ACTIVE: '.session-tab.active',
|
|
TAB_CLOSE: '.tab-close',
|
|
TAB_COUNT_GROUP: '.tab-count-group',
|
|
TAB_NAME: '.tab-name',
|
|
|
|
// Keyboard
|
|
KEYBOARD_ACCESSORY: '.keyboard-accessory-bar',
|
|
KEYBOARD_ACCESSORY_VISIBLE: '.keyboard-accessory-bar.visible',
|
|
|
|
// Terminal
|
|
TERMINAL_CONTAINER: '.terminal-container',
|
|
MAIN: '.main',
|
|
|
|
// Subagent windows
|
|
SUBAGENT_WINDOW: '.subagent-window',
|
|
SUBAGENT_HEADER: '.subagent-header',
|
|
SUBAGENT_BADGE: '.subagent-badge',
|
|
|
|
// Settings
|
|
SETTINGS_MODAL: '#appSettingsModal',
|
|
SETTINGS_MODAL_CONTENT: '.modal-content',
|
|
SETTINGS_MODAL_BODY: '.modal-body',
|
|
SETTINGS_MODAL_TABS: '.modal-tabs',
|
|
|
|
// Modals general
|
|
MODAL: '.modal',
|
|
MODAL_CONTENT: '.modal-content',
|
|
} as const;
|
|
|
|
// Device breakpoints (match app.js MobileDetection)
|
|
export const BREAKPOINTS = {
|
|
PHONE_MAX: 600,
|
|
TABLET_MAX: 768,
|
|
} as const;
|
|
|
|
// Keyboard constants (match app.js KeyboardHandler)
|
|
export const KEYBOARD = {
|
|
SHOW_THRESHOLD: 150, // heightDiff > 150px triggers show
|
|
HIDE_THRESHOLD: 100, // heightDiff < 100px triggers hide
|
|
TYPICAL_IOS_HEIGHT: 336,
|
|
FOCUSIN_DELAY: 400,
|
|
ANIMATION_DELAY: 150,
|
|
RESIZE_DELAY_SHOW: 150,
|
|
RESIZE_DELAY_HIDE: 100,
|
|
ACCESSORY_BAR_HEIGHT: 44,
|
|
TOOLBAR_HEIGHT: 40,
|
|
CONFIRM_TIMEOUT: 2000,
|
|
} as const;
|
|
|
|
// Swipe constants (match app.js SwipeHandler)
|
|
export const SWIPE = {
|
|
MIN_DISTANCE: 80,
|
|
MAX_TIME: 300,
|
|
MAX_VERTICAL_DRIFT: 100,
|
|
} as const;
|
|
|
|
// Subagent window constants
|
|
export const SUBAGENT = {
|
|
MOBILE_CARD_HEIGHT: 110,
|
|
MOBILE_CARD_GAP: 4,
|
|
MOBILE_CARD_STRIDE: 114, // height + gap
|
|
TOOLBAR_OFFSET: 40,
|
|
DEFAULT_HEADER_HEIGHT: 36,
|
|
} as const;
|
|
|
|
// Visual regression
|
|
export const VISUAL = {
|
|
DEFAULT_THRESHOLD: 0.1,
|
|
MAX_DIFF_PERCENT: 0.5,
|
|
SNAPSHOT_DIR: 'test/mobile/snapshots',
|
|
} as const;
|
|
|
|
// Visual regression breakpoints (width values for screenshot comparison)
|
|
export const VISUAL_BREAKPOINTS = [320, 375, 390, 393, 430, 440, 600, 768, 834, 1024] as const;
|
|
|
|
// Wait times
|
|
export const WAIT = {
|
|
DOM_CONTENT_LOADED: 'domcontentloaded' as const,
|
|
PAGE_SETTLE: 3000,
|
|
KEYBOARD_ANIMATION: 200,
|
|
SSE_CONNECT: 1000,
|
|
};
|
|
|
|
// Touch target minimum (WCAG 2.5.5 / Apple HIG)
|
|
export const MIN_TOUCH_TARGET = 44;
|
|
|
|
// Body CSS classes
|
|
export const BODY_CLASSES = {
|
|
MOBILE: 'device-mobile',
|
|
TABLET: 'device-tablet',
|
|
DESKTOP: 'device-desktop',
|
|
TOUCH: 'touch-device',
|
|
IOS: 'ios-device',
|
|
SAFARI: 'safari-browser',
|
|
KEYBOARD_VISIBLE: 'keyboard-visible',
|
|
} as const;
|
|
|
|
// Settings localStorage keys
|
|
export const STORAGE_KEYS = {
|
|
SETTINGS_MOBILE: 'codeman-app-settings-mobile',
|
|
SETTINGS_DESKTOP: 'codeman-app-settings',
|
|
NOTIFICATION_PREFS_MOBILE: 'codeman-notification-prefs-mobile',
|
|
} as const;
|