Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 43 additions & 43 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,60 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
このファイルは、このリポジトリのコードを扱う際にClaude Code (claude.ai/code)に対するガイダンスを提供します。

## Development Commands
## 開発コマンド

- `yarn dev` - Start development mode with Vite
- `yarn build` - Build the extension (runs TypeScript compilation + Vite build)
- `yarn lint` - Run ESLint to check code quality
- `yarn zip` - Create a distributable extension zip file from the built dist folder
- `yarn dev` - Viteを使用した開発モードの開始
- `yarn build` - 拡張機能のビルド(TypeScriptコンパイル + Viteビルドを実行)
- `yarn lint` - ESLintを実行してコード品質をチェック
- `yarn zip` - ビルドされたdistフォルダから配布可能な拡張機能のzipファイルを作成

## Architecture Overview
## アーキテクチャ概要

This is a Chrome Extension (Manifest V3) called **Selection Command** that allows users to perform various actions on selected text on web pages.
これは**Selection Command**と呼ばれるChrome拡張機能(Manifest V3)で、ユーザーがWebページ上で選択したテキストに対してさまざまなアクションを実行できます。

### Key Components
### 主要コンポーネント

**Chrome Extension Structure:**
**Chrome拡張機能の構造:**

- `manifest.json` - Extension manifest defining permissions, content scripts, and background workers
- `src/background_script.ts` - Service worker handling extension lifecycle and background operations
- `src/content_script.tsx` - Main content script injected into web pages
- `src/options_page.tsx` - Extension options/settings page
- `manifest.json` - 権限、コンテンツスクリプト、バックグラウンドワーカーを定義する拡張機能マニフェスト
- `src/background_script.ts` - 拡張機能のライフサイクルとバックグラウンド操作を処理するサービスワーカー
- `src/content_script.tsx` - Webページに注入されるメインのコンテンツスクリプト
- `src/options_page.tsx` - 拡張機能のオプション/設定ページ

**Core Architecture:**
**コアアーキテクチャ:**

- **Actions** (`src/action/`) - Core functionality modules including background operations, popup handling, page actions, and command execution
- **Components** (`src/components/`) - React components organized by feature:
- `menu/` - Context menu and menu item components
- `option/` - Settings and configuration UI
- `pageAction/` - Page automation and recording components
- `result/` - Result display and popup components
- `ui/` - Reusable UI components (uses Radix UI)
- **Services** (`src/services/`) - Business logic and utilities including settings management, storage, analytics, and page action handling
- **Hooks** (`src/hooks/`) - Custom React hooks for state management and Chrome extension APIs
- **Actions** (`src/action/`) - バックグラウンド操作、ポップアップ処理、ページアクション、コマンド実行を含むコア機能モジュール
- **Components** (`src/components/`) - 機能別に整理されたReactコンポーネント:
- `menu/` - コンテキストメニューとメニューアイテムコンポーネント
- `option/` - 設定と構成UI
- `pageAction/` - ページ自動化と記録コンポーネント
- `result/` - 結果表示とポップアップコンポーネント
- `ui/` - 再利用可能なUIコンポーネント(Radix UIを使用)
- **Services** (`src/services/`) - 設定管理、ストレージ、分析、ページアクション処理を含むビジネスロジックとユーティリティ
- **Hooks** (`src/hooks/`) - 状態管理とChrome拡張機能APIのためのカスタムReactフック

**Key Features:**
**主要機能:**

- **Page Actions** - Record and replay browser automation sequences
- **Command Hub** - Web interface for sharing and discovering commands (separate Next.js app in `pages/`)
- **Context Menus** - Right-click actions on selected text
- **Settings Management** - Import/export configurations and user preferences
- **ページアクション** - ブラウザ自動化シーケンスの記録と再生
- **コマンドハブ** - コマンドの共有と発見のためのWebインターフェース(`pages/`内の独立したNext.jsアプリ)
- **コンテキストメニュー** - 選択したテキストに対する右クリックアクション
- **設定管理** - 構成とユーザー設定のインポート/エクスポート

### Technical Stack
### 技術スタック

- **Frontend**: React 18 with TypeScript
- **Build System**: Vite with `@crxjs/vite-plugin` for Chrome extension development
- **UI Components**: Shadcn
- **Form and Validation**: react-hook-form and zod
- **Styling**: CSS Modules + Tailwind CSS(ver.3)
- **State Management**: React hooks with Chrome extension storage APIs
- **Testing**: ESLint for code quality
- **フロントエンド**: React 18 with TypeScript
- **ビルドシステム**: Vite with `@crxjs/vite-plugin` for Chrome extension development
- **UIコンポーネント**: Shadcn
- **フォームとバリデーション**: react-hook-form and zod
- **スタイリング**: CSS Modules + Tailwind CSS(ver.3)
- **状態管理**: React hooks with Chrome extension storage APIs
- **テスト**: ESLint for code quality

### Project Structure Notes
### プロジェクト構造の注意事項

- The main extension code is in `src/`
- The command hub website is a separate Next.js application in `pages/`
- Extension supports internationalization with locale files in `public/_locales/`
- Uses Shadow DOM for content script styling isolation
- Implements Robula+ algorithm for robust XPath selector generation (`src/lib/robula-plus/`)
- メインの拡張機能コードは`src/`内にある
- コマンドハブのウェブサイトは`pages/`内の独立したNext.jsアプリケーション
- 拡張機能は`public/_locales/`のロケールファイルによる国際化をサポート
- コンテンツスクリプトのスタイリング分離にShadow DOMを使用
- 堅牢なXPathセレクター生成のためのRobula+アルゴリズムを実装(`src/lib/robula-plus/`
2 changes: 1 addition & 1 deletion public/_locales/de/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "Befehle definieren, die basierend auf dem ausgewählten Text ausgeführt werden sollen."
},
"Option_commands_desc_count": {
"message": " / 100 Einträge"
"message": " Einträge"
},
"Option_title": {
"message": "Titel"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "Define commands to execute based on selected text."
},
"Option_commands_desc_count": {
"message": " / 100 Records"
"message": " items"
},
"Option_title": {
"message": "Title"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/es/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "Definir comandos para ejecutar basados en el texto seleccionado."
},
"Option_commands_desc_count": {
"message": " / 100 Registros"
"message": " registros"
},
"Option_title": {
"message": "Título"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/fr/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "Définir des commandes à exécuter en fonction du texte sélectionné."
},
"Option_commands_desc_count": {
"message": " / 100 Enregistrements"
"message": " éléments"
},
"Option_title": {
"message": "Titre"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/hi/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "चयनित टेक्स्ट के आधार पर निष्पादित करने के लिए कमांड परिभाषित करता है।"
},
"Option_commands_desc_count": {
"message": " / 100 आइटम"
"message": " आइटम"
},
"Option_title": {
"message": "शीर्षक"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/id/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "Tentukan perintah untuk dieksekusi berdasarkan teks yang dipilih."
},
"Option_commands_desc_count": {
"message": " / 100 Catatan"
"message": " item"
},
"Option_title": {
"message": "Judul"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/it/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "Definisce i comandi da eseguire in base al testo selezionato."
},
"Option_commands_desc_count": {
"message": " / 100 elementi"
"message": " elementi"
},
"Option_title": {
"message": "Titolo"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/ja/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "選択したテキストを元に実行するコマンドを定義します。"
},
"Option_commands_desc_count": {
"message": " / 100 件"
"message": " 件"
},
"Option_title": {
"message": "タイトル"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/ko/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "선택한 텍스트를 기반으로 실행할 명령을 정의합니다."
},
"Option_commands_desc_count": {
"message": " / 100개 항목"
"message": " "
},
"Option_title": {
"message": "제목"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/ms/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "Tentukan arahan untuk dilaksanakan berdasarkan teks yang dipilih."
},
"Option_commands_desc_count": {
"message": " / 100 Rekod"
"message": " item"
},
"Option_title": {
"message": "Tajuk"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/pt_BR/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "Definir comandos para executar com base no texto selecionado."
},
"Option_commands_desc_count": {
"message": " / 100 Registros"
"message": " itens"
},
"Option_title": {
"message": "Título"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/pt_PT/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "Definir comandos para executar com base no texto selecionado."
},
"Option_commands_desc_count": {
"message": " / 100 Registos"
"message": " itens"
},
"Option_title": {
"message": "Título"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/ru/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "Определяет команды для выполнения на основе выбранного текста."
},
"Option_commands_desc_count": {
"message": " / 100 элементов"
"message": " элементов"
},
"Option_title": {
"message": "Название"
Expand Down
2 changes: 1 addition & 1 deletion public/_locales/zh_CN/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"message": "定义基于选中文本执行的命令。"
},
"Option_commands_desc_count": {
"message": " / 100个项目"
"message": " "
},
"Option_title": {
"message": "标题"
Expand Down
12 changes: 5 additions & 7 deletions src/components/Popup.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,29 @@
--background: var(--sc-bg-color-h) var(--sc-bg-color-s) var(--sc-bg-color-l);
--foreground: 222.2 47.4% 11.2%;
--border: var(--sc-bd-color-h) var(--sc-bd-color-s) var(--sc-bd-color-l);
--accent: var(--sc-bg-color-h) var(--sc-bg-color-s)
calc(var(--sc-bg-color-l) - 6%);
--accent: var(--sc-bg-color-h) var(--sc-bg-color-s) calc(var(--sc-bg-color-l) - 6%);
--accent-foreground: 224 71% 4%;
}

.popup[data-state='open'] {
.popup[data-state="open"] {
animation-duration: var(--sc-duration) !important;
}

.popup[data-state='closed'] {
.popup[data-state="closed"] {
animation-duration: 100ms !important;
}

.previewContainer {
position: relative;

& > div {
&>div {
transform: translate(0, 0) !important;
}
}

.previewLabel {
font-family: var(--font-monospace);
@apply font-mono text-gray-800;
font-size: 1.2rem;
color: #444;
}

.previewDescription {
Expand Down
33 changes: 17 additions & 16 deletions src/components/Popup.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useState, useEffect, createContext, forwardRef } from 'react'
import { Popover, PopoverContent, PopoverAnchor } from '@/components/ui/popover'
import { Menu } from '@/components/menu/Menu'
import { useUserSettings } from '@/hooks/useSetting'
import { useDetectStartup } from '@/hooks/useDetectStartup'
import { useTabCommandReceiver } from '@/hooks/useTabCommandReceiver'
import { hexToHsl, isMac, onHover, cn } from '@/lib/utils'
import { t } from '@/services/i18n'
import { STYLE_VARIABLE, EXIT_DURATION, SIDE, ALIGN } from '@/const'
import { useState, useEffect, createContext, forwardRef } from "react"
import { Popover, PopoverContent, PopoverAnchor } from "@/components/ui/popover"
import { Menu } from "@/components/menu/Menu"
import { useUserSettings } from "@/hooks/useSetting"
import { useDetectStartup } from "@/hooks/useDetectStartup"
import { useTabCommandReceiver } from "@/hooks/useTabCommandReceiver"
import { hexToHsl, isMac, onHover, cn } from "@/lib/utils"
import { t } from "@/services/i18n"
import { STYLE_VARIABLE, EXIT_DURATION, SIDE, ALIGN } from "@/const"

import css from './Popup.module.css'
import css from "./Popup.module.css"

export type PopupProps = {
positionElm: Element | null
Expand Down Expand Up @@ -46,7 +46,7 @@ export const Popup = forwardRef<HTMLDivElement, PopupProps>(
userSettings?.userStyles &&
userSettings.userStyles.reduce((acc: any, cur: any) => {
if (cur.value == null) return acc
if (cur.name === 'background-color' || cur.name === 'border-color') {
if (cur.name === "background-color" || cur.name === "border-color") {
const hsl = hexToHsl(cur.value)
return {
...acc,
Expand Down Expand Up @@ -116,9 +116,10 @@ export const Popup = forwardRef<HTMLDivElement, PopupProps>(
align={align}
sideOffset={sideOffset}
alignOffset={alignOffset}
className={cn(css.popup, isPreview && 'z-10')}
className={cn(css.popup, isPreview && "z-10 mt-2")}
style={userStyles}
onOpenAutoFocus={noFocus}
onCloseAutoFocus={noFocus}
{...onHover(handleOnHover, true)}
>
{!isContextMenu ? <Menu /> : null}
Expand All @@ -136,7 +137,7 @@ export function PreviewDesc(props: PopupProps) {
const { userSettings } = useUserSettings()
const key = userSettings?.startupMethod?.keyboardParam

const os = isMac() ? 'mac' : 'windows'
const os = isMac() ? "mac" : "windows"
const keyLabel = t(`Option_keyboardParam_${key}_${os}`)

return (
Expand All @@ -145,16 +146,16 @@ export function PreviewDesc(props: PopupProps) {
<span>Preview...</span>
</p>
{isContextMenu && (
<p className={css.previewDescription}>{t('previewOnContextMenu')}</p>
<p className={css.previewDescription}>{t("previewOnContextMenu")}</p>
)}
{!visible && isKeyboard && (
<p className={css.previewDescription}>
{t('previewOnKeyboard', [keyLabel])}
{t("previewOnKeyboard", [keyLabel])}
</p>
)}
{!visible && isLeftClickHold && (
<p className={css.previewDescription}>
{t('previewOnLeftClickHold', [keyLabel])}
{t("previewOnLeftClickHold", [keyLabel])}
</p>
)}
</>
Expand Down
Loading