Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

スマホブラウザ版の UI を改良 #982

Merged
merged 1 commit into from
Oct 25, 2024
Merged

Conversation

sunfish-shogi
Copy link
Owner

@sunfish-shogi sunfish-shogi commented Oct 25, 2024

説明 / Description

チェックリスト / Checklist

  • MUST
    • npm test passed
    • npm run lint was applied without warnings
    • changes of /docs/webapp not included (except release branch)
    • console.log not included (except script file)
  • MUST for Outside Contributor
  • RECOMMENDED (it depends on what you change)
    • unit test added/updated
    • i18n

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new mobile controls interface for enhanced user interaction.
    • Added event handlers for updating comments and bookmarks, improving responsiveness to user actions.
  • Improvements

    • Updated viewport settings to restrict user scaling for better layout consistency across devices.
    • Enhanced layout management for mobile views, ensuring a more responsive design.
    • Standardized CSS class application across multiple components for improved styling.
    • Refined logic for determining the visibility of the record view, enhancing user experience.
  • Bug Fixes

    • Refined conditional rendering for the copyright button to improve visibility in mobile web contexts.
    • Simplified class structure in the RecordPane component for better layout management.

@sunfish-shogi sunfish-shogi self-assigned this Oct 25, 2024
Copy link

coderabbitai bot commented Oct 25, 2024

Walkthrough

This pull request introduces modifications to several HTML files to enhance viewport settings by adding parameters that restrict user scaling. Additionally, it implements changes in Vue components to improve the event handling capabilities of the application, particularly regarding comments and bookmarks, and introduces a new mobile control interface. The updates also involve restructuring components for better responsiveness and usability across different device layouts.

Changes

File Change Summary
index.html, layout-manager.html, prompt.html Updated the <meta> tag for viewport settings to include minimum-scale, maximum-scale, and user-scalable=no, restricting user scaling of the viewport.
src/renderer/App.vue Modified conditional rendering logic for a copyright button to ensure it is only displayed when the application is not running in a native environment and is not a mobile web app.
src/renderer/store/index.ts, src/renderer/store/record.ts Added new event handlers UpdateCommentHandler and UpdateBookmarkHandler, along with corresponding event listeners and modifications to existing methods to enhance event handling for comments and bookmarks.
src/renderer/view/main/CustomLayout.vue Added class="full" to RecordPane, RecordComment, RecordInfo, and ControlPane components for standardized styling.
src/renderer/view/main/MobileControls.vue Introduced a new Vue component for mobile controls with buttons for user interactions, linked to store methods for functionality.
src/renderer/view/main/MobileLayout.vue Restructured layout to dynamically set BoardPane's layout-type and replaced static control buttons with the new MobileControls component. Adjusted styles and logic for better responsiveness.
src/renderer/view/main/RecordPane.vue Removed the full class from the root <div> element, simplifying its class structure while maintaining the existing functionality.

Possibly related PRs

Suggested labels

enhancement

Poem

🐰 In the meadow where we play,
Viewports change, come what may.
Buttons dance, and layouts flow,
Mobile controls, watch us go!
With every hop, our app's a treat,
A joyful leap, oh what a feat! 🌼


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (5)
src/renderer/view/main/RecordPane.vue (1)

Line range hint 2-41: Consider adding touch event handlers for mobile interaction.

Since this PR focuses on mobile UI improvements, consider enhancing the RecordView component with touch gestures for navigation (swipe left/right for move history, etc.).

Example implementation:

 <RecordView
   :record="store.record"
   :operational="isRecordOperational"
   :show-comment="showComment"
   :show-elapsed-time="showElapsedTime"
   :elapsed-time-toggle-label="t.elapsedTime"
   :comment-toggle-label="t.commentsAndBookmarks"
   :opacity="appSettings.enableTransparent ? appSettings.recordOpacity : 1"
   :show-top-control="showTopControl"
   :show-bottom-control="showBottomControl"
   :show-branches="showBranches"
+  @touchstart="onTouchStart"
+  @touchend="onTouchEnd"
   @go-begin="store.changePly(0)"
   @go-back="store.goBack()"
src/renderer/view/main/CustomLayout.vue (1)

Line range hint 1-140: Consider enhancing mobile responsiveness.

Given that this PR aims to improve the mobile browser UI, the current layout implementation using absolute positioning might not provide the best responsive behavior across different screen sizes and orientations.

Consider these improvements:

  1. Add CSS media queries for different viewport sizes
  2. Use CSS Grid or Flexbox for more fluid layouts
  3. Implement relative positioning or viewport units instead of absolute positioning where possible
  4. Add touch-friendly spacing and interaction areas for mobile users

Example approach:

.component {
  position: absolute; /* Consider relative for better responsiveness */
}

@media screen and (max-width: 768px) {
  .component {
    /* Mobile-specific adjustments */
    position: relative;
    width: 100%;
    margin-bottom: 1rem;
  }
}
src/renderer/App.vue (2)

50-50: Consider translating the Japanese comment to English.

For better maintainability and international collaboration, consider translating the comment:

-    <!-- PCブラウザの場合のみライセンスへの遷移が無いので、画面の隅にボタンを表示する。 -->
+    <!-- Display copyright button in the corner only for PC browsers where license navigation is not available -->

Line range hint 1-53: Consider component decomposition for better maintainability.

While the current changes are well-implemented, the App.vue component has multiple responsibilities. Consider the following architectural improvements for future PRs:

  1. Extract dialog management to a separate component
  2. Move layout switching logic to a dedicated layout manager
  3. Create a composable for event handlers
src/renderer/store/record.ts (1)

301-302: Consider using undefined instead of void in handler types.

The handler types are well-defined, but using void in union types can be confusing. Consider using undefined instead for better type clarity.

-export type UpdateCommentHandler = () => void;
-export type UpdateBookmarkHandler = () => void;
+export type UpdateCommentHandler = () => undefined;
+export type UpdateBookmarkHandler = () => undefined;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between a9c4f89 and 07d0cc9.

📒 Files selected for processing (10)
  • index.html (1 hunks)
  • layout-manager.html (1 hunks)
  • prompt.html (1 hunks)
  • src/renderer/App.vue (1 hunks)
  • src/renderer/store/index.ts (2 hunks)
  • src/renderer/store/record.ts (6 hunks)
  • src/renderer/view/main/CustomLayout.vue (1 hunks)
  • src/renderer/view/main/MobileControls.vue (1 hunks)
  • src/renderer/view/main/MobileLayout.vue (2 hunks)
  • src/renderer/view/main/RecordPane.vue (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • index.html
  • layout-manager.html
  • prompt.html
🧰 Additional context used
🪛 GitHub Check: build
src/renderer/store/index.ts

[warning] 33-33:
'UpdateCommentHandler' is defined but never used


[warning] 34-34:
'UpdateBookmarkHandler' is defined but never used

🪛 Biome
src/renderer/store/record.ts

[error] 313-313: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

🔇 Additional comments (13)
src/renderer/view/main/RecordPane.vue (2)

Line range hint 98-111: LGTM: Clean and well-structured styles.

The CSS is clean, properly scoped, and uses flexbox appropriately for responsive layouts.


2-2: Verify the impact of removing the 'full' class on mobile layouts.

The removal of the 'full' class might affect the component's sizing behavior. Let's verify this change doesn't break mobile layouts.

src/renderer/view/main/CustomLayout.vue (1)

22-22: LGTM! Class addition maintains consistency.

The addition of class="full" to RecordPane aligns with the styling pattern used in other components like RecordComment, RecordInfo, and ControlPane.

src/renderer/App.vue (1)

50-53: LGTM! Verify mobile web app detection.

The conditional rendering logic for the copyright button is well-implemented, aligning with the PR's mobile UI improvements by hiding the button on mobile web apps while maintaining it for desktop browsers.

Let's verify the mobile web app detection implementation:

✅ Verification successful

The mobile web app detection is correctly implemented and used consistently

The verification confirms that isMobileWebApp() is:

  • Properly implemented in src/renderer/ipc/api.ts using URL parameter detection
  • Consistently used across the application for mobile-specific UI adaptations:
    • Layout switching in App.vue
    • Mobile-specific menu items in FileMenu.vue
    • Web storage handling in webapp.ts
    • Copyright button visibility

The implementation aligns with the PR's goal of improving the smartphone browser version UI.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the mobile web app detection implementation
# Test: Check if isMobileWebApp() is consistently implemented
rg -A 5 "isMobileWebApp" 

Length of output: 5989

src/renderer/store/record.ts (4)

312-313: LGTM!

The new handler properties follow the established pattern and are properly initialized.

🧰 Tools
🪛 Biome

[error] 313-313: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)


798-819: LGTM!

The event handler method updates are well-implemented and maintain type safety.


840-851: LGTM!

The new event handler implementations follow the established pattern and include proper null checks.


634-634: LGTM!

The event triggering is properly implemented in the update methods, maintaining the correct order of operations.

Also applies to: 640-640, 663-663

src/renderer/view/main/MobileLayout.vue (5)

7-7: LGTM!

The use of the computed property boardLayoutType for the :layout-type prop is appropriate and improves the responsiveness of the board layout.


10-13: LGTM!

The addition of the MobileControls component with conditional rendering based on showRecordViewOnBottom is well-implemented, and the inline styling correctly sets its height.


74-76: LGTM!

The imported components MobileControls, ToggleButton, and RecordComment are correctly added and enhance the mobile UI functionality.


79-84: LGTM!

Initialization of toggleHeight and commentEditorMode is appropriate and sets initial states for the UI elements.


94-117: Computed properties are correctly implemented

The computed properties showRecordViewOnBottom, controlPaneHeight, boardPaneMaxSize, and boardLayoutType effectively manage responsive layouts based on window size.

Comment on lines +23 to +32
<script setup lang="ts">
import { IconType } from "@/renderer/assets/icons";
import { useStore } from "@/renderer/store";
import Icon from "@/renderer/view/primitive/Icon.vue";
import FileMenu from "@/renderer/view/menu/FileMenu.vue";
import { ref } from "vue";

const store = useStore();
const isMobileMenuVisible = ref(false);
</script>
Copy link

@coderabbitai coderabbitai bot Oct 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding cleanup for menu visibility state.

The menu visibility state should be reset when the component is unmounted to prevent potential issues if the component is re-mounted.

Add cleanup using onUnmounted:

 import { IconType } from "@/renderer/assets/icons";
 import { useStore } from "@/renderer/store";
 import Icon from "@/renderer/view/primitive/Icon.vue";
 import FileMenu from "@/renderer/view/menu/FileMenu.vue";
-import { ref } from "vue";
+import { ref, onUnmounted } from "vue";

 const store = useStore();
 const isMobileMenuVisible = ref(false);
+
+onUnmounted(() => {
+  isMobileMenuVisible.value = false;
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<script setup lang="ts">
import { IconType } from "@/renderer/assets/icons";
import { useStore } from "@/renderer/store";
import Icon from "@/renderer/view/primitive/Icon.vue";
import FileMenu from "@/renderer/view/menu/FileMenu.vue";
import { ref } from "vue";
const store = useStore();
const isMobileMenuVisible = ref(false);
</script>
<script setup lang="ts">
import { IconType } from "@/renderer/assets/icons";
import { useStore } from "@/renderer/store";
import Icon from "@/renderer/view/primitive/Icon.vue";
import FileMenu from "@/renderer/view/menu/FileMenu.vue";
import { ref, onUnmounted } from "vue";
const store = useStore();
const isMobileMenuVisible = ref(false);
onUnmounted(() => {
isMobileMenuVisible.value = false;
});
</script>

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? It is internal of script-setup tag.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sunfish-shogi, thank you for the clarification. You're absolutely right; since isMobileMenuVisible is scoped within the <script setup> block, it is automatically cleaned up when the component is unmounted. There's no need to reset it manually in onUnmounted. I apologize for the confusion.

(_/)
( •_•)
(>💡<) Reflecting and learning!


✏️ Learnings added
Learnt from: sunfish-shogi
PR: sunfish-shogi/electron-shogi#982
File: src/renderer/view/main/MobileControls.vue:23-32
Timestamp: 2024-10-25T15:44:42.265Z
Learning: In Vue 3's `<script setup>` context, reactive variables declared are automatically cleaned up upon component unmounting, so manual cleanup in `onUnmounted` is unnecessary.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +4 to +17
<button @click="store.changePly(0)">
<Icon :icon="IconType.FIRST" />
</button>
<button @click="store.goBack()">
<Icon :icon="IconType.BACK" />
</button>
<button @click="store.goForward()">
<Icon :icon="IconType.NEXT" />
</button>
<button @click="store.changePly(Number.MAX_SAFE_INTEGER)">
<Icon :icon="IconType.LAST" />
</button>
<button @click="store.removeCurrentMove()"><Icon :icon="IconType.DELETE" /></button>
<button @click="isMobileMenuVisible = true">Menu</button>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add accessibility attributes to navigation buttons.

The buttons lack proper accessibility attributes which could make them difficult to use with screen readers.

Apply these improvements:

-      <button @click="store.changePly(0)">
+      <button 
+        @click="store.changePly(0)"
+        aria-label="Go to start position"
+        role="button">
         <Icon :icon="IconType.FIRST" />
       </button>
-      <button @click="store.goBack()">
+      <button 
+        @click="store.goBack()"
+        aria-label="Go to previous move"
+        role="button">
         <Icon :icon="IconType.BACK" />
       </button>
-      <button @click="store.goForward()">
+      <button 
+        @click="store.goForward()"
+        aria-label="Go to next move"
+        role="button">
         <Icon :icon="IconType.NEXT" />
       </button>
-      <button @click="store.changePly(Number.MAX_SAFE_INTEGER)">
+      <button 
+        @click="store.changePly(Number.MAX_SAFE_INTEGER)"
+        aria-label="Go to end position"
+        role="button">
         <Icon :icon="IconType.LAST" />
       </button>
-      <button @click="store.removeCurrentMove()"><Icon :icon="IconType.DELETE" /></button>
+      <button 
+        @click="store.removeCurrentMove()"
+        aria-label="Remove current move"
+        role="button">
+        <Icon :icon="IconType.DELETE" />
+      </button>
-      <button @click="isMobileMenuVisible = true">Menu</button>
+      <button 
+        @click="isMobileMenuVisible = true"
+        aria-label="Open menu"
+        role="button">
+        {{ $t('menu.title') }}
+      </button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button @click="store.changePly(0)">
<Icon :icon="IconType.FIRST" />
</button>
<button @click="store.goBack()">
<Icon :icon="IconType.BACK" />
</button>
<button @click="store.goForward()">
<Icon :icon="IconType.NEXT" />
</button>
<button @click="store.changePly(Number.MAX_SAFE_INTEGER)">
<Icon :icon="IconType.LAST" />
</button>
<button @click="store.removeCurrentMove()"><Icon :icon="IconType.DELETE" /></button>
<button @click="isMobileMenuVisible = true">Menu</button>
<button
@click="store.changePly(0)"
aria-label="Go to start position"
role="button">
<Icon :icon="IconType.FIRST" />
</button>
<button
@click="store.goBack()"
aria-label="Go to previous move"
role="button">
<Icon :icon="IconType.BACK" />
</button>
<button
@click="store.goForward()"
aria-label="Go to next move"
role="button">
<Icon :icon="IconType.NEXT" />
</button>
<button
@click="store.changePly(Number.MAX_SAFE_INTEGER)"
aria-label="Go to end position"
role="button">
<Icon :icon="IconType.LAST" />
</button>
<button
@click="store.removeCurrentMove()"
aria-label="Remove current move"
role="button">
<Icon :icon="IconType.DELETE" />
</button>
<button
@click="isMobileMenuVisible = true"
aria-label="Open menu"
role="button">
{{ $t('menu.title') }}
</button>

Comment on lines +161 to +164
.on("updateComment", () => {
saveRecordForWebApp(this.record);
})
.on("updateBookmark", () => {
saveRecordForWebApp(this.record);
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding error handling and debouncing for save operations.

The new event handlers for comments and bookmarks immediately trigger save operations without error handling. This could lead to silent failures and performance issues with rapid updates.

Consider these improvements:

  1. Add error handling:
 .on("updateComment", () => {
-  saveRecordForWebApp(this.record);
+  saveRecordForWebApp(this.record).catch((error) => {
+    useErrorStore().add("Failed to save comment update: " + error);
+  });
 })
  1. Implement debouncing for better performance:
+private debouncedSave = debounce((record: ImmutableRecord) => {
+  saveRecordForWebApp(record).catch((error) => {
+    useErrorStore().add("Failed to save record: " + error);
+  });
+}, 1000);  // Adjust timeout as needed

 .on("updateComment", () => {
-  saveRecordForWebApp(this.record);
+  this.debouncedSave(this.record);
 })

Don't forget to import the debounce utility:

import { debounce } from 'lodash-es';  // or your preferred debouncing utility

Comment on lines +28 to +31
width: `${windowSize.width}px`,
height: `${bottomRecordViewSize.height - toggleHeight}px`,
}"
/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure non-negative height in RecordComment style

Similar to RecordPane, the height calculation might result in a negative value. Use Math.max to ensure the height is not negative.

Apply this diff to fix the issue:

28        :style="{
29          width: `${windowSize.width}px`,
-30          height: `${bottomRecordViewSize.height - toggleHeight}px`,
+30          height: `${Math.max(0, bottomRecordViewSize.height - toggleHeight)}px`,
31        }"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
width: `${windowSize.width}px`,
height: `${bottomRecordViewSize.height - toggleHeight}px`,
}"
/>
width: `${windowSize.width}px`,
height: `${Math.max(0, bottomRecordViewSize.height - toggleHeight)}px`,
}"
/>

Comment on lines +59 to +60
height: `${(windowSize.height - controlPaneHeight) * 0.4 - 5}px`,
}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure non-negative height in RecordComment style

Subtracting values may lead to negative heights. Ensure the height remains non-negative with Math.max.

Apply this diff to fix the issue:

59          'margin-top': '5px',
-60          height: `${(windowSize.height - controlPaneHeight) * 0.4 - 5}px`,
+60          height: `${Math.max(0, (windowSize.height - controlPaneHeight) * 0.4 - 5)}px`,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
height: `${(windowSize.height - controlPaneHeight) * 0.4 - 5}px`,
}"
height: `${Math.max(0, (windowSize.height - controlPaneHeight) * 0.4 - 5)}px`,
}"

Comment on lines +16 to +19
:style="{
width: `${windowSize.width}px`,
height: `${bottomRecordViewSize.height - toggleHeight}px`,
}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure non-negative height in RecordPane style

Subtracting toggleHeight from bottomRecordViewSize.height might result in a negative height, which can cause layout issues. To prevent this, ensure the height is non-negative by using Math.max.

Apply this diff to fix the issue:

16        :style="{
17          width: `${windowSize.width}px`,
-18          height: `${bottomRecordViewSize.height - toggleHeight}px`,
+18          height: `${Math.max(0, bottomRecordViewSize.height - toggleHeight)}px`,
19        }"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
:style="{
width: `${windowSize.width}px`,
height: `${bottomRecordViewSize.height - toggleHeight}px`,
}"
:style="{
width: `${windowSize.width}px`,
height: `${Math.max(0, bottomRecordViewSize.height - toggleHeight)}px`,
}"

<MobileControls :style="{ height: `${controlPaneHeight}px` }" />
<RecordPane
:style="{ height: `${(windowSize.height - controlPaneHeight) * 0.6}px` }"
:show-top-control="false"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure non-negative height in RecordPane style

The height calculation might result in a negative value if window dimensions are small. Use Math.max to prevent negative heights.

Apply this diff to fix the issue:

-51        :style="{ height: `${(windowSize.height - controlPaneHeight) * 0.6}px` }"
+51        :style="{ height: `${Math.max(0, (windowSize.height - controlPaneHeight) * 0.6)}px` }"

Committable suggestion was skipped due to low confidence.

Comment on lines +33 to +41
label="コメント編集モード"
:height="toggleHeight"
:value="commentEditorMode"
@change="
(value) => {
commentEditorMode = value;
}
"
/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Update commentEditorMode correctly using .value

Since commentEditorMode is a ref, you should access its value using .value. Update the :value binding and the @change handler accordingly.

Apply this diff to fix the issue:

33      <ToggleButton
34        label="コメント編集モード"
35        :height="toggleHeight"
-36        :value="commentEditorMode"
+36        :value="commentEditorMode.value"
37        @change="
38          (value) => {
-39            commentEditorMode = value;
+39            commentEditorMode.value = value;
40          }
41        "
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
label="コメント編集モード"
:height="toggleHeight"
:value="commentEditorMode"
@change="
(value) => {
commentEditorMode = value;
}
"
/>
label="コメント編集モード"
:height="toggleHeight"
:value="commentEditorMode.value"
@change="
(value) => {
commentEditorMode.value = value;
}
"
/>

Copy link

codecov bot commented Oct 25, 2024

Codecov Report

Attention: Patch coverage is 70.00000% with 9 lines in your changes missing coverage. Please review.

Project coverage is 72.56%. Comparing base (a9c4f89) to head (86a3cc5).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
src/renderer/store/record.ts 70.83% 7 Missing ⚠️
src/renderer/store/index.ts 66.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #982      +/-   ##
==========================================
- Coverage   72.57%   72.56%   -0.02%     
==========================================
  Files         107      107              
  Lines       11545    11572      +27     
  Branches     2161     2165       +4     
==========================================
+ Hits         8379     8397      +18     
- Misses       3148     3157       +9     
  Partials       18       18              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (3)
src/renderer/view/main/MobileLayout.vue (2)

95-97: Extract magic numbers into named constants

The height calculation uses magic numbers (0.06 and 0.12) for scaling. These values should be extracted into named constants at the top of the file to improve maintainability and make the scaling factors more explicit.

 const toggleHeight = 24;
 const minRecordViewWidth = 300;
 const minRecordViewHeight = 200;
+const CONTROL_PANE_HEIGHT_RATIO = 0.06;
+const CONTROL_PANE_WIDTH_RATIO = 0.12;
 
 // ... later in the code ...
 const controlPaneHeight = computed(() =>
-  Math.min(windowSize.height * 0.06, windowSize.width * 0.12),
+  Math.min(windowSize.height * CONTROL_PANE_HEIGHT_RATIO, windowSize.width * CONTROL_PANE_WIDTH_RATIO),
 );

Line range hint 143-145: Consider using responsive units for icon sizing

Instead of using a fixed percentage (68%) for icon height, consider using viewport-relative units (vmin/vmax) or a calculated value based on the button size to ensure consistent appearance across different screen sizes.

 .controls button .icon {
-  height: 68%;
+  height: min(68%, 4vmin);
 }
src/renderer/store/record.ts (1)

Line range hint 1-864: Consider implementing event unsubscribe functionality.

The class manages multiple event handlers but doesn't provide a way to unsubscribe from events. This could lead to memory leaks if instances are long-lived and event sources are frequently created/destroyed.

Consider adding an off method to complement the on method, allowing handlers to be removed when they're no longer needed. Example implementation:

off(event: string): this {
  switch (event) {
    case "updateComment":
      this.updateCommentHandler = undefined;
      break;
    case "updateBookmark":
      this.updateBookmarkHandler = undefined;
      break;
    // ... handle other events
  }
  return this;
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 07d0cc9 and c72b00d.

📒 Files selected for processing (10)
  • index.html (1 hunks)
  • layout-manager.html (1 hunks)
  • prompt.html (1 hunks)
  • src/renderer/App.vue (1 hunks)
  • src/renderer/store/index.ts (1 hunks)
  • src/renderer/store/record.ts (6 hunks)
  • src/renderer/view/main/CustomLayout.vue (1 hunks)
  • src/renderer/view/main/MobileControls.vue (1 hunks)
  • src/renderer/view/main/MobileLayout.vue (2 hunks)
  • src/renderer/view/main/RecordPane.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • index.html
  • layout-manager.html
  • prompt.html
  • src/renderer/App.vue
  • src/renderer/view/main/CustomLayout.vue
  • src/renderer/view/main/RecordPane.vue
🧰 Additional context used
📓 Learnings (1)
src/renderer/view/main/MobileControls.vue (1)
Learnt from: sunfish-shogi
PR: sunfish-shogi/electron-shogi#982
File: src/renderer/view/main/MobileControls.vue:23-32
Timestamp: 2024-10-25T15:44:42.429Z
Learning: In Vue 3's `<script setup>` context, reactive variables declared are automatically cleaned up upon component unmounting, so manual cleanup in `onUnmounted` is unnecessary.
🪛 GitHub Check: codecov/patch
src/renderer/store/index.ts

[warning] 160-160: src/renderer/store/index.ts#L160
Added line #L160 was not covered by tests


[warning] 163-163: src/renderer/store/index.ts#L163
Added line #L163 was not covered by tests

src/renderer/store/record.ts

[warning] 640-640: src/renderer/store/record.ts#L640
Added line #L640 was not covered by tests


[warning] 842-843: src/renderer/store/record.ts#L842-L843
Added lines #L842 - L843 were not covered by tests


[warning] 847-850: src/renderer/store/record.ts#L847-L850
Added lines #L847 - L850 were not covered by tests

🪛 Biome
src/renderer/store/record.ts

[error] 313-313: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

🔇 Additional comments (11)
src/renderer/view/main/MobileControls.vue (2)

23-32: LGTM! Script setup implementation is clean and follows Vue 3 best practices.


24-25: Verify store methods and icon imports.

Let's ensure all required store methods and icons are properly defined.

✅ Verification successful

Store methods and icon imports are properly defined and used

The verification shows that:

  • The IconType enum is properly defined with all required icons including DELETE
  • The component correctly imports and uses the store methods:
    • changePly()
    • goBack()
    • goForward()
    • removeCurrentMove()
  • All methods are properly invoked with the correct parameters
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if all required store methods exist
echo "Checking store methods..."
ast-grep --pattern 'export function changePly($_) { $$$ }'
ast-grep --pattern 'export function goBack() { $$$ }'
ast-grep --pattern 'export function goForward() { $$$ }'
ast-grep --pattern 'export function removeCurrentMove() { $$$ }'

echo "Checking icon definitions..."
ast-grep --pattern 'export enum IconType { $$$ }'

Length of output: 3646


Script:

#!/bin/bash
# Let's check the store implementation and usage in MobileControls.vue
echo "Checking store implementation..."
rg -A 5 "export const useStore" src/renderer/store/

echo "Checking MobileControls.vue usage..."
rg -A 10 "useStore" src/renderer/view/main/MobileControls.vue

Length of output: 647


Script:

#!/bin/bash
# Let's check the store implementation for navigation methods
echo "Checking store implementation for navigation methods..."
rg -A 5 "export function (changePly|goBack|goForward|removeCurrentMove)" src/renderer/store/

# Let's also check how these methods are used in MobileControls.vue
echo "Checking method usage in MobileControls.vue..."
rg "(changePly|goBack|goForward|removeCurrentMove)" src/renderer/view/main/MobileControls.vue

Length of output: 694

src/renderer/view/main/MobileLayout.vue (3)

78-78: Verify lazyUpdateDelay value through performance testing

The current delay of 80ms for lazy updates should be validated through performance testing on various mobile devices to ensure smooth resizing without unnecessary re-renders.

#!/bin/bash
# Search for other uses of Lazy helper to compare delay values
rg -A 2 'new Lazy\(\)'

Line range hint 1-63: Verify mobile-specific configurations

Since this is a mobile layout component, please ensure:

  1. The parent HTML file includes proper viewport meta tags
  2. Touch events are properly handled (e.g., touch-action CSS property)
  3. Testing is performed on various mobile browsers
#!/bin/bash
# Check for viewport meta tags in HTML files
rg -l 'viewport' --glob '*.html'

# Check for touch event handlers
rg 'touch' --glob '*.vue'

7-7: Verify BoardLayoutType threshold values for different layouts

The layout type selection logic uses specific aspect ratio thresholds (0.5 and 1.6) to determine the appropriate layout. Please verify these values through testing on various mobile devices to ensure optimal layout transitions.

Also applies to: 107-116

✅ Verification successful

Let me try a different search pattern to find the BoardLayoutType usage.


Based on the search results, I can see that BoardLayoutType is an enum defined in src/common/settings/layout.ts with three values:

  • STANDARD
  • COMPACT
  • PORTRAIT

The layout selection logic in MobileLayout.vue uses aspect ratio thresholds to determine the appropriate layout:

  • If width < height * 0.5 -> PORTRAIT
  • If width < height * 1.6 -> PORTRAIT
  • Otherwise -> COMPACT

These thresholds appear to be carefully chosen to provide good breakpoints for mobile layouts. The STANDARD layout is not used in mobile mode.

Let me generate the final response:

Layout thresholds are appropriate for mobile view

The aspect ratio thresholds (0.5 and 1.6) used for mobile layout selection are well-chosen:

  • Very narrow screens (width/height < 0.5) use PORTRAIT layout
  • Moderately narrow screens (width/height < 1.6) use PORTRAIT layout
  • Wider screens use COMPACT layout

The STANDARD layout is intentionally excluded from mobile view as it's not optimized for small screens.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other uses of BoardLayoutType to ensure consistency
ast-grep --pattern 'BoardLayoutType.$$$'

Length of output: 608


Script:

#!/bin/bash
# Search for BoardLayoutType enum definition and usage
rg -A 5 "BoardLayoutType" 

# Also search for layout type related code
rg -A 5 "layoutType|layout-type"

Length of output: 321270

src/renderer/store/record.ts (4)

301-302: LGTM! New type definitions are clear and consistent.

The new type definitions for UpdateCommentHandler and UpdateBookmarkHandler follow the existing pattern and are well-defined.


798-819: LGTM! Event handler registration is well-implemented.

The new event handler overloads and implementation in the on method follow the existing pattern consistently.


840-851: Add unit tests for new event trigger methods.

The new event trigger methods onUpdateComment and onUpdateBookmark lack test coverage. Consider adding tests to verify:

  • Handlers are called when events are triggered
  • Handlers are not called when undefined
#!/bin/bash
# Search for similar event handler tests to use as a template
rg -A 5 "describe.*event.*handler" --type test
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 842-843: src/renderer/store/record.ts#L842-L843
Added lines #L842 - L843 were not covered by tests


[warning] 847-850: src/renderer/store/record.ts#L847-L850
Added lines #L847 - L850 were not covered by tests


634-634: Add unit tests for comment and bookmark update methods.

The methods updateComment, updateBookmark, and appendComment trigger events that lack test coverage. Consider adding tests to verify:

  • Event handlers are called when updates occur
  • The _unsaved flag is set correctly
  • Comments and bookmarks are updated properly

Also applies to: 640-640, 663-663

src/renderer/store/index.ts (2)

159-164: Previous review comment about error handling and debouncing is still applicable.

The direct calls to saveRecordForWebApp without error handling or debouncing could lead to silent failures and performance issues.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 160-160: src/renderer/store/index.ts#L160
Added line #L160 was not covered by tests


[warning] 163-163: src/renderer/store/index.ts#L163
Added line #L163 was not covered by tests


159-164: Add test coverage for new event handlers.

The new event handlers for comment and bookmark updates lack test coverage, which could lead to undetected issues.

Run the following script to verify test coverage:

Would you like me to help generate unit tests for these event handlers?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 160-160: src/renderer/store/index.ts#L160
Added line #L160 was not covered by tests


[warning] 163-163: src/renderer/store/index.ts#L163
Added line #L163 was not covered by tests

Comment on lines +17 to +19
<button @click="isMobileMenuVisible = true">Menu</button>
</div>
<FileMenu v-if="isMobileMenuVisible" @close="isMobileMenuVisible = false" />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance menu button and dialog implementation.

The menu button and dialog implementation could be improved for better mobile UX and internationalization:

-      <button @click="isMobileMenuVisible = true">Menu</button>
+      <button 
+        @click="isMobileMenuVisible = true"
+        class="menu-button">
+        {{ $t('menu.title') }}
+      </button>
-    <FileMenu v-if="isMobileMenuVisible" @close="isMobileMenuVisible = false" />
+    <FileMenu 
+      v-if="isMobileMenuVisible" 
+      @close="isMobileMenuVisible = false"
+      class="mobile-menu" />

Add these styles:

.menu-button {
  font-weight: 500;
}
.menu-button:active {
  background-color: rgba(0, 0, 0, 0.1);
}
.mobile-menu {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1000;
}

Comment on lines +312 to +313
private updateCommentHandler: UpdateCommentHandler | null = null;
private updateBookmarkHandler: UpdateBookmarkHandler | null = null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider using undefined instead of null for handler initialization.

The new handler properties follow the existing pattern, but there's an opportunity to improve type safety.

- private updateCommentHandler: UpdateCommentHandler | null = null;
- private updateBookmarkHandler: UpdateBookmarkHandler | null = null;
+ private updateCommentHandler: UpdateCommentHandler | undefined = undefined;
+ private updateBookmarkHandler: UpdateBookmarkHandler | undefined = undefined;

This aligns with TypeScript best practices and the static analysis suggestion about avoiding confusing void types in unions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private updateCommentHandler: UpdateCommentHandler | null = null;
private updateBookmarkHandler: UpdateBookmarkHandler | null = null;
private updateCommentHandler: UpdateCommentHandler | undefined = undefined;
private updateBookmarkHandler: UpdateBookmarkHandler | undefined = undefined;
🧰 Tools
🪛 Biome

[error] 313-313: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (1)
src/renderer/view/main/MobileLayout.vue (1)

107-117: Document layout breakpoint ratios.

The layout type selection uses magic numbers (0.5 and 1.6) for aspect ratio breakpoints. Consider extracting these as named constants with documentation explaining their significance and how they were determined.

Example implementation:

+// Aspect ratio breakpoints for layout transitions
+const PORTRAIT_BREAKPOINT_BOTTOM = 0.5; // Switch to portrait when width < 50% of height
+const PORTRAIT_BREAKPOINT_SIDE = 1.6;   // Switch to portrait when width < 160% of height

 const boardLayoutType = computed(() => {
   if (showRecordViewOnBottom.value) {
-    return windowSize.width < windowSize.height * 0.5
+    return windowSize.width < windowSize.height * PORTRAIT_BREAKPOINT_BOTTOM
       ? BoardLayoutType.PORTRAIT
       : BoardLayoutType.COMPACT;
   } else {
-    return windowSize.width < windowSize.height * 1.6
+    return windowSize.width < windowSize.height * PORTRAIT_BREAKPOINT_SIDE
       ? BoardLayoutType.PORTRAIT
       : BoardLayoutType.COMPACT;
   }
 });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c72b00d and 86a3cc5.

📒 Files selected for processing (10)
  • index.html (1 hunks)
  • layout-manager.html (1 hunks)
  • prompt.html (1 hunks)
  • src/renderer/App.vue (1 hunks)
  • src/renderer/store/index.ts (1 hunks)
  • src/renderer/store/record.ts (6 hunks)
  • src/renderer/view/main/CustomLayout.vue (1 hunks)
  • src/renderer/view/main/MobileControls.vue (1 hunks)
  • src/renderer/view/main/MobileLayout.vue (2 hunks)
  • src/renderer/view/main/RecordPane.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • index.html
  • layout-manager.html
  • prompt.html
  • src/renderer/App.vue
  • src/renderer/view/main/CustomLayout.vue
  • src/renderer/view/main/RecordPane.vue
🧰 Additional context used
📓 Learnings (1)
src/renderer/view/main/MobileControls.vue (1)
Learnt from: sunfish-shogi
PR: sunfish-shogi/electron-shogi#982
File: src/renderer/view/main/MobileControls.vue:23-32
Timestamp: 2024-10-25T15:44:42.429Z
Learning: In Vue 3's `<script setup>` context, reactive variables declared are automatically cleaned up upon component unmounting, so manual cleanup in `onUnmounted` is unnecessary.
🪛 GitHub Check: codecov/patch
src/renderer/store/index.ts

[warning] 160-160: src/renderer/store/index.ts#L160
Added line #L160 was not covered by tests


[warning] 163-163: src/renderer/store/index.ts#L163
Added line #L163 was not covered by tests

src/renderer/store/record.ts

[warning] 640-640: src/renderer/store/record.ts#L640
Added line #L640 was not covered by tests


[warning] 842-843: src/renderer/store/record.ts#L842-L843
Added lines #L842 - L843 were not covered by tests


[warning] 847-850: src/renderer/store/record.ts#L847-L850
Added lines #L847 - L850 were not covered by tests

🪛 Biome
src/renderer/store/record.ts

[error] 313-313: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

🔇 Additional comments (7)
src/renderer/view/main/MobileControls.vue (1)

1-43: Verify mobile layout behavior across different orientations.

Let's ensure the component handles different mobile orientations and aspect ratios as mentioned in the PR objectives.

✅ Verification successful

Mobile layout implementation is properly handled

The component is well-integrated into a responsive mobile layout system:

  • MobileLayout.vue implements dynamic orientation handling through showRecordViewOnBottom computed property
  • Responsive sizing is managed through:
    • Dynamic control height calculation based on screen dimensions
    • Automatic layout switching between portrait and compact modes
    • Window resize event handling with debouncing
  • The controls maintain consistent sizing with width: 100% and proportional icon scaling at height: 68%

The implementation appropriately handles different mobile orientations and aspect ratios through computed properties and reactive window size monitoring.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for responsive design implementation across the codebase

# Test 1: Look for media queries handling different orientations
echo "Checking for orientation-specific styles..."
rg -l "orientation: (portrait|landscape)" --type css --type vue

# Test 2: Check for viewport meta tags
echo "Checking for viewport meta tags..."
rg -l "viewport" --type html

# Test 3: Look for responsive utilities or breakpoint definitions
echo "Checking for responsive utilities..."
rg -l "(sm|md|lg|xl):" --type vue --type css

Length of output: 834


Script:

#!/bin/bash
# Let's modify our search to handle Vue files correctly and check for responsive design patterns

# Check for orientation and responsive styles in all files
echo "Checking for orientation and responsive styles..."
rg -l "orientation:|@media" --type-add 'vue:*.vue' --type vue

# Check for mobile-specific class names and styles
echo "Checking mobile-specific patterns..."
rg -l "mobile|responsive|screen" --type-add 'vue:*.vue' --type vue

# Look specifically at the main layout file
echo "Checking main layout implementation..."
rg "class.*controls" --type-add 'vue:*.vue' --type vue -A 5

# Check for any existing mobile-specific components
echo "Finding mobile-specific components..."
fd -e vue -e js -e ts . | rg -i "mobile"

Length of output: 1818


Script:

#!/bin/bash
# Let's examine the mobile-specific components and their responsive handling

# Check SimpleBoardView.vue for its media queries
echo "Checking SimpleBoardView.vue media queries..."
rg "@media" src/renderer/view/primitive/SimpleBoardView.vue -A 3 -B 1

# Examine MobileLayout.vue to understand the overall mobile structure
echo "Checking MobileLayout.vue content..."
cat src/renderer/view/main/MobileLayout.vue

# Look for any responsive class definitions in style files
echo "Checking for responsive classes..."
rg "\.full|\.row|\.controls" --type-add 'vue:*.vue' --type vue -A 2

Length of output: 5694

src/renderer/view/main/MobileLayout.vue (1)

7-7: LGTM! Responsive layout implementation looks good.

The dynamic layout-type binding and conditional rendering of MobileControls component with appropriate height calculation enhances the mobile responsiveness.

Also applies to: 10-13

src/renderer/store/record.ts (4)

301-302: LGTM!

The new handler types follow the established pattern and are well-defined.


634-634: LGTM!

The handler calls are correctly placed after state updates in the respective methods.

Also applies to: 640-640, 663-663


798-816: Add test coverage for new event handlers.

The new event handler registration for updateComment and updateBookmark lacks test coverage. Consider adding tests to verify:

  1. Handler registration
  2. Event triggering
  3. Handler cleanup

312-313: 🛠️ Refactor suggestion

Consider using undefined instead of null for handler initialization.

Following TypeScript best practices and static analysis recommendations:

-  private updateCommentHandler: UpdateCommentHandler | null = null;
-  private updateBookmarkHandler: UpdateBookmarkHandler | null = null;
+  private updateCommentHandler: UpdateCommentHandler | undefined = undefined;
+  private updateBookmarkHandler: UpdateBookmarkHandler | undefined = undefined;

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome

[error] 313-313: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

src/renderer/store/index.ts (1)

159-164: ⚠️ Potential issue

Add error handling and test coverage for new event handlers.

The new event handlers for comments and bookmarks lack error handling and test coverage.

The previous review comment about adding error handling and debouncing is still valid. Additionally, please add test coverage for these new handlers to ensure their reliability.

Apply this diff to implement error handling:

 .on("updateComment", () => {
-  saveRecordForWebApp(this.record);
+  saveRecordForWebApp(this.record).catch((error) => {
+    useErrorStore().add("Failed to save comment update: " + error);
+  });
 })
 .on("updateBookmark", () => {
-  saveRecordForWebApp(this.record);
+  saveRecordForWebApp(this.record).catch((error) => {
+    useErrorStore().add("Failed to save bookmark update: " + error);
+  });
 })
#!/bin/bash
# Description: Check for test coverage of the new event handlers

# Test: Search for test files covering these handlers
rg -l "updateComment|updateBookmark" "src/**/*test*"
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 160-160: src/renderer/store/index.ts#L160
Added line #L160 was not covered by tests


[warning] 163-163: src/renderer/store/index.ts#L163
Added line #L163 was not covered by tests

Comment on lines +34 to +43
<style scoped>
.controls button {
font-size: 100%;
width: 100%;
height: 100%;
}
.controls button .icon {
height: 68%;
}
</style>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance mobile-specific styles.

The current styles could be improved for better mobile interaction:

 <style scoped>
 .controls button {
   font-size: 100%;
   width: 100%;
   height: 100%;
+  min-height: 44px; /* Ensure minimum tap target size */
+  touch-action: manipulation; /* Disable double-tap zoom */
+  transition: transform 0.1s ease;
 }
+
+.controls button:active {
+  transform: scale(0.95);
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
 .controls button .icon {
   height: 68%;
+  pointer-events: none; /* Prevent touch event issues on icons */
 }
 </style>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<style scoped>
.controls button {
font-size: 100%;
width: 100%;
height: 100%;
}
.controls button .icon {
height: 68%;
}
</style>
<style scoped>
.controls button {
font-size: 100%;
width: 100%;
height: 100%;
min-height: 44px; /* Ensure minimum tap target size */
touch-action: manipulation; /* Disable double-tap zoom */
transition: transform 0.1s ease;
}
.controls button:active {
transform: scale(0.95);
background-color: rgba(0, 0, 0, 0.1);
}
.controls button .icon {
height: 68%;
pointer-events: none; /* Prevent touch event issues on icons */
}
</style>

Comment on lines +23 to +32
<script setup lang="ts">
import { IconType } from "@/renderer/assets/icons";
import { useStore } from "@/renderer/store";
import Icon from "@/renderer/view/primitive/Icon.vue";
import FileMenu from "@/renderer/view/menu/FileMenu.vue";
import { ref } from "vue";

const store = useStore();
const isMobileMenuVisible = ref(false);
</script>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance type safety and store usage.

Consider improving type safety and store usage patterns:

 <script setup lang="ts">
 import { IconType } from "@/renderer/assets/icons";
-import { useStore } from "@/renderer/store";
+import type { Store } from "@/renderer/store";
+import { useStore } from "@/renderer/store";
 import Icon from "@/renderer/view/primitive/Icon.vue";
 import FileMenu from "@/renderer/view/menu/FileMenu.vue";
 import { ref } from "vue";
 
-const store = useStore();
+const store: Store = useStore();
 const isMobileMenuVisible = ref<boolean>(false);

Committable suggestion was skipped due to low confidence.

Comment on lines +3 to +18
<div class="full row controls">
<button @click="store.changePly(0)">
<Icon :icon="IconType.FIRST" />
</button>
<button @click="store.goBack()">
<Icon :icon="IconType.BACK" />
</button>
<button @click="store.goForward()">
<Icon :icon="IconType.NEXT" />
</button>
<button @click="store.changePly(Number.MAX_SAFE_INTEGER)">
<Icon :icon="IconType.LAST" />
</button>
<button @click="store.removeCurrentMove()"><Icon :icon="IconType.DELETE" /></button>
<button @click="isMobileMenuVisible = true">Menu</button>
</div>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance mobile touch interaction and semantic structure.

The controls section could benefit from improved mobile interaction and semantic structure:

  1. Add touch event handling for better mobile experience
  2. Use semantic HTML elements for navigation controls
-    <div class="full row controls">
+    <nav class="full row controls" role="navigation" aria-label="Game controls">
-      <button @click="store.changePly(0)">
+      <button 
+        @click="store.changePly(0)"
+        @touchstart.prevent="store.changePly(0)">
         <Icon :icon="IconType.FIRST" />
       </button>
-      <button @click="store.goBack()">
+      <button 
+        @click="store.goBack()"
+        @touchstart.prevent="store.goBack()">
         <Icon :icon="IconType.BACK" />
       </button>
       <!-- Similar changes for other buttons -->
-    </div>
+    </nav>

Committable suggestion was skipped due to low confidence.

Comment on lines +35 to +41
:value="commentEditorMode"
@change="
(value) => {
commentEditorMode = value;
}
"
/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix ref access in ToggleButton component.

The commentEditorMode is a ref but it's not being accessed correctly in the template. When using refs in template expressions, Vue automatically unwraps them, but in event handlers, you need to explicitly use .value.

Apply this diff to fix the ref access:

  <ToggleButton
    label="コメント編集モード"
    :height="toggleHeight"
    :value="commentEditorMode"
    @change="
      (value) => {
-       commentEditorMode = value;
+       commentEditorMode.value = value;
      }
    "
  />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
:value="commentEditorMode"
@change="
(value) => {
commentEditorMode = value;
}
"
/>
:value="commentEditorMode"
@change="
(value) => {
commentEditorMode.value = value;
}
"
/>

Comment on lines +79 to +81
const toggleHeight = 24;
const minRecordViewWidth = 300;
const minRecordViewHeight = 200;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider making toggle height responsive.

The toggleHeight is hardcoded to 24 pixels, which might not be optimal for all screen sizes and densities. Consider making it responsive similar to how controlPaneHeight is calculated.

Example implementation:

-const toggleHeight = 24;
+const toggleHeight = computed(() => Math.min(windowSize.height * 0.03, windowSize.width * 0.06));

Committable suggestion was skipped due to low confidence.

@sunfish-shogi sunfish-shogi merged commit 54ccc35 into main Oct 25, 2024
3 of 5 checks passed
@sunfish-shogi sunfish-shogi deleted the improve-mobile branch October 25, 2024 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant