mirror of
https://github.com/yamadashy/repomix.git
synced 2025-06-11 00:25:54 +03:00
Merge pull request #641 from yamadashy/feat/website-open-tooltip
feat(website): Show 'Open with your app' button on desktop with tooltip
This commit is contained in:
143
CLAUDE.md
143
CLAUDE.md
@@ -2,6 +2,18 @@
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Important: Continuous Knowledge Updates
|
||||
|
||||
**ALWAYS update this CLAUDE.md file during development tasks when you learn:**
|
||||
- New project-specific patterns or conventions
|
||||
- Solutions to common problems or edge cases
|
||||
- Debugging techniques specific to this codebase
|
||||
- Tool usage patterns that improve efficiency
|
||||
- Review feedback patterns that could help future development
|
||||
- Architecture decisions and their rationale
|
||||
|
||||
**When to update:** Don't wait until task completion - update immediately when you discover useful knowledge that would benefit future development sessions. This ensures knowledge continuity across different coding sessions.
|
||||
|
||||
# Repomix Development Guide
|
||||
|
||||
Repomix is a tool that packs repository contents into single files optimized for AI consumption. It converts codebases into structured formats (XML, Markdown, Plain Text) with intelligent compression, security scanning, and token counting for LLM integration.
|
||||
@@ -92,7 +104,136 @@ Repomix is a tool that packs repository contents into single files optimized for
|
||||
- Proper error propagation through async/worker boundaries
|
||||
|
||||
## Git Workflow
|
||||
|
||||
### Pre-Commit Requirements (MANDATORY)
|
||||
**ALWAYS run these commands before every commit:**
|
||||
```bash
|
||||
npm run lint
|
||||
npm run test
|
||||
```
|
||||
|
||||
- **npm run lint**: Runs Biome formatter, TypeScript type checking, and Secretlint security scan
|
||||
- **npm run test**: Executes full test suite to ensure no regressions
|
||||
- **Never commit failing code**: Fix all lint errors and test failures before committing
|
||||
- **Use `--write` flag**: Biome will auto-fix formatting issues when possible
|
||||
|
||||
### Commit Message Format
|
||||
- Follow [Conventional Commits](https://www.conventionalcommits.org/) with scope: `type(scope): Description`
|
||||
- Write detailed commit messages focusing on the "why" rather than the "what"
|
||||
- Run `npm run lint && npm test` before committing changes
|
||||
- Examples: `feat(cli): Add new --no-progress flag`, `fix(security): Handle special characters in file paths`
|
||||
|
||||
## Pull Request Review Process
|
||||
|
||||
### Viewing PR Comments
|
||||
There are different types of comments in GitHub PRs that require different approaches to view:
|
||||
|
||||
**1. General PR Comments (in main conversation):**
|
||||
```bash
|
||||
gh pr view {PR_NUMBER} --comments
|
||||
```
|
||||
|
||||
**2. Specific Code Line Comments (Files changed tab):**
|
||||
```bash
|
||||
gh api repos/yamadashy/repomix/pulls/{PR_NUMBER}/comments --jq '.[] | {path: .path, line: .line, body: .body}'
|
||||
```
|
||||
|
||||
**3. Review Comments with Status:**
|
||||
```bash
|
||||
gh api repos/yamadashy/repomix/pulls/{PR_NUMBER}/reviews --jq '.[] | select(.state == "COMMENTED" or .state == "CHANGES_REQUESTED") | .body'
|
||||
```
|
||||
|
||||
### Automated Review Bots
|
||||
This repository uses several automated review tools:
|
||||
|
||||
- **CodeRabbit**: AI-powered code review with actionable suggestions
|
||||
- **Gemini Code Assist**: Google's AI code reviewer with severity ratings (High/Medium/Low)
|
||||
- **Copilot Pull Request Reviewer**: GitHub's automated review suggestions
|
||||
- **Codecov**: Test coverage analysis and reporting
|
||||
|
||||
### Responding to Review Feedback
|
||||
|
||||
**1. Address Technical Issues First:**
|
||||
- Fix high-priority issues (security, functionality, memory leaks)
|
||||
- Address medium-priority issues (UX, maintainability)
|
||||
- Consider low-priority suggestions for future improvements
|
||||
|
||||
**2. Commit Changes with Clear Messages:**
|
||||
```bash
|
||||
git commit -m "fix(scope): Address PR review feedback
|
||||
|
||||
- Fix specific issue 1 (reference commit/line if applicable)
|
||||
- Improve specific aspect 2
|
||||
- Address reviewer concern about X
|
||||
|
||||
🤖 Generated with [Claude Code](https://claude.ai/code)
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
**3. Respond to Reviewers:**
|
||||
- Use `gh pr comment {PR_NUMBER} --body "message"` for general responses
|
||||
- Reference specific commits that address issues: `Fixed in commit \`abc1234\``
|
||||
- Explain rationale for decisions when not implementing suggestions
|
||||
- Thank reviewers for their feedback
|
||||
|
||||
**4. Resolve Conversations (IMPORTANT!):**
|
||||
- **Always resolve addressed feedback** - this helps track progress and shows respect for reviewers
|
||||
- CodeRabbit: Use `@coderabbitai resolve` command in PR comments
|
||||
- Others: Respond with explanation, then let reviewers mark as resolved
|
||||
- GitHub Web UI: Use "Resolve conversation" button on Files changed tab
|
||||
- **Don't forget this step** - unresolved conversations can delay PR approval
|
||||
|
||||
### Common Review Issues and Solutions
|
||||
|
||||
**Vue.js/Frontend:**
|
||||
- Event listener cleanup: Use `onUnmounted()` instead of return functions in `onMounted()`
|
||||
- Disabled element events: Move event handlers to parent containers
|
||||
- CSS positioning: Consider `position: fixed` for tooltips to avoid parent overflow issues
|
||||
- Accessibility: Maintain ARIA labels and proper focus management
|
||||
|
||||
**Performance:**
|
||||
- Use `{ passive: true }` for scroll listeners
|
||||
- Implement proper cleanup for all event listeners
|
||||
- Consider debouncing/throttling for frequent events
|
||||
|
||||
**Code Quality:**
|
||||
- Remove duplicate CSS definitions
|
||||
- Use existing color schemes for consistency
|
||||
- Follow established patterns in the codebase
|
||||
- Maintain proper TypeScript typing
|
||||
|
||||
### Review Process Checklist
|
||||
|
||||
Before marking PR as ready for merge:
|
||||
|
||||
1. ✅ **Address all feedback** - Fix high/medium priority issues
|
||||
2. ✅ **Run linting and tests (MANDATORY)** - `npm run lint && npm test` - Must pass before committing
|
||||
3. ✅ **Commit with clear messages** - Reference what was fixed
|
||||
4. ✅ **Respond to reviewers** - Explain changes and decisions
|
||||
5. ✅ **Resolve conversations** - Mark addressed feedback as resolved
|
||||
6. ✅ **Update documentation** - If architectural changes were made
|
||||
|
||||
**Remember**: Resolving conversations shows that feedback has been addressed and helps maintainers track review progress. This is essential for efficient PR management.
|
||||
|
||||
## Knowledge Management & Continuous Improvement
|
||||
|
||||
### Document Learning During Development
|
||||
|
||||
**Key principle:** Update CLAUDE.md immediately when discovering useful patterns, not at the end of tasks.
|
||||
|
||||
**Examples of knowledge worth documenting:**
|
||||
- **Project quirks**: "Website uses `position: fixed` for tooltips due to parent `overflow: hidden`"
|
||||
- **Tool discoveries**: "Use `gh api` for line-specific PR comments, `gh pr view --comments` for general ones"
|
||||
- **Debug techniques**: "Check `canShareFiles()` implementation when Web Share API behaves unexpectedly"
|
||||
- **Performance patterns**: "Always use `{ passive: true }` for scroll listeners in Vue components"
|
||||
- **Architecture insights**: "tooltip-container pattern prevents disabled button event issues"
|
||||
|
||||
### Maintaining This File
|
||||
|
||||
- **Be specific**: Instead of "fix tooltip issues", write "move mouseenter to container for disabled buttons"
|
||||
- **Include context**: Explain *why* a solution works, not just *what* to do
|
||||
- **Reference locations**: Include file paths and line numbers when relevant
|
||||
- **Update immediately**: Don't batch updates - add knowledge as you learn it
|
||||
- **Cross-reference**: Link related sections (e.g., PR review patterns ↔ Vue.js best practices)
|
||||
|
||||
This file is a living document that should grow with every development session, ensuring no valuable knowledge is lost between tasks.
|
||||
|
||||
@@ -4,7 +4,7 @@ import themeTomorrowUrl from 'ace-builds/src-noconflict/theme-tomorrow?url';
|
||||
import themeTomorrowNightUrl from 'ace-builds/src-noconflict/theme-tomorrow_night?url';
|
||||
import { BarChart2, Copy, Download, GitFork, HeartHandshake, PackageSearch, Share, Star } from 'lucide-vue-next';
|
||||
import { useData } from 'vitepress';
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import { VAceEditor } from 'vue3-ace-editor';
|
||||
import type { PackResult } from '../api/client';
|
||||
import {
|
||||
@@ -31,6 +31,9 @@ const shared = ref(false);
|
||||
const canShare = ref(canShareFiles());
|
||||
const { isDark } = useData();
|
||||
const editorInstance = ref<Ace.Editor | null>(null);
|
||||
const isMobile = ref(false);
|
||||
const tooltipContainer = ref<HTMLElement | null>(null);
|
||||
const tooltipContent = ref<HTMLElement | null>(null);
|
||||
|
||||
const editorOptions = computed(() => ({
|
||||
...getEditorOptions(),
|
||||
@@ -70,6 +73,12 @@ const handleShare = async (event: Event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// Only allow sharing on mobile devices with Web Share API support
|
||||
if (!isMobile.value || !canShare.value) {
|
||||
console.log('Share is only available on mobile devices');
|
||||
return;
|
||||
}
|
||||
|
||||
const success = await shareResult(props.result.content, props.result.format, props.result);
|
||||
if (success) {
|
||||
shared.value = true;
|
||||
@@ -85,6 +94,28 @@ const handleEditorMount = (editor: Ace.Editor) => {
|
||||
editorInstance.value = editor;
|
||||
};
|
||||
|
||||
const updateTooltipPosition = () => {
|
||||
if (!tooltipContainer.value || !tooltipContent.value || isMobile.value) return;
|
||||
|
||||
const containerRect = tooltipContainer.value.getBoundingClientRect();
|
||||
const tooltipEl = tooltipContent.value;
|
||||
|
||||
// Position above the button with proper spacing for the arrow (like existing tooltips)
|
||||
tooltipEl.style.top = `${containerRect.top - 46}px`;
|
||||
tooltipEl.style.left = `${containerRect.left + containerRect.width / 2}px`;
|
||||
|
||||
// Show tooltip (override CSS hover states)
|
||||
tooltipEl.style.opacity = '1';
|
||||
tooltipEl.style.visibility = 'visible';
|
||||
};
|
||||
|
||||
const hideTooltip = () => {
|
||||
if (tooltipContent.value) {
|
||||
tooltipContent.value.style.opacity = '0';
|
||||
tooltipContent.value.style.visibility = 'hidden';
|
||||
}
|
||||
};
|
||||
|
||||
const messages = [
|
||||
{
|
||||
type: 'sponsor',
|
||||
@@ -110,6 +141,29 @@ const supportMessage = computed(() => ({
|
||||
text: messages[currentMessageIndex.value].text,
|
||||
color: messages[currentMessageIndex.value].color,
|
||||
}));
|
||||
|
||||
const handleResize = () => {
|
||||
isMobile.value = window.innerWidth <= 768;
|
||||
};
|
||||
|
||||
const handleScroll = () => {
|
||||
// Hide tooltip on scroll to prevent detachment from button
|
||||
if (tooltipContent.value) {
|
||||
tooltipContent.value.style.opacity = '0';
|
||||
tooltipContent.value.style.visibility = 'hidden';
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
isMobile.value = window.innerWidth <= 768;
|
||||
window.addEventListener('resize', handleResize);
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -170,16 +224,22 @@ const supportMessage = computed(() => ({
|
||||
Download
|
||||
</button>
|
||||
<div v-if="canShare" class="mobile-only" style="flex-basis: 100%"></div>
|
||||
<button
|
||||
v-if="canShare"
|
||||
class="action-button mobile-only"
|
||||
@click="handleShare"
|
||||
:class="{ shared }"
|
||||
aria-label="Share output via mobile apps"
|
||||
>
|
||||
<Share :size="16" />
|
||||
{{ shared ? 'Shared!' : 'Open with your app' }}
|
||||
</button>
|
||||
<div v-if="canShare" class="tooltip-container" ref="tooltipContainer" @mouseenter="updateTooltipPosition" @mouseleave="hideTooltip">
|
||||
<button
|
||||
class="action-button"
|
||||
@click="handleShare"
|
||||
:class="{ shared }"
|
||||
:disabled="!isMobile"
|
||||
aria-label="Share output via mobile apps"
|
||||
>
|
||||
<Share :size="16" />
|
||||
{{ shared ? 'Shared!' : 'Open with your app' }}
|
||||
</button>
|
||||
<div class="tooltip-content desktop-only" ref="tooltipContent">
|
||||
Only available on mobile devices
|
||||
<div class="tooltip-arrow"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-container">
|
||||
<VAceEditor
|
||||
@@ -420,4 +480,71 @@ dd {
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip-container {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.tooltip-content {
|
||||
position: fixed;
|
||||
transform: translateX(-50%);
|
||||
margin-bottom: 8px;
|
||||
padding: 8px 12px;
|
||||
background: #333;
|
||||
color: white;
|
||||
font-size: 0.875rem;
|
||||
white-space: nowrap;
|
||||
border-radius: 4px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.2s, visibility 0.2s;
|
||||
z-index: 9999;
|
||||
pointer-events: none;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-width: 8px;
|
||||
border-style: solid;
|
||||
border-color: #333 transparent transparent transparent;
|
||||
}
|
||||
|
||||
.tooltip-container:hover .tooltip-content {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.desktop-only {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.desktop-only {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.action-button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.action-button:disabled:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* Dark mode support for tooltip */
|
||||
html.dark .tooltip-content {
|
||||
background: #333;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
html.dark .tooltip-arrow {
|
||||
border-color: #333 transparent transparent transparent;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user