Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
2 changes: 1 addition & 1 deletion website/client/.tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nodejs 22.14.0
nodejs 22.15.1
Comment thread
yamadashy marked this conversation as resolved.
58 changes: 56 additions & 2 deletions website/client/components/Home/TryItResultContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
import ace, { type Ace } from 'ace-builds';
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, Star } from 'lucide-vue-next';
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 { VAceEditor } from 'vue3-ace-editor';
import type { PackResult } from '../api/client';
import { copyToClipboard, downloadResult, formatTimestamp, getEditorOptions } from '../utils/resultViewer';
import {
canShareFiles,
copyToClipboard,
downloadResult,
formatTimestamp,
getEditorOptions,
shareResult,
} from '../utils/resultViewer';

ace.config.setModuleUrl('ace/theme/tomorrow', themeTomorrowUrl);
ace.config.setModuleUrl('ace/theme/tomorrow_night', themeTomorrowNightUrl);
Expand All @@ -20,6 +27,8 @@ const props = defineProps<{
}>();

const copied = ref(false);
const shared = ref(false);
const canShare = ref(canShareFiles());
const { isDark } = useData();
const editorInstance = ref<Ace.Editor | null>(null);

Expand Down Expand Up @@ -57,6 +66,19 @@ const handleDownload = (event: Event) => {
downloadResult(props.result.content, props.result.format, props.result);
};

const handleShare = async (event: Event) => {
event.preventDefault();
event.stopPropagation();

const success = await shareResult(props.result.content, props.result.format, props.result);
if (success) {
shared.value = true;
setTimeout(() => {
shared.value = false;
}, 2000);
}
};
Comment thread
yamadashy marked this conversation as resolved.

const handleEditorMount = (editor: Ace.Editor) => {
editorInstance.value = editor;
};
Expand Down Expand Up @@ -145,6 +167,16 @@ const supportMessage = computed(() => ({
<Download :size="16" />
Download
</button>
<div v-if="canShare" class="mobile-only" style="flex-basis: 100%"></div>
<button
Comment thread
yamadashy marked this conversation as resolved.
v-if="canShare"
class="action-button mobile-only"
@click="handleShare"
:class="{ shared }"
>
<Share :size="16" />
{{ shared ? 'Shared!' : 'Open with your app' }}
</button>
</div>
<div class="editor-container">
<VAceEditor
Expand Down Expand Up @@ -268,6 +300,7 @@ dd {

.output-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
padding: 12px;
background: var(--vp-c-bg);
Expand Down Expand Up @@ -298,6 +331,12 @@ dd {
border-color: var(--vp-c-brand-1);
}

.action-button.shared {
background: var(--vp-c-brand-1);
color: white;
border-color: var(--vp-c-brand-1);
}

.editor-container {
height: 100%;
width: 100%;
Expand Down Expand Up @@ -344,6 +383,11 @@ dd {
color: var(--vp-c-brand-1);
}

/* Hide mobile-only elements on desktop */
Comment thread
yamadashy marked this conversation as resolved.
Outdated
.mobile-only {
display: none;
}

@media (max-width: 768px) {
.content-wrapper {
grid-template-columns: 1fr;
Expand All @@ -367,5 +411,15 @@ dd {
.support-message {
max-width: 100%;
}

/* Show mobile-only elements on mobile */
.mobile-only {
display: inline-flex;
}

.metadata-panel {
max-height: 400px;
overflow-y: auto;
}
}
</style>
9 changes: 9 additions & 0 deletions website/client/components/utils/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const AnalyticsAction = {
// Output events
COPY_OUTPUT: 'copy_output',
DOWNLOAD_OUTPUT: 'download_output',
SHARE_OUTPUT: 'share_output',
} as const;

export type AnalyticsCategoryType = (typeof AnalyticsCategory)[keyof typeof AnalyticsCategory];
Expand Down Expand Up @@ -117,6 +118,14 @@ export const analyticsUtils = {
label: format,
});
},

trackShareOutput(format: string): void {
trackEvent({
category: AnalyticsCategory.OUTPUT,
action: AnalyticsAction.SHARE_OUTPUT,
label: format,
});
},
};

// Type definitions for window.gtag
Expand Down
32 changes: 32 additions & 0 deletions website/client/components/utils/resultViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,38 @@ export function downloadResult(content: string, format: string, result: PackResu
document.body.removeChild(a);
}

/**
* Handle sharing with Web Share API as text content
*/
export async function shareResult(content: string, format: string, result: PackResult): Promise<boolean> {
try {
const repoName = formatRepositoryName(result.metadata.repository);

const shareData = {
title: `Repomix Output - ${repoName}`,
text: content,
};

if (navigator.share) {
await navigator.share(shareData);
analyticsUtils.trackShareOutput(format);
return true;
}

return false;
} catch (err) {
console.error('Failed to share:', err);
return false;
}
}

/**
* Check if Web Share API is supported
*/
export function canShareFiles(): boolean {
return navigator.share && typeof navigator.share === 'function';
}
Comment thread
yamadashy marked this conversation as resolved.

/**
* Get Ace editor options
*/
Expand Down
3 changes: 2 additions & 1 deletion website/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"scripts": {
"docs:dev": "vitepress dev",
"docs:build": "vitepress build",
"docs:preview": "vitepress preview"
"docs:preview": "vitepress preview",
"lint": "tsc --noEmit"
},
"dependencies": {
"jszip": "^3.10.1",
Expand Down
1 change: 1 addition & 0 deletions website/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"scripts": {
"dev": "PORT=8080 tsx watch src/index.ts",
"build": "tsc",
"lint": "tsc --noEmit",
"start": "node dist/index.js",
"clean": "rimraf dist",
"cloud-deploy": "gcloud builds submit --config=cloudbuild.yaml ."
Expand Down
14 changes: 13 additions & 1 deletion website/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,19 @@ app.use('*', cloudLogger());
app.use(
'/*',
cors({
origin: ['http://localhost:5173', 'https://repomix.com', 'https://api.repomix.com', 'https://*.repomix.pages.dev'],
origin: (origin) => {
const allowedOrigins = ['http://localhost:5173', 'https://repomix.com', 'https://api.repomix.com'];

if (!origin || allowedOrigins.includes(origin)) {
return origin;
}

if (origin.endsWith('.repomix.pages.dev')) {
return origin;
}

return null;
Comment thread
yamadashy marked this conversation as resolved.
},
allowMethods: ['GET', 'POST', 'OPTIONS'],
allowHeaders: ['Content-Type'],
maxAge: 86400,
Expand Down