From b6399985e720397da50b4e94583ec6e3dd20c546 Mon Sep 17 00:00:00 2001 From: Amit Raikwar Date: Tue, 14 Jul 2026 03:39:59 +0530 Subject: [PATCH 1/2] feat(MAC-6): settings overhaul, calendar slice & ci/cd modernisation - Redesigned Settings app with 20+ macOS-faithful preference panels (General, Wi-Fi, Bluetooth, Network, Notifications, Sound, Focus, Screen Time, Appearance, Accessibility, Siri, Privacy & Security, Desktop & Dock, Displays, Battery, Lock Screen, Touch ID, Users & Groups, Internet Accounts, Wallet, iCloud, Game Centre, Wallpaper). - Added Calendar app slice and selector to appStore for consistent window state management. - Introduced data/Options.ts context menu data files for all simulated apps (Bin, Calendar, Chrome, Finder, Github, Notes, Settings, Spotify, Terminal, VsCode) driven by a shared src/types/menu.ts type. - Refactored appStore, settingsStore, and processStore slices and types to align with new Options data pattern and window state extensions. - Replaced legacy CI/CD workflows (main.yml, deploy.yaml, release.yml) with purpose-built build-web.yml and ci-web.yml for cleaner separation of build and CI concerns. - Simplified DateTimeDrawer by removing WorldClockComponent; revamped Wifi top-bar component; applied minor UI fixes to Window, Launchpad, Lock, and Power screens. - Addresses requirements specified in MAC-6. --- .github/workflows/build-web.yml | 119 + .github/workflows/ci-web.yml | 52 + .github/workflows/deploy.yaml | 28 - .github/workflows/main.yml | 30 - .github/workflows/release.yml | 39 - jest.config.js | 4 +- src/assets/icons/SettingsIcons.tsx | 677 + src/assets/icons/index.ts | 1 + src/components/Modal/Modal.tsx | 34 +- .../Modal/Modals/Search/SearchModal.tsx | 3 +- .../__snapshots__/SearchModal.test.tsx.snap | 4 +- .../__snapshots__/Modal.test.tsx.snap | 48 +- src/components/Window/Window.tsx | 181 +- src/components/Window/WindowControl.tsx | 185 +- .../Window/__tests__/WindowControl.test.tsx | 4 +- .../Window/__tests__/Windows.test.tsx | 2 +- .../__snapshots__/WindowControl.test.tsx.snap | 252 +- .../__snapshots__/Windows.test.tsx.snap | 686 +- src/localization/locales/en/main.json | 2 +- src/providers/draggable/DraggableProvider.tsx | 42 +- src/providers/draggable/types.ts | 2 + .../RouterProvider.test.tsx.snap | 3585 ++- .../LazyHomeScreen.test.tsx.snap | 3543 ++- .../program/__tests__/LazyBinScreen.test.tsx | 3 +- .../__tests__/LazyFinderScreen.test.tsx | 1 + .../__tests__/LazySettingsScreen.test.tsx | 3 +- .../__tests__/LazyTerminalScreen.test.tsx | 3 +- .../__snapshots__/LazyBinScreen.test.tsx.snap | 37 +- .../LazyFinderScreen.test.tsx.snap | 24 +- .../LazySettingsScreen.test.tsx.snap | 1482 +- .../LazyTerminalScreen.test.tsx.snap | 30 +- .../LazyPowerScreen.test.tsx.snap | 3 + .../private/Home/BottomBar/BottomBar.tsx | 12 +- .../BottomBar/__tests__/BottomBar.test.tsx | 25 +- .../__snapshots__/BottomBar.test.tsx.snap | 9 + src/screens/private/Home/Home.tsx | 21 +- .../private/Home/Launchpad/Launchpad.tsx | 373 +- .../Launchpad/__tests__/Launchpad.test.tsx | 4 +- .../__snapshots__/Launchpad.test.tsx.snap | 1712 +- .../private/Home/Launchpad/constants.ts | 62 + .../Home/TopBar/LeftSideComponents/Apple.tsx | 27 +- .../TopAppBarAppMenu/TopAppBarAppMenu.tsx | 56 +- .../__tests__/TopAppBarAppMenu.test.tsx | 130 - .../TopAppBarAppMenu.test.tsx.snap | 13707 --------- .../TopAppBarAppMenu/constants.ts | 219 +- .../TopAppBarAppMenu/types.ts | 19 +- .../TopBar/RightSideComponents/Battery.tsx | 39 +- .../DateTimeDrawer/DateTimeDrawer.tsx | 513 +- .../DateTimeDrawer/WorldClockComponent.tsx | 37 - .../__tests__/WorldClockComponent.test.tsx | 10 - .../DateTimeDrawer.test.tsx.snap | 940 +- .../WorldClockComponent.test.tsx.snap | 38 - .../TopBar/RightSideComponents/Monitor.tsx | 18 +- .../TopBar/RightSideComponents/Settings.tsx | 469 +- .../Home/TopBar/RightSideComponents/User.tsx | 18 +- .../Home/TopBar/RightSideComponents/Wifi.tsx | 108 +- .../__tests__/Wifi.test.tsx | 16 +- .../__snapshots__/Battery.test.tsx.snap | 24 +- .../__snapshots__/Settings.test.tsx.snap | 890 +- .../__snapshots__/Wifi.test.tsx.snap | 591 +- .../__snapshots__/TopBar.test.tsx.snap | 3504 ++- .../__snapshots__/Home.test.tsx.snap | 24810 ++++++++++++---- .../__tests__/ProgramButton.test.tsx | 7 +- .../__snapshots__/ProgramButton.test.tsx.snap | 2 + src/screens/private/program/Bin/Bin.tsx | 29 +- .../__tests__/__snapshots__/Bin.test.tsx.snap | 37 +- .../private/program/Bin/data/Options.ts | 34 + .../private/program/Calendar/Calendar.tsx | 62 +- .../private/program/Calendar/data/Options.ts | 34 + .../private/program/Chrome/data/Options.ts | 39 + src/screens/private/program/Finder/Finder.tsx | 24 +- .../__snapshots__/Finder.test.tsx.snap | 24 +- .../private/program/Finder/data/Options.ts | 530 + .../private/program/Github/data/Options.ts | 34 + .../private/program/Notes/data/Options.ts | 879 + .../private/program/Settings/Settings.tsx | 664 +- .../Settings/__tests__/Settings.test.tsx | 44 +- .../__snapshots__/Settings.test.tsx.snap | 1482 +- .../components/AccessibilitySettings.tsx | 54 + .../components/AppearanceSettings.tsx | 97 + .../Settings/components/BatterySettings.tsx | 57 + .../Settings/components/BluetoothSettings.tsx | 73 + .../components/DesktopDockSettings.tsx | 58 + .../Settings/components/DisplaysSettings.tsx | 125 + .../Settings/components/FocusSettings.tsx | 83 + .../components/GameCenterSettings.tsx | 64 + .../Settings/components/GeneralSettings.tsx | 205 + .../components/GeneralSubPageSettings.tsx | 302 + .../Settings/components/ICloudSettings.tsx | 90 + .../components/InternetAccountsSettings.tsx | 67 + .../components/LockScreenSettings.tsx | 118 + .../Settings/components/NetworkSettings.tsx | 80 + .../components/NotificationsSettings.tsx | 97 + .../components/PrivacySecuritySettings.tsx | 141 + .../components/ScreenTimeSettings.tsx | 134 + .../Settings/components/SiriSettings.tsx | 72 + .../Settings/components/SoundSettings.tsx | 58 + .../components/TouchIdPasswordSettings.tsx | 85 + .../components/UsersGroupsSettings.tsx | 69 + .../Settings/components/WalletSettings.tsx | 108 + .../Settings/components/WallpaperSettings.tsx | 83 + .../Settings/components/WifiSettings.tsx | 91 + .../program/Settings/components/index.ts | 24 + .../private/program/Settings/const.tsx | 61 + .../private/program/Settings/data/Options.ts | 29 + .../private/program/Spotify/data/Options.ts | 39 + .../private/program/Terminal/Terminal.tsx | 50 +- .../__snapshots__/Terminal.test.tsx.snap | 30 +- .../private/program/Terminal/data/Options.ts | 39 + src/screens/private/program/VsCode/VsCode.tsx | 8 +- .../private/program/VsCode/data/Options.ts | 789 + .../__snapshots__/Lock.test.tsx.snap | 44 +- .../public/Lock/component/UserLogin.tsx | 28 +- .../__snapshots__/UserLogin.test.tsx.snap | 220 +- .../__snapshots__/Power.test.tsx.snap | 3 + .../public/Power/component/FloatingButton.tsx | 48 +- .../FloatingButton.test.tsx.snap | 3 + src/store/appStore/appStore/appStore.ts | 3 + src/store/appStore/appStore/types.ts | 2 + .../appStore/selector/Bin/Bin.selector.ts | 6 +- .../Bin/__tests__/Bin.selector.test.ts | 4 +- .../selector/Calendar/Calendar.selector.ts | 10 + src/store/appStore/selector/Calendar/index.ts | 1 + .../selector/Finder/Finder.selector.ts | 5 +- .../Finder/__tests__/Finder.selector.test.ts | 3 +- .../selector/Terminal/Terminal.selector.ts | 6 +- .../__tests__/Terminal.selector.test.ts | 4 +- .../selector/VsCode/VsCode.selector.ts | 5 +- .../VsCode/__tests__/VsCode.selector.test.ts | 3 +- src/store/appStore/selector/index.ts | 1 + src/store/appStore/slice/Bin/Bin.slice.ts | 14 +- .../slice/Bin/__tests__/Bin.slice.test.ts | 4 +- src/store/appStore/slice/Bin/types.ts | 9 +- .../appStore/slice/Calendar/Calendar.slice.ts | 27 + src/store/appStore/slice/Calendar/index.ts | 3 + src/store/appStore/slice/Calendar/types.ts | 18 + .../appStore/slice/Finder/Finder.slice.ts | 9 +- .../Finder/__tests__/Finder.slice.test.ts | 3 +- src/store/appStore/slice/Finder/types.ts | 8 +- .../appStore/slice/Terminal/Terminal.slice.ts | 14 +- .../Terminal/__tests__/Terminal.slice.test.ts | 4 +- src/store/appStore/slice/Terminal/types.ts | 9 +- .../appStore/slice/VsCode/VsCode.slice.ts | 9 +- .../VsCode/__tests__/VsCode.slice.test.ts | 3 +- src/store/appStore/slice/VsCode/types.ts | 8 +- src/store/appStore/slice/index.ts | 1 + .../selector/ActiveApp/ActiveApp.selector.ts | 1 + .../__tests__/ActiveApp.selector.test.ts | 7 +- .../slice/ActiveApp/ActiveApp.slice.ts | 84 +- .../__tests__/ActiveApp.slice.test.ts | 16 +- .../processStore/slice/ActiveApp/constants.ts | 3 +- .../processStore/slice/ActiveApp/types.ts | 10 + .../selector/Battery/Battery.selector.ts | 5 +- .../__tests__/Battery.selector.test.ts | 5 +- .../selector/Bluetooth/Bluetooth.selector.ts | 5 +- .../__tests__/Bluetooth.selector.test.ts | 5 +- .../selector/General/General.selector.ts | 7 +- .../__tests__/General.selector.test.ts | 7 +- .../selector/Sound/Sound.selector.ts | 5 +- .../Sound/__tests__/Sound.selector.test.ts | 5 +- .../selector/Users/Users.selector.ts | 1 + .../__snapshots__/Users.selector.test.ts.snap | 3 +- .../selector/Wifi/Wifi.selector.ts | 5 +- .../Wifi/__tests__/Wifi.selector.test.ts | 5 +- .../slice/Battery/Battery.slice.ts | 8 +- .../Battery/__tests__/Battery.slice.test.ts | 7 +- .../settingsStore/slice/Battery/types.ts | 8 +- .../slice/Bluetooth/Bluetooth.slice.ts | 8 +- .../__tests__/Bluetooth.slice.test.ts | 5 +- .../settingsStore/slice/Bluetooth/types.ts | 8 +- .../slice/General/General.slice.ts | 13 +- .../General/__tests__/General.slice.test.ts | 29 +- .../settingsStore/slice/General/index.ts | 2 +- .../settingsStore/slice/General/types.ts | 23 +- .../settingsStore/slice/Sound/Sound.slice.ts | 8 +- .../slice/Sound/__tests__/Sound.slice.test.ts | 7 +- src/store/settingsStore/slice/Sound/types.ts | 8 +- .../settingsStore/slice/Users/Users.slice.ts | 15 +- .../__snapshots__/Users.slice.test.ts.snap | 3 +- src/store/settingsStore/slice/Users/types.ts | 4 +- .../settingsStore/slice/Wifi/Wifi.slice.ts | 8 +- .../slice/Wifi/__tests__/Wifi.slice.test.ts | 7 +- src/store/settingsStore/slice/Wifi/types.ts | 8 +- src/types/menu.ts | 19 + 184 files changed, 40515 insertions(+), 27319 deletions(-) create mode 100644 .github/workflows/build-web.yml create mode 100644 .github/workflows/ci-web.yml delete mode 100644 .github/workflows/deploy.yaml delete mode 100644 .github/workflows/main.yml delete mode 100644 .github/workflows/release.yml create mode 100644 src/assets/icons/SettingsIcons.tsx delete mode 100644 src/screens/private/Home/TopBar/LeftSideComponents/TopAppBarAppMenu/__tests__/TopAppBarAppMenu.test.tsx delete mode 100644 src/screens/private/Home/TopBar/LeftSideComponents/TopAppBarAppMenu/__tests__/__snapshots__/TopAppBarAppMenu.test.tsx.snap delete mode 100644 src/screens/private/Home/TopBar/RightSideComponents/DateTimeDrawer/WorldClockComponent.tsx delete mode 100644 src/screens/private/Home/TopBar/RightSideComponents/DateTimeDrawer/__tests__/WorldClockComponent.test.tsx delete mode 100644 src/screens/private/Home/TopBar/RightSideComponents/DateTimeDrawer/__tests__/__snapshots__/WorldClockComponent.test.tsx.snap create mode 100644 src/screens/private/program/Bin/data/Options.ts create mode 100644 src/screens/private/program/Calendar/data/Options.ts create mode 100644 src/screens/private/program/Chrome/data/Options.ts create mode 100644 src/screens/private/program/Finder/data/Options.ts create mode 100644 src/screens/private/program/Github/data/Options.ts create mode 100644 src/screens/private/program/Notes/data/Options.ts create mode 100644 src/screens/private/program/Settings/components/AccessibilitySettings.tsx create mode 100644 src/screens/private/program/Settings/components/AppearanceSettings.tsx create mode 100644 src/screens/private/program/Settings/components/BatterySettings.tsx create mode 100644 src/screens/private/program/Settings/components/BluetoothSettings.tsx create mode 100644 src/screens/private/program/Settings/components/DesktopDockSettings.tsx create mode 100644 src/screens/private/program/Settings/components/DisplaysSettings.tsx create mode 100644 src/screens/private/program/Settings/components/FocusSettings.tsx create mode 100644 src/screens/private/program/Settings/components/GameCenterSettings.tsx create mode 100644 src/screens/private/program/Settings/components/GeneralSettings.tsx create mode 100644 src/screens/private/program/Settings/components/GeneralSubPageSettings.tsx create mode 100644 src/screens/private/program/Settings/components/ICloudSettings.tsx create mode 100644 src/screens/private/program/Settings/components/InternetAccountsSettings.tsx create mode 100644 src/screens/private/program/Settings/components/LockScreenSettings.tsx create mode 100644 src/screens/private/program/Settings/components/NetworkSettings.tsx create mode 100644 src/screens/private/program/Settings/components/NotificationsSettings.tsx create mode 100644 src/screens/private/program/Settings/components/PrivacySecuritySettings.tsx create mode 100644 src/screens/private/program/Settings/components/ScreenTimeSettings.tsx create mode 100644 src/screens/private/program/Settings/components/SiriSettings.tsx create mode 100644 src/screens/private/program/Settings/components/SoundSettings.tsx create mode 100644 src/screens/private/program/Settings/components/TouchIdPasswordSettings.tsx create mode 100644 src/screens/private/program/Settings/components/UsersGroupsSettings.tsx create mode 100644 src/screens/private/program/Settings/components/WalletSettings.tsx create mode 100644 src/screens/private/program/Settings/components/WallpaperSettings.tsx create mode 100644 src/screens/private/program/Settings/components/WifiSettings.tsx create mode 100644 src/screens/private/program/Settings/components/index.ts create mode 100644 src/screens/private/program/Settings/const.tsx create mode 100644 src/screens/private/program/Settings/data/Options.ts create mode 100644 src/screens/private/program/Spotify/data/Options.ts create mode 100644 src/screens/private/program/Terminal/data/Options.ts create mode 100644 src/screens/private/program/VsCode/data/Options.ts create mode 100644 src/store/appStore/selector/Calendar/Calendar.selector.ts create mode 100644 src/store/appStore/selector/Calendar/index.ts create mode 100644 src/store/appStore/slice/Calendar/Calendar.slice.ts create mode 100644 src/store/appStore/slice/Calendar/index.ts create mode 100644 src/store/appStore/slice/Calendar/types.ts create mode 100644 src/types/menu.ts diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml new file mode 100644 index 0000000..ceceaba --- /dev/null +++ b/.github/workflows/build-web.yml @@ -0,0 +1,119 @@ +name: Build & Publish Web App + +on: + workflow_dispatch: + +permissions: + contents: write + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + check-branch: + name: Validate Branch + runs-on: ubuntu-latest + steps: + - name: Assert development branch + run: | + echo "Triggered branch: ${{ github.ref_name }}" + if [ "${{ github.ref_name }}" != "development" ]; then + echo "Error: This workflow can only be manually run on the 'development' branch." + exit 1 + fi + + build-web: + name: Build Web App + needs: check-branch + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v6 + with: + token: ${{ secrets.PA_TOKEN }} + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 20 + + - name: Enable Corepack + run: corepack enable + + - name: Install Dependencies + run: yarn install --immutable + + - name: Build Web App + run: yarn build + env: + REACT_APP_GOOGLE_CLIENT_ID: ${{ secrets.REACT_APP_GOOGLE_CLIENT_ID }} + + - name: Upload Web Build Artifacts + uses: actions/upload-artifact@v7 + with: + name: web-build-frontend + path: build/ + retention-days: 1 + + release-web: + name: Release Web App + needs: build-web + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout Code + uses: actions/checkout@v6 + with: + token: ${{ secrets.PA_TOKEN }} + fetch-depth: 0 + + - name: Conventional Changelog Action + id: changelog + uses: TriPSs/conventional-changelog-action@latest + with: + github-token: ${{ secrets.PA_TOKEN }} + git-user-name: 'GrowBoard Bot' + output-file: false + version-file: 'package.json' + git-path: '.' + tag-prefix: 'v' + skip-on-empty: 'false' + + - name: Download Web Build Artifacts + if: ${{ steps.changelog.outputs.skipped == 'false' }} + uses: actions/download-artifact@v7 + with: + name: web-build-frontend + path: build/ + + - name: Zip Build Artifacts + if: ${{ steps.changelog.outputs.skipped == 'false' }} + run: | + cd build + zip -r ../web-build.zip . + cd .. + + - name: Create GitHub Release + uses: softprops/action-gh-release@v4 + if: ${{ steps.changelog.outputs.skipped == 'false' }} + with: + tag_name: ${{ steps.changelog.outputs.tag }} + name: ${{ steps.changelog.outputs.tag }} + body: ${{ steps.changelog.outputs.clean_changelog }} + files: web-build.zip + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.PA_TOKEN }} + + - name: 📂 Sync files + if: ${{ steps.changelog.outputs.skipped == 'false' }} + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 + with: + server: ${{ secrets.MAC_AMITRAIKWAR_FTP_SERVER }} + username: ${{ secrets.MAC_AMITRAIKWAR_FTP_ACCOUNT }} + password: ${{ secrets.MAC_AMITRAIKWAR_FTP_PASSWORD }} + local-dir: build/ + server-dir: ./ diff --git a/.github/workflows/ci-web.yml b/.github/workflows/ci-web.yml new file mode 100644 index 0000000..ce68202 --- /dev/null +++ b/.github/workflows/ci-web.yml @@ -0,0 +1,52 @@ +name: Web CI + +on: + push: + branches: + - development + paths: + - 'src/**' + - 'public/**' + - 'package.json' + - 'yarn.lock' + - '.github/workflows/ci-web.yml' + pull_request: + branches: + - development + paths: + - 'src/**' + - 'public/**' + - 'package.json' + - 'yarn.lock' + - '.github/workflows/ci-web.yml' + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + web-ci: + name: Lint, Build and Test Web + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 20 + + - name: Enable Corepack + run: corepack enable + + - name: Install Dependencies + run: yarn install --immutable + + - name: Lint + run: yarn lint + + - name: Build + run: yarn build + + - name: Test + run: yarn test --watchAll=false --passWithNoTests diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml deleted file mode 100644 index 7127a41..0000000 --- a/.github/workflows/deploy.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: Deploy job - -on: - release: - types: [published] - -jobs: - setup_and_deploy: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20.x] - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - - name: Install Dependencies - run: yarn install - - name: Build - run: yarn build --if-present - - name: 📂 Sync files - uses: SamKirkland/FTP-Deploy-Action@v4.3.5 - with: - server: ${{ secrets.MAC_AMITRAIKWAR_FTP_SERVER }} - username: ${{ secrets.MAC_AMITRAIKWAR_FTP_ACCOUNT }} - password: ${{ secrets.MAC_AMITRAIKWAR_FTP_PASSWORD }} - local-dir: ./build/ - server-dir: ./ diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 43c09d8..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Build - -on: - push: - branches: ['development'] - pull_request: - branches: ['development', 'production'] - -jobs: - build_test_lint: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20.x] - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - - name: Install Dependencies - run: yarn install - - name: Build - run: yarn build --if-present - - name: Linting - run: yarn lint - - name: Test - run: yarn test:cov - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v4.0.1 - with: - token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 51199c1..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Releases -on: - push: - branches: - - production - -permissions: - contents: write - -jobs: - release: - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v4 - with: - token: ${{ secrets.PA_TOKEN }} - - name: conventional changelog action - id: changelog - # https://github.com/TriPSs/conventional-changelog-action - uses: TriPSs/conventional-changelog-action@latest - with: - # you can also create separate token to trace action - github-token: '${{ secrets.PA_TOKEN }}' - git-user-name: 'AR mac Bot' - output-file: false - - name: create release - # https://github.com/actions/create-release - uses: softprops/action-gh-release@v1 - if: ${{steps.changelog.outputs.skipped == 'false'}} - env: - # This token is provided by Actions, you do not need to create your own token - GITHUB_TOKEN: ${{ secrets.PA_TOKEN }} - with: - tag_name: ${{ steps.changelog.outputs.tag }} - name: ${{ steps.changelog.outputs.tag }} - body: ${{steps.changelog.outputs.clean_changelog}} - draft: false - prerelease: false diff --git a/jest.config.js b/jest.config.js index 2fc9b16..53ad8f6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -24,8 +24,8 @@ module.exports = { moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx'], moduleDirectories: ['node_modules'], moduleNameMapper: { - '@assets': '/src/assets', - '@assets/*': '/src/assets/*', + '^@assets$': '/src/assets', + '^@assets/(.*)$': '/src/assets/$1', '@router': '/src/router', '@screens': '/src/screens', '@hooks': '/src/hooks', diff --git a/src/assets/icons/SettingsIcons.tsx b/src/assets/icons/SettingsIcons.tsx new file mode 100644 index 0000000..37f6f98 --- /dev/null +++ b/src/assets/icons/SettingsIcons.tsx @@ -0,0 +1,677 @@ +import React from 'react'; + +// Wrapper to standardise macOS colored icon container +export const IconWrapper = ({ + color, + children, +}: { + color: string; + children: React.ReactNode; +}) => ( +
+ {children} +
+); + +export const WifiIcon = () => ( + + + + + + + + +); + +export const BluetoothIcon = () => ( + + + + + +); + +export const NetworkIcon = () => ( + + + + + + + +); + +export const BatteryIcon = () => ( + + + + + + +); + +export const GeneralIcon = () => ( + + + + + + +); + +export const AccessibilityIcon = () => ( + + + + + + +); + +export const AppearanceIcon = () => ( + + + + + + +); + +export const SiriIcon = () => ( + + + + + + +); + +export const DesktopDockIcon = () => ( + + + + + + + + +); + +export const DisplaysIcon = () => ( + + + + + + +); + +export const WallpaperIcon = () => ( + + + + + + + +); + +export const SoundIcon = () => ( + + + + + + +); + +export const AppleCareIcon = () => ( + + + +); + +export const InfoIcon = () => ( + + + + + +); + +export const SoftwareUpdateIcon = () => ( + + + +); + +export const StorageIcon = () => ( + + + + + + +); + +export const ContinuityIcon = () => ( + + + + +); + +export const AutoFillIcon = () => ( + + + + +); + +export const DateIcon = () => ( + + + + +); + +export const LanguageIcon = () => ( + + + + + +); + +export const LoginItemsIcon = () => ( + + + + +); + +export const SharingIcon = () => ( + + + + + +); + +export const ChevronIcon = () => ( + + + +); + +export const SearchIcon = () => ( + + + + +); + +export const BackIcon = ({ disabled }: { disabled: boolean }) => ( + + + +); + +export const ForwardIcon = ({ disabled }: { disabled: boolean }) => ( + + + +); + +export const NotificationsIcon = () => ( + + + + + + +); + +export const FocusIcon = () => ( + + + + + +); + +export const ScreenTimeIcon = () => ( + + + + + + + + +); + +export const LockScreenIcon = () => ( + + + + + + +); + +export const PrivacySecurityIcon = () => ( + + + + + + + + +); + +export const TouchIdPasswordIcon = () => ( + + + + + + + + + +); + +export const UsersGroupsIcon = () => ( + + + + + + + + +); + +export const InternetAccountsIcon = () => ( + + + + + + +); + +export const GameCenterIcon = () => ( + + + + + + + +); + +export const ICloudIcon = () => ( + + + + + +); + +export const WalletIcon = () => ( + + + + + + +); diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index 3057ab9..85463f5 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -20,6 +20,7 @@ export { BackIcon } from './Back'; export { RefreshIcon } from './Refresh'; export { MenuIcon } from './Menu'; export { InfoIcon } from './InfoIcon'; +export { AirDropIcon } from './AirDrop'; // Social icons export { LinkedInIcon } from './LinkedIn'; diff --git a/src/components/Modal/Modal.tsx b/src/components/Modal/Modal.tsx index c97eb03..07b57a2 100644 --- a/src/components/Modal/Modal.tsx +++ b/src/components/Modal/Modal.tsx @@ -1,4 +1,4 @@ -import { Modal, ModalContent } from '@chakra-ui/react'; +import { Box } from '@chakra-ui/react'; import { ModalProps } from './types'; import { SearchModal } from './Modals'; import { ModalID } from '@uiStore'; @@ -13,12 +13,36 @@ const ModalToShow = ({ modalID }: { modalID: ModalID }) => { }; const ModalComponent = ({ isOpen, modalID, onModalClose }: ModalProps) => { + if (!isOpen || modalID === 'none' || modalID === ('none' as any)) return null; + return ( - - + <> + {/* Custom Backdrop */} + + + {/* Custom Modal Content Container */} + - - + + ); }; diff --git a/src/components/Modal/Modals/Search/SearchModal.tsx b/src/components/Modal/Modals/Search/SearchModal.tsx index 9104753..327d46f 100644 --- a/src/components/Modal/Modals/Search/SearchModal.tsx +++ b/src/components/Modal/Modals/Search/SearchModal.tsx @@ -36,8 +36,9 @@ const SearchModal = () => { diff --git a/src/components/Modal/Modals/Search/__tests__/__snapshots__/SearchModal.test.tsx.snap b/src/components/Modal/Modals/Search/__tests__/__snapshots__/SearchModal.test.tsx.snap index 07a154f..e334edd 100644 --- a/src/components/Modal/Modals/Search/__tests__/__snapshots__/SearchModal.test.tsx.snap +++ b/src/components/Modal/Modals/Search/__tests__/__snapshots__/SearchModal.test.tsx.snap @@ -11,7 +11,7 @@ exports[`SearchModal should not render component if isOpen is false 1`] = ` data-group="true" >
`; -exports[`Modal component search modal should render correctly 1`] = `
`; +exports[`Modal component search modal should render correctly 1`] = ` +
+
+
+
+
+
+ + + +
+ +
+
+
+
+
+`; diff --git a/src/components/Window/Window.tsx b/src/components/Window/Window.tsx index afc76e8..e1f9dde 100644 --- a/src/components/Window/Window.tsx +++ b/src/components/Window/Window.tsx @@ -3,7 +3,7 @@ import { WindowProps } from './types'; import { Box } from '@chakra-ui/react'; import { ResizableBox, ResizeCallbackData } from 'react-resizable'; import { useWindowDimensions } from '@hooks'; -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import './css/window.css'; import { darkModeColorSelector, @@ -21,7 +21,7 @@ import WindowCloseControl from './WindowControl'; const Window = ({ children, topBar, app }: WindowProps) => { const { windowTabBgColor } = settingsStore(useShallow(darkModeColorSelector)); const currentApp = processStore(useShallow(activeAppSelector))(app); - const { setWindowSize, updatePosition } = processStore( + const { setWindowSize, updatePosition, bringToFront } = processStore( useShallow(activeAppActionsSelector), ); @@ -37,6 +37,22 @@ const Window = ({ children, topBar, app }: WindowProps) => { }; const maximized = currentApp?.size === WindowSize.MAX ? true : false; + const [prevMaximized, setPrevMaximized] = useState(maximized); + const [isTransitioning, setIsTransitioning] = useState(false); + + if (maximized !== prevMaximized) { + setPrevMaximized(maximized); + setIsTransitioning(true); + } + + useEffect(() => { + if (isTransitioning) { + const timer = setTimeout(() => { + setIsTransitioning(false); + }, 500); + return () => clearTimeout(timer); + } + }, [isTransitioning]); const onMaximizeClick = () => { const newSize = maximized ? WindowSize.DEFAULT : WindowSize.MAX; @@ -47,67 +63,126 @@ const Window = ({ children, topBar, app }: WindowProps) => { updatePosition(app, position); }; + const handleBringToFront = () => { + bringToFront(app); + }; + + const [isOpening, setIsOpening] = useState(true); + + useEffect(() => { + const timer = setTimeout(() => { + setIsOpening(false); + }, 50); + return () => clearTimeout(timer); + }, []); + + const isMinimized = currentApp?.size === WindowSize.HIDE; + + // Bottom Center of the screen (mimicking Dock location) + const targetX = width / 2 - 400; + const targetY = height - 30; + + // Translation needed to move the window's center to the dock + const translateX = targetX; + const translateY = targetY; + + const shouldCollapse = isMinimized || isOpening; + + const minimizeStyle: React.CSSProperties = shouldCollapse + ? { + transform: `translate(${translateX}px, ${translateY}px) scale(0.01)`, + opacity: 0, + pointerEvents: 'none', + visibility: 'hidden', + zIndex: 0, + transition: + 'transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity 0.4s ease-in-out, visibility 0.4s', + } + : { + transform: 'translate(0px, 0px) scale(1)', + opacity: 1, + pointerEvents: 'auto', + visibility: 'visible', + transition: + 'transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity 0.2s ease-in-out, visibility 0s', + }; + return ( - - - - - - {topBar} + + + + {topBar} + + + + {children} - - {children} - - - - + + +
); }; diff --git a/src/components/Window/WindowControl.tsx b/src/components/Window/WindowControl.tsx index 46912d8..981f887 100644 --- a/src/components/Window/WindowControl.tsx +++ b/src/components/Window/WindowControl.tsx @@ -1,4 +1,4 @@ -import { Box, Text, useBoolean } from '@chakra-ui/react'; +import { Box, useBoolean } from '@chakra-ui/react'; import { ProgramType, WindowSize, @@ -7,22 +7,6 @@ import { useShallow, } from '@processStore'; -const CommonBoxProps = { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - alignContent: 'center', -}; - -const CommonTextProps = { - fontSize: 12, - fontWeight: 'bold', - _hover: { - cursor: 'pointer', - }, - transition: 'all 0.1s', -}; - const WindowControl = ({ app, onMaximizeClick, @@ -30,10 +14,15 @@ const WindowControl = ({ app: ProgramType; onMaximizeClick: () => void; }) => { - const [opacity, setOpacity] = useBoolean(false); + const [isHovered, setIsHovered] = useBoolean(false); + const { removeApp, setWindowSize } = processStore( useShallow(activeAppActionsSelector), ); + + const activeAppRunning = processStore((state) => state.ActiveApp.activeApp); + const isActive = activeAppRunning === app; + const onClose = () => { setTimeout(() => { removeApp(app); @@ -43,71 +32,143 @@ const WindowControl = ({ const onMinimize = () => { setWindowSize(app, WindowSize.HIDE); }; - const onMouseEnter = () => { - setOpacity.on(); - }; - const onMouseLeave = () => { - setOpacity.off(); - }; + // macOS Traffic Light styling + // Active Colors + const redBg = '#FF5F56'; + const redBorder = '#E0443E'; + const yellowBg = '#FFBD2E'; + const yellowBorder = '#DEA123'; + const greenBg = '#27C93F'; + const greenBorder = '#1AAB29'; + + // Inactive Colors (macOS Dark mode style since the design is dark-themed) + const inactiveBg = '#4C4C4C'; + const inactiveBorder = '#3A3A3A'; + + // Icon Stroke Colors (only visible on hover) + const redStroke = '#4C0002'; + const yellowStroke = '#5C3E00'; + const greenStroke = '#004D05'; return ( - <> + + {/* Close Button */} - - x - + + + + {/* Minimize Button */} - - - - + + + + {/* Maximize Button */} - - o - + + - + ); }; diff --git a/src/components/Window/__tests__/WindowControl.test.tsx b/src/components/Window/__tests__/WindowControl.test.tsx index 8b27255..7034bb4 100644 --- a/src/components/Window/__tests__/WindowControl.test.tsx +++ b/src/components/Window/__tests__/WindowControl.test.tsx @@ -81,11 +81,11 @@ describe('WindowControl', () => { />, ); - fireEvent.mouseEnter(screen.getByText('x')); + fireEvent.mouseEnter(screen.getByTestId('traffic-lights')); expect(container).toMatchSnapshot(); - fireEvent.mouseLeave(screen.getByText('x')); + fireEvent.mouseLeave(screen.getByTestId('traffic-lights')); expect(container).toMatchSnapshot(); }); diff --git a/src/components/Window/__tests__/Windows.test.tsx b/src/components/Window/__tests__/Windows.test.tsx index 9c2f197..2a64953 100644 --- a/src/components/Window/__tests__/Windows.test.tsx +++ b/src/components/Window/__tests__/Windows.test.tsx @@ -254,7 +254,7 @@ describe('Windows', () => { expect(capturedDraggableProps.maximized).toBe(true); expect(capturedResizableProps.resizeHandles).toEqual([]); - expect(capturedResizableProps.style.transition).toBe('all 0.2s'); + expect(capturedResizableProps.style.transition).toBe('all 0.3s cubic-bezier(0.16, 1, 0.3, 1)'); // Test toggle back to DEFAULT fireEvent.click(screen.getByLabelText('maximize')); diff --git a/src/components/Window/__tests__/__snapshots__/WindowControl.test.tsx.snap b/src/components/Window/__tests__/__snapshots__/WindowControl.test.tsx.snap index ea8ef7c..0c12be1 100644 --- a/src/components/Window/__tests__/__snapshots__/WindowControl.test.tsx.snap +++ b/src/components/Window/__tests__/__snapshots__/WindowControl.test.tsx.snap @@ -3,34 +3,70 @@ exports[`WindowControl should render correctly 1`] = `
-

- x -

-
-
-

+ + +

+
- - -

-
-
-

+ + +

+
- o -

+ + + +
`; @@ -38,34 +74,70 @@ exports[`WindowControl should render correctly 1`] = ` exports[`WindowControl should trigger mouse enter and leave event 1`] = `
-

- x -

-
-
-

+ + +

+
- - -

-
-
-

+ + +

+
- o -

+ + + +
`; @@ -73,34 +145,70 @@ exports[`WindowControl should trigger mouse enter and leave event 1`] = ` exports[`WindowControl should trigger mouse enter and leave event 2`] = `
-

- x -

-
-
-

+ + +

+
- - -

-
-
-

+ + +

+
- o -

+ + + +
`; diff --git a/src/components/Window/__tests__/__snapshots__/Windows.test.tsx.snap b/src/components/Window/__tests__/__snapshots__/Windows.test.tsx.snap index 3adcfde..c243b26 100644 --- a/src/components/Window/__tests__/__snapshots__/Windows.test.tsx.snap +++ b/src/components/Window/__tests__/__snapshots__/Windows.test.tsx.snap @@ -3,62 +3,102 @@ exports[`Windows should render for default values 1`] = `
-

- x -

-
-
-

- - -

-
-
-

+ + + +

+
+ + + +
+
+ + + +
+
+
- o -

+
+ Top bar +
+
- Top bar + Test
-
-
- Test -
-
@@ -68,56 +108,96 @@ exports[`Windows should render for default values 1`] = ` exports[`Windows should render maximized window 1`] = `
-

- x -

-
-
-

- - -

+
+ + + +
+
+ + + +
+
+ + + +
+
+
-

- o -

-
-
-
-
-
- Test +
+ Test +
@@ -129,56 +209,96 @@ exports[`Windows should render maximized window 1`] = ` exports[`Windows should toggle maximize on double click on title bar 1`] = `
-

- x -

-
-
-

- - -

+
+ + + +
+
+ + + +
+
+ + + +
+
+
-

- o -

-
-
-
-
-
- Test +
+ Test +
@@ -190,56 +310,96 @@ exports[`Windows should toggle maximize on double click on title bar 1`] = ` exports[`Windows should trigger close on close button press 1`] = `
-

- x -

-
-
-

- - -

+
+ + + +
+
+ + + +
+
+ + + +
+
+
-

- o -

-
-
-
-
-
- Test +
+ Test +
@@ -251,56 +411,96 @@ exports[`Windows should trigger close on close button press 1`] = ` exports[`Windows should trigger maximize on maximize button press 1`] = `
-

- x -

-
-
-

- - -

+
+ + + +
+
+ + + +
+
+ + + +
+
+
-

- o -

-
-
-
-
-
- Test +
+ Test +
@@ -312,56 +512,96 @@ exports[`Windows should trigger maximize on maximize button press 1`] = ` exports[`Windows should trigger minimize on minimize button press 1`] = `
-

- x -

-
-
-

- - -

+
+ + + +
+
+ + + +
+
+ + + +
+
+
-

- o -

-
-
-
-
-
- Test +
+ Test +
diff --git a/src/localization/locales/en/main.json b/src/localization/locales/en/main.json index c93ff81..e42955e 100644 --- a/src/localization/locales/en/main.json +++ b/src/localization/locales/en/main.json @@ -21,7 +21,7 @@ "loginPasswordText2": "Your password is required to enable Touch ID", "inputPlaceholder": "Enter Password", "passwordHintLabel": "Password Hint", - "passwordHint": "Your password is the same as your macOS user account password. If you've forgotten it, try entering your Apple ID password or use the Reset Password assistant. Please use - 'Amit'", + "passwordHint": "Your password is the same as your macOS user account password. If you've forgotten it, try entering your Apple ID password or use the Reset Password assistant. Please use - '1234'", "keyboard": { "type": "ABC - India", "option": { diff --git a/src/providers/draggable/DraggableProvider.tsx b/src/providers/draggable/DraggableProvider.tsx index 239d742..56b6af3 100644 --- a/src/providers/draggable/DraggableProvider.tsx +++ b/src/providers/draggable/DraggableProvider.tsx @@ -7,32 +7,30 @@ const DraggableProvider = ({ position, maximized, onPositionChange, + onStart, }: DraggableProps) => { const { width, height } = useWindowDimensions(); - const positionHandler = maximized - ? {} - : { - onStop: (e: any, data: any) => { - const { x, y } = data; - onPositionChange({ x, y }); - }, - }; + const draggableProps = { + handle: '.handle', + bounds: { left: 0, top: 0, right: width, bottom: height }, + positionOffset: { x: 0, y: 28 }, + defaultPosition: maximized ? position : { x: 0, y: 0 }, + position: !maximized ? position : { x: 0, y: 0 }, + grid: [3, 3] as [number, number], + scale: 1, + ...(maximized + ? {} + : { + onStart: onStart ? () => onStart() : undefined, + onStop: (_e: any, data: any) => { + const { x, y } = data; + onPositionChange({ x, y }); + }, + }), + } as React.ComponentProps; - return ( - - {children} - - ); + return {children}; }; export default DraggableProvider; diff --git a/src/providers/draggable/types.ts b/src/providers/draggable/types.ts index 370328c..05510d0 100644 --- a/src/providers/draggable/types.ts +++ b/src/providers/draggable/types.ts @@ -8,4 +8,6 @@ export type DraggableProps = { position: Position; maximized: boolean; onPositionChange: (position: Position) => void; + /** Called when a drag starts — use to bring window to front */ + onStart?: () => void; }; diff --git a/src/providers/routerProvider/__tests__/__snapshots__/RouterProvider.test.tsx.snap b/src/providers/routerProvider/__tests__/__snapshots__/RouterProvider.test.tsx.snap index e12659a..da96577 100644 --- a/src/providers/routerProvider/__tests__/__snapshots__/RouterProvider.test.tsx.snap +++ b/src/providers/routerProvider/__tests__/__snapshots__/RouterProvider.test.tsx.snap @@ -24,12 +24,12 @@ exports[`RouterProvider should render for lock when power is on but user logged class="css-sikaw0" >
+

+

+
@@ -1316,53 +1318,101 @@ exports[`RouterProvider should render mac for login 1`] = `
-
+
-
+ + + + +
-
+
-
-
- + +
+ +
+
+ - ⌘ X + ⌘X -

+
+ +
+
+ + -
- -
@@ -2748,16 +3051,16 @@ exports[`RouterProvider should render mac for login 1`] = ` -
- - - - - - + + @@ -3852,12 +3271,12 @@ exports[`RouterProvider should render mac for login 1`] = ` role="group" >
+
+ +
@@ -455,7 +508,7 @@ exports[`LazyHomeComponent should render correctly to match snapshot 1`] = ` tabindex="-1" > -
+
-
+ + + + +
-
+
-
-
+ + +
+ +
+
- ⌘ X + ⌘X -

+
+ +
+ + + - - - + + - - + + - - - - - - - - + + @@ -2795,12 +2212,12 @@ exports[`LazyHomeComponent should render correctly to match snapshot 1`] = ` role="group" > + + + +`; + +exports[`Home should render correctly with apps to match snapshot 1`] = ` +
+
+
+ +
+
+
+
+
-
-
- - - - - -
-
-
-
-
-
- Launchpad -
-
- Finder -
-
- Notes -
-
- Chrome -
-
- VsCode -
-
- Terminal -
-
- Spotify -
-
- Github -
-
- Settings -
-
-
- numbers -
-
- pages -
-
- xcode -
-
-
- Bin -
-
-
-
-
-
-
-`; - -exports[`Home should render correctly with apps to match snapshot 1`] = ` -
-
-
- -
-
-
-
- - -
- - -
- - - ⌘ X + ⌘X -

+
+ +
+
+ + -
- - +
+ + + + + + +
+
- - Stop Debugging - - - ⇧F5 - - - -
- -
- +

- Step Over - - +

- F10 - - -

+
- - Step Into - - - F11 - - - +

- Step Out - - +

- ⇧F11 - - -

+
- - Continue - -
+
+
+ +
+
+ + -
-
+ -

- Dark mode -

-

- Off -

-
-
- +

+ Focus +

+
+ +

- Night Shift + Display

+
+
+
+ + + +
+
+
+ +
+
+

- Off + Sound

+
+
+
+ + + + + +
+
+
+ +
-

- True Tone -

-

- Off -

-
-
- - - - - - - - @@ -7325,9 +8002,6 @@ exports[`Home should render correctly with apps to match snapshot 1`] = ` -
`; @@ -7360,12 +8034,12 @@ exports[`Home should render correctly with bin app to match snapshot 1`] = ` role="group" > + + + +
+ + + + + + - - - -
-
-
-
- Launchpad -
-
- Finder -
-
- Notes -
-
- Chrome -
-
- VsCode -
-
- Terminal -
- Spotify +
+
+
+
+

+ THURSDAY +

+

+ 14 +

+
+

+ No Events Today +

+
+
+
+

+ Pune ↗ +

+

+ 23° +

+
+
+
+ + + +

+ Mostly Cloudy +

+
+

+ H:29° L:22° +

+
+
+
+
+
+
+
+
+
+

+ Cupertino +

+

+ Yesterday +

+

+ -12:30 +

+
+
+
+
+
+

+ Tokyo +

+

+ Today +

+

+ +3:30 +

+
+
+
+
+
+

+ Sydney +

+

+ Today +

+

+ +4:30 +

+
+
+
+
+
+

+ Paris +

+

+ Yesterday +

+

+ -3:30 +

+
+
+
+
+
+
+
+

+ ▼ DOW +

+

+ 52,499 +

+
+
+

+ ▼ S&P 500 +

+

+ 7,515 +

+
+
+

+ ▲ AAPL +

+

+ 317.31 +

+
+
+
+

+ Economic Times +

+

+ US stocks today: S&P 500 and Nasdaq open lo... +

+
+
+
+
+

+ 1h 55m +

+
+
+
+

+ 60m +

+
+
+

+ 30m +

+
+
+

+ 0 +

+
+
+
+
+
+
+
+

+ 12 AM +

+

+ 6 AM +

+

+ 12 PM +

+
+
+
+
+
+ +

+ Xcode +

+
+

+ 1h 14m +

+
+
+
+ +

+ Chrome +

+
+

+ 38m +

+
+
+
+ +

+ Settings +

+
+

+ 1m +

+
+
+
+ +

+ Finder +

+
+

+ 18s +

+
+
+
+
+
+ +
+

+ ✕ +

+
+
+
+
+
+
+
+
+
Github
Settings
-
numbers
pages
- xcode + VsCode +
+
+ Terminal +
+
+ Spotify +
+
+ Github +
+
+ Settings +
+
+
+ numbers +
+
+ pages +
+
+ xcode
-
-
-
-
-
-
-
- Launchpad -
-
- Finder -
-
- Notes -
-
- Chrome -
- VsCode +
+
+
+
+

+ THURSDAY +

+

+ 14 +

+
+

+ No Events Today +

+
+
+
+

+ Pune ↗ +

+

+ 23° +

+
+
+
+ + + +

+ Mostly Cloudy +

+
+

+ H:29° L:22° +

+
+
+
+
+
+
+
+
+
+

+ Cupertino +

+

+ Yesterday +

+

+ -12:30 +

+
+
+
+
+
+

+ Tokyo +

+

+ Today +

+

+ +3:30 +

+
+
+
+
+
+

+ Sydney +

+

+ Today +

+

+ +4:30 +

+
+
+
+
+
+

+ Paris +

+

+ Yesterday +

+

+ -3:30 +

+
+
+
+
+
+
+
+

+ ▼ DOW +

+

+ 52,499 +

+
+
+

+ ▼ S&P 500 +

+

+ 7,515 +

+
+
+

+ ▲ AAPL +

+

+ 317.31 +

+
+
+
+

+ Economic Times +

+

+ US stocks today: S&P 500 and Nasdaq open lo... +

+
+
+
+
+

+ 1h 55m +

+
+
+
+

+ 60m +

+
+
+

+ 30m +

+
+
+

+ 0 +

+
+
+
+
+
+
+
+

+ 12 AM +

+

+ 6 AM +

+

+ 12 PM +

+
+
+
+
+
+ +

+ Xcode +

+
+

+ 1h 14m +

+
+
+
+ +

+ Chrome +

+
+

+ 38m +

+
+
+
+ +

+ Settings +

+
+

+ 1m +

+
+
+
+ +

+ Finder +

+
+

+ 18s +

+
+
+
+
+
+ +
+

+ ✕ +

+
+
+
+
+
+
+
+
+
Terminal
Spotify
Github
Settings
-
+ VsCode +
+
+ Terminal +
+
+ Spotify +
+
+ Github +
+
+ Settings +
+
+
-
+
+
+ + + +
+
+

+ Bluetooth +

+

+ On +

+
+
+
+
+ + + +
+
+

+ AirDrop +

+

+ Off +

+
+
+
+
+
+
+
+
+

+ Not Playing +

+
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+
+ + + + + + +
+
+ + + + +
+
+
+
+
+
+ + + + +
+
+ + + + +
+
+ + + +

+ Focus +

+
+
+
+

+ Display +

+
+
+
+ + + +
+
+
+ +
+
+
+

+ Sound +

+
+
+
+ + + + + +
+
+
+ +
+
+
+ +
+
+
+
+ -
-
-
-
-
-
-
- Launchpad -
-
- Finder -
-
- Notes -
- Chrome
-
-
- VsCode -
-
- Terminal + class="chakra-stack css-1jbmm9k" + > +
+
+
+

+ THURSDAY +

+

+ 14 +

+
+

+ No Events Today +

+
+
+
+

+ Pune ↗ +

+

+ 23° +

+
+
+
+ + + +

+ Mostly Cloudy +

+
+

+ H:29° L:22° +

+
+
+
+
+
+
+
+
+
+

+ Cupertino +

+

+ Yesterday +

+

+ -12:30 +

+
+
+
+
+
+

+ Tokyo +

+

+ Today +

+

+ +3:30 +

+
+
+
+
+
+

+ Sydney +

+

+ Today +

+

+ +4:30 +

+
+
+
+
+
+

+ Paris +

+

+ Yesterday +

+

+ -3:30 +

+
+
+
+
+
+
+
+

+ ▼ DOW +

+

+ 52,499 +

+
+
+

+ ▼ S&P 500 +

+

+ 7,515 +

+
+
+

+ ▲ AAPL +

+

+ 317.31 +

+
+
+
+

+ Economic Times +

+

+ US stocks today: S&P 500 and Nasdaq open lo... +

+
+
+
+
+

+ 1h 55m +

+
+
+
+

+ 60m +

+
+
+

+ 30m +

+
+
+

+ 0 +

+
+
+
+
+
+
+
+

+ 12 AM +

+

+ 6 AM +

+

+ 12 PM +

+
+
+
+
+
+ +

+ Xcode +

+
+

+ 1h 14m +

+
+
+
+ +

+ Chrome +

+
+

+ 38m +

+
+
+
+ +

+ Settings +

+
+

+ 1m +

+
+
+
+ +

+ Finder +

+
+

+ 18s +

+
+
+
+
+
+ +
+

+ ✕ +

+
+
+
+
+
+
+
+
+
Spotify
Github
Settings
-
numbers -
-
- pages +
+
+ VsCode +
+
+ Terminal +
+
+ Spotify +
+
+ Github +
+
+ Settings +
+
+
+ numbers +
+
+ pages
+
+
+`; + +exports[`Home should render correctly with finder app to match snapshot 1`] = ` +
+
+
+ +
+
+
+
+ + +
+ + + + + + + + - +

+ Go +

+ +
-
-
-
-
- -
-
-
-
-`; - -exports[`Home should render correctly with finder app to match snapshot 1`] = ` -
-
-
- -
-
-
-
- - + +
-
+ -