improve ui

This commit is contained in:
f 2025-02-05 02:54:53 +03:00
parent 7c68845eb0
commit ffcfd9c074
9 changed files with 3017 additions and 1307 deletions

View File

@ -1,15 +1,20 @@
# Add New Prompt
You'll need to add your prompt into README.md, and to the `prompts.csv` file. If your prompt includes quotes, you will need to double-quote them to escape in CSV file.
You'll need to add your prompt into README.md, and to the `prompts.csv` file. If
your prompt includes quotes, you will need to double-quote them to escape in CSV
file.
If the prompt is generated by AI, please add `<mark>Generated by AI</mark>` to the end of the contribution line.
If the prompt is generated by AI, please add `<mark>Generated by AI</mark>` to
the end of the contribution line.
- [ ] I've confirmed the prompt works well
- [ ] I've added `Contributed by: [@yourusername](https://github.com/yourusername)`
- [ ] I've added
`Contributed by: [@yourusername](https://github.com/yourusername)`
- [ ] I've added to the README.md
- [ ] I've added to the `prompts.csv`
- [ ] Escaped quotes by double-quoting them
- [ ] No spaces after commas after double quotes. e.g. `"Hello","hi"`, not `"Hello", "hi"`
- [ ] No spaces after commas after double quotes. e.g. `"Hello","hi"`, not
`"Hello", "hi"`
- [ ] Removed "Act as" from the title on CSV
Please make sure you've completed all the checklist.

View File

@ -33,7 +33,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
node-version: "18"
- name: Install dependencies
run: npm install openai@^4.0.0 @octokit/rest@^19.0.0
@ -52,7 +52,7 @@ jobs:
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
});
const octokit = new Octokit({
auth: process.env.GH_TOKEN
});
@ -60,7 +60,7 @@ jobs:
const eventName = process.env.GITHUB_EVENT_NAME;
const eventPath = process.env.GITHUB_EVENT_PATH;
const event = require(eventPath);
// Double check user authorization
const actor = event.sender?.login || event.pull_request?.user?.login || event.issue?.user?.login;
if (actor !== 'f') {
@ -72,7 +72,7 @@ jobs:
let command = '';
let issueNumber = null;
let isPullRequest = false;
if (eventName === 'issues') {
command = event.issue.body;
issueNumber = event.issue.number;
@ -96,7 +96,7 @@ jobs:
// Extract the actual command after /ai
const aiCommand = command.substring(3).trim();
// Handle resolve conflicts command
if (aiCommand === 'resolve' || aiCommand === 'fix conflicts') {
if (!isPullRequest) {
@ -112,7 +112,7 @@ jobs:
try {
console.log('Starting resolve command execution...');
// Get PR details
console.log('Fetching PR details...');
const { data: pr } = await octokit.pulls.get({
@ -140,7 +140,7 @@ jobs:
title = title.trim();
// Remove "Act as" or "Act as a" or "Act as an" from start if present
title = title.replace(/^Act as (?:a |an )?/i, '');
// Capitalize each word except common articles and prepositions
const lowercaseWords = ['a', 'an', 'the', 'and', 'but', 'or', 'for', 'nor', 'on', 'at', 'to', 'for', 'with', 'in'];
const capitalized = title.toLowerCase().split(' ').map((word, index) => {
@ -150,7 +150,7 @@ jobs:
}
return word;
}).join(' ');
// Add "Act as" prefix
return `Act as ${capitalized}`;
};
@ -168,17 +168,17 @@ jobs:
console.log('Attempting to extract prompts from README changes...');
const promptMatches = [...addedLines.matchAll(/## (?:Act as (?:a |an )?)?([^\n]+)\n(?:Contributed by:[^\n]*\n)?(?:> )?([^#]+?)(?=\n##|\n\n##|$)/ig)];
for (const match of promptMatches) {
const actName = normalizeTitle(match[1]);
const promptText = match[2].trim()
.replace(/^(?:Contributed by:?[^\n]*\n\s*)+/i, '')
.trim();
const contributorLine = addedLines.match(/Contributed by: \[@([^\]]+)\]\(https:\/\/github\.com\/([^\)]+)\)/);
const contributorInfo = contributorLine
const contributorInfo = contributorLine
? `Contributed by: [@${contributorLine[1]}](https://github.com/${contributorLine[2]})`
: `Contributed by: [@${pr.user.login}](https://github.com/${pr.user.login})`;
prompts.set(actName.toLowerCase(), { actName, promptText, contributorInfo });
console.log(`Found prompt in README: "${actName}"`);
foundInReadme = true;
@ -206,7 +206,7 @@ jobs:
const promptText = matches[1][1].replace(/""/g, '"').trim()
.replace(/^(?:Contributed by:?[^\n]*\n\s*)+/i, '')
.trim();
const contributorInfo = `Contributed by: [@${pr.user.login}](https://github.com/${pr.user.login})`;
prompts.set(actName.toLowerCase(), { actName, promptText, contributorInfo });
console.log(`Found prompt in CSV: "${actName}"`);
@ -256,16 +256,16 @@ jobs:
for (const { actName, promptText, contributorInfo } of promptsArray) {
// Remove markdown quote character and trim whitespace
const cleanPrompt = promptText.replace(/^>\s*/gm, '').trim();
// For README: Add quote to each line
const readmePrompt = cleanPrompt.split('\n')
.map(line => `> ${line.trim()}`)
.join('\n');
const newSection = `## ${actName}\n${contributorInfo}\n\n${readmePrompt}\n\n`;
// For CSV: Convert to single paragraph
const csvPrompt = cleanPrompt.replace(/\n+/g, ' ').trim();
// Insert the new section before Contributors in README
const contributorsIndex = readmeContent.indexOf('## Contributors');
if (contributorsIndex === -1) {
@ -483,13 +483,13 @@ jobs:
if (file.status === 'removed') {
return `Deleted: ${file.filename}`;
}
// Get file content for added or modified files
if (file.status === 'added' || file.status === 'modified') {
const patch = file.patch || '';
return `${file.status === 'added' ? 'Added' : 'Modified'}: ${file.filename}\nChanges:\n${patch}`;
}
return `${file.status}: ${file.filename}`;
}));
@ -551,7 +551,7 @@ jobs:
// If response contains code changes, create a new branch and PR
if (response.includes('```')) {
const branchName = `ai-bot/fix-${issueNumber}`;
// Create new branch
const defaultBranch = event.repository.default_branch;
const ref = await octokit.git.getRef({
@ -559,7 +559,7 @@ jobs:
repo: event.repository.name,
ref: `heads/${defaultBranch}`
});
await octokit.git.createRef({
owner: event.repository.owner.login,
repo: event.repository.name,
@ -572,7 +572,7 @@ jobs:
for (const block of codeBlocks) {
const [_, filePath, ...codeLines] = block.split('\n');
const content = Buffer.from(codeLines.join('\n')).toString('base64');
await octokit.repos.createOrUpdateFileContents({
owner: event.repository.owner.login,
repo: event.repository.name,
@ -620,4 +620,4 @@ jobs:
repo: context.repo.repo,
issue_number: issueNumber,
body: '❌ Sorry, there was an error processing your command. Please try again or contact the repository maintainers.'
});
});

View File

@ -19,7 +19,7 @@ jobs:
with:
script: |
const pr = context.payload.pull_request;
// Check if PR has conflicts
if (pr.mergeable === false) {
console.log('PR has conflicts, commenting /ai resolve');
@ -30,7 +30,7 @@ jobs:
body: '/ai resolve'
});
}
// Check if PR title starts with "updated"
if (pr.title.toLowerCase().startsWith('updated')) {
console.log('PR title starts with "updated", commenting /ai suggest title');
@ -40,4 +40,4 @@ jobs:
issue_number: pr.number,
body: '/ai suggest title'
});
}
}

View File

@ -8,70 +8,70 @@ jobs:
lint_and_check_trailing_whitespaces:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install csvkit
- name: Validate CSV structure
run: |
echo "Checking CSV structure..."
if ! csvclean -n prompts.csv 2>&1 | tee /tmp/csv_errors.log; then
echo "::error::CSV validation failed"
cat /tmp/csv_errors.log
exit 1
fi
- name: Check CSV format
run: |
echo "Checking CSV format..."
if ! python -c '
import csv
with open("prompts.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
headers = next(reader)
if headers != ["act", "prompt"]:
print("Error: CSV headers must be exactly [act, prompt]")
exit(1)
for row_num, row in enumerate(reader, 2):
if len(row) != 2:
print(f"Error: Row {row_num} has {len(row)} columns, expected 2")
exit(1)
if not row[0] or not row[1]:
print(f"Error: Row {row_num} has empty values")
exit(1)
'; then
echo "::error::CSV format check failed"
exit 1
fi
- name: Check Trailing Whitespaces
run: |
echo "Checking for trailing whitespaces..."
if grep -q "[[:space:]]$" prompts.csv; then
echo "::error::Found trailing whitespaces in prompts.csv"
grep -n "[[:space:]]$" prompts.csv | while read -r line; do
echo "Line with trailing whitespace: $line"
done
exit 1
fi
echo "No trailing whitespaces found"
- name: Check for UTF-8 BOM and line endings
run: |
echo "Checking for UTF-8 BOM and line endings..."
if file prompts.csv | grep -q "with BOM"; then
echo "::error::File contains UTF-8 BOM marker"
exit 1
fi
if file prompts.csv | grep -q "CRLF"; then
echo "::error::File contains Windows-style (CRLF) line endings"
exit 1
fi
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.8"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install csvkit
- name: Validate CSV structure
run: |
echo "Checking CSV structure..."
if ! csvclean -n prompts.csv 2>&1 | tee /tmp/csv_errors.log; then
echo "::error::CSV validation failed"
cat /tmp/csv_errors.log
exit 1
fi
- name: Check CSV format
run: |
echo "Checking CSV format..."
if ! python -c '
import csv
with open("prompts.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
headers = next(reader)
if headers != ["act", "prompt"]:
print("Error: CSV headers must be exactly [act, prompt]")
exit(1)
for row_num, row in enumerate(reader, 2):
if len(row) != 2:
print(f"Error: Row {row_num} has {len(row)} columns, expected 2")
exit(1)
if not row[0] or not row[1]:
print(f"Error: Row {row_num} has empty values")
exit(1)
'; then
echo "::error::CSV format check failed"
exit 1
fi
- name: Check Trailing Whitespaces
run: |
echo "Checking for trailing whitespaces..."
if grep -q "[[:space:]]$" prompts.csv; then
echo "::error::Found trailing whitespaces in prompts.csv"
grep -n "[[:space:]]$" prompts.csv | while read -r line; do
echo "Line with trailing whitespace: $line"
done
exit 1
fi
echo "No trailing whitespaces found"
- name: Check for UTF-8 BOM and line endings
run: |
echo "Checking for UTF-8 BOM and line endings..."
if file prompts.csv | grep -q "with BOM"; then
echo "::error::File contains UTF-8 BOM marker"
exit 1
fi
if file prompts.csv | grep -q "CRLF"; then
echo "::error::File contains Windows-style (CRLF) line endings"
exit 1
fi

View File

@ -16,7 +16,7 @@ jobs:
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
ruby-version: "3.2"
bundler-cache: true # This will cache dependencies
- name: Update Bundler

View File

@ -1,42 +1,66 @@
# Contribution Guidelines
Before contributing to this repository, please ensure you are adhering to the following general guidelines. Further, if you are submitting a new prompt to the repository, be sure you are also following the prompt-specific guidelines. These checks will ensure that your contributions can be easily integrated into the main repository, without any headache for the owners.
Before contributing to this repository, please ensure you are adhering to the
following general guidelines. Further, if you are submitting a new prompt to the
repository, be sure you are also following the prompt-specific guidelines. These
checks will ensure that your contributions can be easily integrated into the
main repository, without any headache for the owners.
## General Guidelines
The following guidelines should be followed when making any open-source contributions:
- [ ] Contributions should be made via a pull request to the main repository from a personal fork.
- [ ] Pull requests should be accompanied by a descriptive title and detailed explanation.
The following guidelines should be followed when making any open-source
contributions:
- [ ] Contributions should be made via a pull request to the main repository
from a personal fork.
- [ ] Pull requests should be accompanied by a descriptive title and detailed
explanation.
- [ ] Submit all pull requests to the repository's main branch.
- [ ] Before submitting a pull request, ensure additions/edits are aligned with the overall repo organization.
- [ ] Before submitting a pull request, ensure additions/edits are aligned with
the overall repo organization.
- [ ] Be sure changes are compatible with the repository's license.
- [ ] In case of conflicts, provide helpful explanations regarding your proposed changes so that they can be approved by repo owners.
- [ ] In case of conflicts, provide helpful explanations regarding your proposed
changes so that they can be approved by repo owners.
## New Prompt Guidelines
To add a new prompt to this repository, a contributor should take the following steps (in their personal fork):
To add a new prompt to this repository, a contributor should take the following
steps (in their personal fork):
1. Create and test the new prompt.
- See the [README](https://github.com/f/awesome-chatgpt-prompts/blob/main/README.md) for guidance on how to write effective prompts.
- Ensure prompts generate intended results and can be used by other users to replicate those results.
- See the
[README](https://github.com/f/awesome-chatgpt-prompts/blob/main/README.md)
for guidance on how to write effective prompts.
- Ensure prompts generate intended results and can be used by other users to
replicate those results.
2. Add the prompt to `README.md` using the following markdown template:
`## Prompt Title`
`## Prompt Title`
`Contributed by: [@github_username](https://github.com/github_profile)`
`Contributed by: [@github_username](https://github.com/github_profile)`
`> prompt content`
`> prompt content`
- <b>Note:</b> If your prompt was generated by ChatGPT, append `<mark>Generated by ChatGPT</mark>` to the "Contributed by" line.
- <b>Note:</b> If your prompt was generated by ChatGPT, append
`<mark>Generated by ChatGPT</mark>` to the "Contributed by" line.
3. Add the prompt to `prompts.csv`.
- Put the prompt title in the `act` column, and the prompt itself in the `prompt` column.
- Put the prompt title in the `act` column, and the prompt itself in the
`prompt` column.
4. Submit a pull request on the repository's main branch.
- If possible, provide some documentation of how you tested your prompt and the kinds of results you received.
- Be sure to include a detailed title and description.
- If possible, provide some documentation of how you tested your prompt and
the kinds of results you received.
- Be sure to include a detailed title and description.
### New Prompt Checklist:
- [ ] I've confirmed the prompt works well
- [ ] I've added `Contributed by: [@yourusername](https://github.com/yourusername)`
- [ ] I've added
`Contributed by: [@yourusername](https://github.com/yourusername)`
- [ ] I've added to the README.md
- [ ] I've added to the `prompts.csv`
- [ ] Escaped quotes by double-quoting them
- [ ] No spaces after commas after double quotes. e.g. `"act","prompt"` not `"act", "prompt"`
- [ ] No spaces after commas after double quotes. e.g. `"act","prompt"` not
`"act", "prompt"`
- [ ] Removed "Act as" from the title on CSV
Please ensure these requirements are met before submitting a pull request.

2374
README.md

File diff suppressed because it is too large Load Diff

View File

@ -318,6 +318,12 @@
transition: transform 0.3s ease;
}
/* Blinking cursor animation for development mode */
@keyframes blink-cursor {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
.site-slogan {
font-size: 0.9rem;
opacity: 0.7;
@ -1183,7 +1189,7 @@
border-radius: 12px;
padding: 32px;
width: 90%;
max-width: 460px;
max-width: 520px;
z-index: 1002;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.2);
display: none;
@ -1194,10 +1200,22 @@
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}
.prompts-count-label {
display: none;
}
.dev-mode .count-label {
display: none;
}
.dev-mode .prompts-count-label {
display: block;
}
.copilot-suggestion-content {
margin-bottom: 24px;
color: var(--text-color-light);
font-size: 1rem;
font-size: 1.1rem;
line-height: 1.5;
}
@ -1219,6 +1237,7 @@
font-size: 0.9rem;
opacity: 0.8;
order: 2;
margin-top: 8px;
}
.dark-mode .copilot-suggestion-checkbox {
@ -1229,23 +1248,30 @@
width: 16px;
height: 16px;
accent-color: var(--accent-color);
cursor: pointer;
margin: 0;
}
.copilot-suggestion-checkbox:hover {
opacity: 1;
}
.copilot-suggestion-buttons {
display: flex;
flex-direction: column;
gap: 12px;
order: 1;
}
.copilot-suggestion-button {
padding: 10px 16px;
padding: 12px 16px;
border-radius: 8px;
font-size: 0.95rem;
border: none;
cursor: pointer;
transition: all 0.2s ease;
flex: 1;
font-weight: 500;
width: 100%;
}
.copilot-suggestion-button.primary {
@ -1281,15 +1307,17 @@
@media (max-width: 480px) {
.copilot-suggestion-modal {
padding: 24px;
max-width: 100%;
margin: 0 16px;
}
.copilot-suggestion-content {
font-size: 0.95rem;
font-size: 1rem;
margin-bottom: 20px;
}
.copilot-suggestion-button {
padding: 8px 14px;
padding: 10px 16px;
font-size: 0.9rem;
}
}
@ -1360,6 +1388,7 @@
<div class="search-container">
<div class="prompt-count" id="promptCount">
<span class="count-label">All Prompts</span>
<span class="prompts-count-label">Developer Prompts</span>
<span class="count-number">0</span>
</div>
<input type="text" id="searchInput" placeholder="Search prompts...">
@ -1442,800 +1471,7 @@
</div>
</footer>
</div>
<script>
// Dark mode functionality
function toggleDarkMode() {
const body = document.body;
const toggle = document.querySelector('.dark-mode-toggle');
const sunIcon = toggle.querySelector('.sun-icon');
const moonIcon = toggle.querySelector('.moon-icon');
body.classList.toggle('dark-mode');
const isDarkMode = body.classList.contains('dark-mode');
localStorage.setItem('dark-mode', isDarkMode);
sunIcon.style.display = isDarkMode ? 'none' : 'block';
moonIcon.style.display = isDarkMode ? 'block' : 'none';
}
// Initialize everything after DOM loads
document.addEventListener('DOMContentLoaded', () => {
// Initialize dev mode
const devModeToggle = document.getElementById('devModeToggle');
const initialDevMode = localStorage.getItem('dev-mode') === 'true';
devModeToggle.checked = initialDevMode;
// Initialize chat button icons
updateChatButtonIcons(initialDevMode);
// Handle dev mode toggle
devModeToggle.addEventListener('change', (e) => {
const newDevMode = e.target.checked;
localStorage.setItem('dev-mode', newDevMode);
// Update chat button icons
updateChatButtonIcons(newDevMode);
// Check if we should show Copilot suggestion
if (newDevMode) {
const currentPlatform = document.querySelector('.platform-tag.active');
const shouldNotShow = localStorage.getItem('copilot-suggestion-hidden') === 'true';
if (currentPlatform &&
currentPlatform.dataset.platform !== 'github-copilot' &&
!shouldNotShow) {
showCopilotSuggestion();
}
}
filterPrompts();
});
// Fetch GitHub stars
fetch('https://api.github.com/repos/f/awesome-chatgpt-prompts')
.then(response => response.json())
.then(data => {
const stars = data.stargazers_count;
document.getElementById('starCount').textContent = stars.toLocaleString();
})
.catch(error => {
console.error('Error fetching star count:', error);
document.getElementById('starCount').textContent = '50k+';
});
// Create prompt cards
createPromptCards();
// Initialize dark mode
const isDarkMode = localStorage.getItem('dark-mode');
const toggle = document.querySelector('.dark-mode-toggle');
const sunIcon = toggle.querySelector('.sun-icon');
const moonIcon = toggle.querySelector('.moon-icon');
// Set dark mode by default if not set
if (isDarkMode === null) {
localStorage.setItem('dark-mode', 'true');
document.body.classList.add('dark-mode');
sunIcon.style.display = 'none';
moonIcon.style.display = 'block';
} else if (isDarkMode === 'true') {
document.body.classList.add('dark-mode');
sunIcon.style.display = 'none';
moonIcon.style.display = 'block';
} else {
sunIcon.style.display = 'block';
moonIcon.style.display = 'none';
}
// Initialize search functionality
initializeSearch();
// Initialize chat button icons on page load
const isDevMode = localStorage.getItem('dev-mode') === 'true';
updateChatButtonIcons(isDevMode);
});
// Search functionality
async function initializeSearch() {
try {
const response = await fetch('/prompts.csv');
const csvText = await response.text();
const prompts = parseCSV(csvText);
// Sort prompts alphabetically by act
prompts.sort((a, b) => a.act.localeCompare(b.act));
const searchInput = document.getElementById('searchInput');
const searchResults = document.getElementById('searchResults');
const promptCount = document.getElementById('promptCount');
const isDevMode = document.getElementById('devModeToggle').checked;
// Update prompt count
const totalPrompts = isDevMode ? prompts.filter(p => p.for_devs === true).length : prompts.length;
updatePromptCount(totalPrompts, totalPrompts);
// Show filtered prompts initially
const filteredPrompts = isDevMode ? prompts.filter(p => p.for_devs === true) : prompts;
displaySearchResults(filteredPrompts);
searchInput.addEventListener('input', (e) => {
const searchTerm = e.target.value.toLowerCase();
const filteredPrompts = prompts.filter(prompt => {
const matchesSearch = prompt.act.toLowerCase().includes(searchTerm) ||
prompt.prompt.toLowerCase().includes(searchTerm);
return isDevMode ? (matchesSearch && prompt.for_devs === true) : matchesSearch;
});
// Update count with filtered results
const totalPrompts = isDevMode ? prompts.filter(p => p.for_devs === true).length : prompts.length;
updatePromptCount(filteredPrompts.length, totalPrompts);
displaySearchResults(filteredPrompts);
});
} catch (error) {
console.error('Error loading prompts:', error);
}
}
function updatePromptCount(filteredCount, totalCount) {
const promptCount = document.getElementById('promptCount');
const countLabel = promptCount.querySelector('.count-label');
const countNumber = promptCount.querySelector('.count-number');
if (filteredCount === totalCount) {
promptCount.classList.remove('filtered');
countLabel.textContent = 'All Prompts';
countNumber.textContent = totalCount;
} else {
promptCount.classList.add('filtered');
countLabel.textContent = `Found ${filteredCount} of ${totalCount}`;
countNumber.textContent = filteredCount;
}
}
function parseCSV(csv) {
const lines = csv.split('\n');
const headers = lines[0].split(',').map(header => header.replace(/"/g, '').trim());
return lines.slice(1).map(line => {
const values = line.match(/(".*?"|[^",\s]+)(?=\s*,|\s*$)/g) || [];
const entry = {};
headers.forEach((header, index) => {
let value = values[index] ? values[index].replace(/"/g, '').trim() : '';
// Remove backticks from the act/title
if (header === 'act') {
value = value.replace(/`/g, '');
}
// Convert 'TRUE'/'FALSE' strings to boolean for for_devs
if (header === 'for_devs') {
value = value.toUpperCase() === 'TRUE';
}
entry[header] = value;
});
return entry;
}).filter(entry => entry.act && entry.prompt);
}
function displaySearchResults(results) {
const searchResults = document.getElementById('searchResults');
const searchInput = document.getElementById('searchInput');
const isDevMode = document.getElementById('devModeToggle').checked;
// Filter results based on dev mode
if (isDevMode) {
results = results.filter(result => result.for_devs === true);
}
searchResults.innerHTML = '';
if (window.innerWidth <= 768 && !searchInput.value.trim()) {
return;
}
if (results.length === 0) {
const li = document.createElement('li');
li.className = 'search-result-item add-prompt';
li.innerHTML = `
<a href="https://github.com/f/awesome-chatgpt-prompts/pulls" target="_blank" style="text-decoration: none; color: inherit; display: flex; align-items: center; gap: 8px;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="16"></line>
<line x1="8" y1="12" x2="16" y2="12"></line>
</svg>
Add this prompt
</a>
`;
searchResults.appendChild(li);
return;
}
results.forEach(result => {
const li = document.createElement('li');
li.className = 'search-result-item';
li.textContent = result.act;
li.addEventListener('click', () => {
// Find the prompt card with matching title
const cards = document.querySelectorAll('.prompt-card');
const targetCard = Array.from(cards).find(card => {
const cardTitle = card.querySelector('.prompt-title').textContent
.replace(/\s+/g, ' ') // Normalize whitespace
.replace(/[\n\r]/g, '') // Remove newlines
.trim();
const searchTitle = result.act
.replace(/\s+/g, ' ') // Normalize whitespace
.replace(/[\n\r]/g, '') // Remove newlines
.trim();
return cardTitle.toLowerCase().includes(searchTitle.toLowerCase()) || searchTitle.toLowerCase().includes(cardTitle.toLowerCase());
});
if (targetCard) {
// Remove highlight from all cards
cards.forEach(card => {
card.style.transition = 'all 0.3s ease';
card.style.transform = 'none';
card.style.boxShadow = 'none';
card.style.borderColor = '';
});
// Different scroll behavior for mobile and desktop
const isMobile = window.innerWidth <= 768;
const headerHeight = document.querySelector('.site-header').offsetHeight;
if (isMobile) {
// On mobile, scroll the window
const cardRect = targetCard.getBoundingClientRect();
const scrollTop = window.pageYOffset + cardRect.top - headerHeight - 20;
window.scrollTo({
top: scrollTop,
behavior: 'smooth'
});
} else {
// On desktop, scroll the main-content container
const mainContent = document.querySelector('.main-content');
const cardRect = targetCard.getBoundingClientRect();
const scrollTop = mainContent.scrollTop + cardRect.top - headerHeight - 20;
mainContent.scrollTo({
top: scrollTop,
behavior: 'smooth'
});
}
// Add highlight effect after scrolling completes
setTimeout(() => {
targetCard.style.transform = 'scale(1.02)';
targetCard.style.boxShadow = '0 0 0 2px var(--accent-color)';
targetCard.style.borderColor = 'var(--accent-color)';
// Remove highlight after animation
setTimeout(() => {
targetCard.style.transform = 'none';
targetCard.style.boxShadow = 'none';
targetCard.style.borderColor = '';
}, 2000);
}, 500); // Wait for scroll to complete
} else {
console.log('Card not found for:', result.act);
}
});
searchResults.appendChild(li);
});
}
// Function to filter prompts based on dev mode
function filterPrompts() {
const isDevMode = document.getElementById('devModeToggle').checked;
const searchInput = document.getElementById('searchInput');
const searchTerm = searchInput.value.toLowerCase();
// Re-fetch and filter prompts
fetch('/prompts.csv')
.then(response => response.text())
.then(csvText => {
const prompts = parseCSV(csvText);
const filteredPrompts = prompts.filter(prompt => {
const matchesSearch = !searchTerm ||
prompt.act.toLowerCase().includes(searchTerm) ||
prompt.prompt.toLowerCase().includes(searchTerm);
return isDevMode ? (matchesSearch && prompt.for_devs === true) : matchesSearch;
});
// Update count with filtered results
updatePromptCount(filteredPrompts.length, isDevMode ? prompts.filter(p => p.for_devs === true).length : prompts.length);
displaySearchResults(filteredPrompts);
// Update prompt cards visibility
const promptsGrid = document.querySelector('.prompts-grid');
if (promptsGrid) {
const cards = promptsGrid.querySelectorAll('.prompt-card:not(.contribute-card)');
cards.forEach(card => {
const title = card.querySelector('.prompt-title').textContent.trim();
const matchingPrompt = prompts.find(p => {
const pTitle = p.act.replace(/\s+/g, ' ').replace(/[\n\r]/g, '').trim();
const cardTitle = title.replace(/\s+/g, ' ').replace(/[\n\r]/g, '').trim();
return pTitle.toLowerCase() === cardTitle.toLowerCase() ||
pTitle.toLowerCase().includes(cardTitle.toLowerCase()) ||
cardTitle.toLowerCase().includes(pTitle.toLowerCase());
});
// Show card if not in dev mode or if it's a dev prompt in dev mode
card.style.display = (!isDevMode || (matchingPrompt && matchingPrompt.for_devs === true)) ? '' : 'none';
});
}
});
}
// Update the modal initialization and event listeners
function createPromptCards() {
const container = document.querySelector('.container-lg.markdown-body');
const promptsGrid = document.createElement('div');
promptsGrid.className = 'prompts-grid';
// Add contribute box
const contributeCard = document.createElement('div');
contributeCard.className = 'prompt-card contribute-card';
contributeCard.innerHTML = `
<a href="https://github.com/f/awesome-chatgpt-prompts/pulls" target="_blank" style="text-decoration: none; color: inherit; height: 100%; display: flex; flex-direction: column;">
<div class="prompt-title" style="display: flex; align-items: center; gap: 8px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="16"></line>
<line x1="8" y1="12" x2="16" y2="12"></line>
</svg>
Add Your Prompt
</div>
<p class="prompt-content" style="flex-grow: 1;">
Share your creative prompts with the community! Submit a pull request to add your prompts to the collection.
</p>
<span class="contributor-badge">Contribute Now</span>
</a>
`;
promptsGrid.appendChild(contributeCard);
// Fetch prompts.csv to get for_devs information
fetch('/prompts.csv')
.then(response => response.text())
.then(csvText => {
const prompts = parseCSV(csvText);
const isDevMode = document.getElementById('devModeToggle').checked;
const promptElements = document.querySelectorAll('h2[id^=act] + p + blockquote');
promptElements.forEach((blockquote) => {
const title = blockquote.previousElementSibling.previousElementSibling.textContent.trim();
const content = blockquote.textContent.trim();
// Find matching prompt in CSV
const matchingPrompt = prompts.find(p => {
const csvTitle = p.act.replace(/\s+/g, ' ').replace(/[\n\r]/g, '').trim();
const elementTitle = title.replace(/\s+/g, ' ').replace(/[\n\r]/g, '').trim();
return csvTitle.toLowerCase() === elementTitle.toLowerCase() ||
csvTitle.toLowerCase().includes(elementTitle.toLowerCase()) ||
elementTitle.toLowerCase().includes(csvTitle.toLowerCase());
});
// Extract contributor from the paragraph element
const contributorParagraph = blockquote.previousElementSibling;
const contributorText = contributorParagraph.textContent;
let contributor = null;
// Try different contributor formats
const formats = [
/Contributed by: \[([^\]]+)\]/i,
/Contributed by \[([^\]]+)\]/i,
/Contributed by: @([^\s]+)/i,
/Contributed by @([^\s]+)/i,
/Contributed by: \[@([^\]]+)\]/i,
/Contributed by \[@([^\]]+)\]/i
];
for (const format of formats) {
const match = contributorText.match(format);
if (match) {
contributor = match[1];
// Remove @ if it exists at the start
contributor = contributor.replace(/^@/, '');
break;
}
}
// Set default contributor to 'f' if none found
if (!contributor) {
contributor = 'f';
}
const card = document.createElement('div');
card.className = 'prompt-card';
// Set initial visibility based on dev mode
if (isDevMode && (!matchingPrompt || !matchingPrompt.for_devs)) {
card.style.display = 'none';
}
card.innerHTML = `
<div class="prompt-title">
${title}
<div class="action-buttons">
<button class="chat-button" title="Open in AI Chat" onclick="openInChat(this, '${encodeURIComponent(content.trim())}')">
<svg class="chat-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
<svg class="terminal-icon" style="display: none;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
</button>
<button class="copy-button" title="Copy prompt" onclick="copyPrompt(this, '${encodeURIComponent(content.trim())}')">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path>
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect>
</svg>
</button>
</div>
</div>
<p class="prompt-content">${content}</p>
<a href="https://github.com/${contributor}" class="contributor-badge" target="_blank" rel="noopener">@${contributor}</a>
`;
// Add click event for showing modal
card.addEventListener('click', (e) => {
if (!e.target.closest('.copy-button') && !e.target.closest('.contributor-badge')) {
showModal(title, content);
}
});
const copyButton = card.querySelector('.copy-button');
copyButton.addEventListener('click', async (e) => {
e.stopPropagation();
try {
await navigator.clipboard.writeText(content);
copyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
`;
setTimeout(() => {
copyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
`;
}, 2000);
} catch (err) {
alert('Failed to copy prompt to clipboard');
}
});
promptsGrid.appendChild(card);
});
container.innerHTML = '';
container.appendChild(promptsGrid);
// Initialize modal event listeners
initializeModalListeners();
})
.catch(error => {
console.error('Error loading prompts:', error);
});
}
function initializeModalListeners() {
const modalOverlay = document.getElementById('modalOverlay');
const modalClose = document.querySelector('.modal-close');
if (!modalOverlay || !modalClose) return;
modalClose.addEventListener('click', hideModal);
modalOverlay.addEventListener('click', (e) => {
if (e.target === modalOverlay) {
hideModal();
}
});
}
// Add global event listener for Escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
hideModal();
}
});
function createModal() {
const modalHTML = `
<div class="modal-overlay" id="modalOverlay">
<div class="modal">
<div class="modal-header">
<h2 class="modal-title"></h2>
<div class="modal-actions">
<button class="modal-copy-button" title="Copy prompt">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
</button>
<button class="modal-close" title="Close">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
</div>
<div class="modal-content"></div>
<div class="modal-footer">
<div class="modal-footer-left">
<a class="modal-contributor" target="_blank" rel="noopener"></a>
</div>
<div class="modal-footer-right">
<button class="modal-chat-button" onclick="openModalChat()">
<svg class="chat-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
<svg class="terminal-icon" style="display: none;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
Start Chat
</button>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHTML);
initializeModalListeners();
}
function showModal(title, content) {
let modalOverlay = document.getElementById('modalOverlay');
if (!modalOverlay) {
createModal();
modalOverlay = document.getElementById('modalOverlay');
}
const modalTitle = modalOverlay.querySelector('.modal-title');
const modalContent = modalOverlay.querySelector('.modal-content');
const modalCopyButton = modalOverlay.querySelector('.modal-copy-button');
const modalContributor = modalOverlay.querySelector('.modal-contributor');
const modalChatButton = modalOverlay.querySelector('.modal-chat-button');
if (!modalTitle || !modalContent) return;
modalTitle.textContent = title;
modalContent.textContent = content;
// Update chat button text with platform name and handle visibility
const platform = document.querySelector('.platform-tag.active');
const isDevMode = document.getElementById('devModeToggle').checked;
if (platform) {
const shouldHideChat = ['gemini', 'llama'].includes(platform.dataset.platform);
modalChatButton.style.display = shouldHideChat ? 'none' : 'flex';
if (!shouldHideChat) {
const chatIcon = modalChatButton.querySelector('.chat-icon');
const terminalIcon = modalChatButton.querySelector('.terminal-icon');
if (chatIcon && terminalIcon) {
chatIcon.style.display = isDevMode ? 'none' : 'block';
terminalIcon.style.display = isDevMode ? 'block' : 'none';
}
modalChatButton.innerHTML = `
<svg class="chat-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: ${isDevMode ? 'none' : 'block'}">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
<svg class="terminal-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: ${isDevMode ? 'block' : 'none'}">
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
Chat with ${platform.textContent}
`;
}
}
// Store content for chat button
modalChatButton.dataset.content = content;
// Find the contributor for this prompt
const promptCard = Array.from(document.querySelectorAll('.prompt-card')).find(card =>
card.querySelector('.prompt-title').textContent.trim() === title.trim()
);
if (promptCard) {
const contributorBadge = promptCard.querySelector('.contributor-badge');
if (contributorBadge) {
modalContributor.href = contributorBadge.href;
modalContributor.textContent = `Contributed by ${contributorBadge.textContent}`;
}
}
// Add copy functionality
modalCopyButton.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(content);
modalCopyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
`;
setTimeout(() => {
modalCopyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
`;
}, 2000);
} catch (err) {
alert('Failed to copy prompt to clipboard');
}
});
modalOverlay.style.display = 'block';
document.body.style.overflow = 'hidden';
}
function hideModal() {
const modalOverlay = document.getElementById('modalOverlay');
if (!modalOverlay) return;
modalOverlay.style.display = 'none';
document.body.style.overflow = '';
// Optional: Remove modal from DOM when hidden
modalOverlay.remove();
}
let selectedPlatform = localStorage.getItem('selected-platform') || 'github-copilot'; // Get from localStorage or default to github
// Platform toggle functionality
document.querySelectorAll('.platform-tag').forEach(button => {
button.addEventListener('click', () => {
document.querySelectorAll('.platform-tag').forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
selectedPlatform = button.dataset.platform;
localStorage.setItem('selected-platform', selectedPlatform);
// Hide/show chat buttons based on platform
const chatButtons = document.querySelectorAll('.chat-button, .modal-chat-button');
const shouldHideChat = ['gemini', 'llama'].includes(selectedPlatform);
chatButtons.forEach(btn => {
btn.style.display = shouldHideChat ? 'none' : 'flex';
});
});
});
// Set active platform from localStorage and handle initial button visibility
const platformToActivate = document.querySelector(`[data-platform="${selectedPlatform}"]`) ||
document.querySelector('[data-platform="github-copilot"]');
platformToActivate.classList.add('active');
// Set initial chat button visibility
const shouldHideChat = ['gemini', 'llama'].includes(selectedPlatform);
document.querySelectorAll('.chat-button, .modal-chat-button').forEach(btn => {
btn.style.display = shouldHideChat ? 'none' : 'flex';
});
// Function to open prompt in selected AI chat platform
function openInChat(button, encodedPrompt) {
const promptText = decodeURIComponent(encodedPrompt);
const platform = document.querySelector('.platform-tag.active');
if (!platform) return;
const baseUrl = platform.dataset.url;
let url;
switch (platform.dataset.platform) {
case 'github-copilot':
url = `${baseUrl}?prompt=${encodeURIComponent(promptText)}`;
break;
case 'chatgpt':
url = `${baseUrl}?prompt=${encodeURIComponent(promptText)}`;
break;
case 'claude':
url = `${baseUrl}?q=${encodeURIComponent(promptText)}`;
break;
case 'perplexity':
url = `${baseUrl}/search?q=${encodeURIComponent(promptText)}`;
break;
case 'mistral':
url = `${baseUrl}?q=${encodeURIComponent(promptText)}`;
break;
default:
url = `${baseUrl}?q=${encodeURIComponent(promptText)}`;
}
window.open(url, '_blank');
}
// Existing copy function
async function copyPrompt(button, encodedPrompt) {
const promptText = decodeURIComponent(encodedPrompt);
try {
await navigator.clipboard.writeText(promptText);
const originalHTML = button.innerHTML;
button.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17 4 12"/></svg>';
setTimeout(() => {
button.innerHTML = originalHTML;
}, 1000);
} catch (err) {
console.error('Failed to copy text: ', err);
}
}
// Function to handle chat button click in modal
function openModalChat() {
const modalContent = document.querySelector('.modal-content');
if (modalContent) {
const content = modalContent.textContent;
openInChat(null, encodeURIComponent(content.trim()));
}
}
// Add these functions before the closing script tag
function showCopilotSuggestion() {
const modal = document.getElementById('copilotSuggestionModal');
const backdrop = document.querySelector('.copilot-suggestion-backdrop');
if (modal) {
if (!backdrop) {
const backdropDiv = document.createElement('div');
backdropDiv.className = 'copilot-suggestion-backdrop';
document.body.appendChild(backdropDiv);
}
modal.style.display = 'block';
backdrop.style.display = 'block';
document.body.style.overflow = 'hidden';
}
}
function hideCopilotSuggestion(switchToCopilot) {
const modal = document.getElementById('copilotSuggestionModal');
const backdrop = document.querySelector('.copilot-suggestion-backdrop');
const doNotShowCheckbox = document.getElementById('doNotShowAgain');
if (doNotShowCheckbox && doNotShowCheckbox.checked) {
localStorage.setItem('copilot-suggestion-hidden', 'true');
}
if (switchToCopilot) {
const copilotButton = document.querySelector('[data-platform="github-copilot"]');
if (copilotButton) {
copilotButton.click();
}
}
if (modal) {
modal.style.display = 'none';
if (backdrop) {
backdrop.style.display = 'none';
}
document.body.style.overflow = '';
}
}
// Function to update chat button icons based on dev mode
function updateChatButtonIcons(isDevMode) {
document.querySelectorAll('.chat-button, .modal-chat-button').forEach(button => {
const chatIcon = button.querySelector('.chat-icon');
const terminalIcon = button.querySelector('.terminal-icon');
if (chatIcon && terminalIcon) {
chatIcon.style.display = isDevMode ? 'none' : 'block';
terminalIcon.style.display = isDevMode ? 'block' : 'none';
}
});
}
</script>
<script src="script.js"></script>
<style>video { max-width: 100% !important; }</style>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-MSNHFWTE77"></script>

857
script.js Normal file
View File

@ -0,0 +1,857 @@
// Dark mode functionality
function toggleDarkMode() {
const body = document.body;
const toggle = document.querySelector(".dark-mode-toggle");
const sunIcon = toggle.querySelector(".sun-icon");
const moonIcon = toggle.querySelector(".moon-icon");
body.classList.toggle("dark-mode");
const isDarkMode = body.classList.contains("dark-mode");
localStorage.setItem("dark-mode", isDarkMode);
sunIcon.style.display = isDarkMode ? "none" : "block";
moonIcon.style.display = isDarkMode ? "block" : "none";
}
// Initialize everything after DOM loads
document.addEventListener("DOMContentLoaded", () => {
// Initialize dev mode
const devModeToggle = document.getElementById("devModeToggle");
const initialDevMode = localStorage.getItem("dev-mode") === "true";
devModeToggle.checked = initialDevMode;
// Initialize chat button icons
updateChatButtonIcons(initialDevMode);
// Handle dev mode toggle
devModeToggle.addEventListener("change", (e) => {
const newDevMode = e.target.checked;
localStorage.setItem("dev-mode", newDevMode);
// Toggle dev-mode class on body element
document.body.classList.toggle("dev-mode", newDevMode);
// Update chat button icons
updateChatButtonIcons(newDevMode);
// Check if we should show Copilot suggestion
if (newDevMode) {
const currentPlatform = document.querySelector(".platform-tag.active");
const shouldNotShow =
localStorage.getItem("copilot-suggestion-hidden") === "true";
if (
currentPlatform &&
currentPlatform.dataset.platform !== "github-copilot" &&
!shouldNotShow
) {
showCopilotSuggestion();
}
}
filterPrompts();
});
// Fetch GitHub stars
fetch("https://api.github.com/repos/f/awesome-chatgpt-prompts")
.then((response) => response.json())
.then((data) => {
const stars = data.stargazers_count;
document.getElementById("starCount").textContent = stars.toLocaleString();
})
.catch((error) => {
console.error("Error fetching star count:", error);
document.getElementById("starCount").textContent = "50k+";
});
// Create prompt cards
createPromptCards();
// Initialize dark mode
const isDarkMode = localStorage.getItem("dark-mode");
const toggle = document.querySelector(".dark-mode-toggle");
const sunIcon = toggle.querySelector(".sun-icon");
const moonIcon = toggle.querySelector(".moon-icon");
// Set dark mode by default if not set
if (isDarkMode === null) {
localStorage.setItem("dark-mode", "true");
document.body.classList.add("dark-mode");
sunIcon.style.display = "none";
moonIcon.style.display = "block";
} else if (isDarkMode === "true") {
document.body.classList.add("dark-mode");
sunIcon.style.display = "none";
moonIcon.style.display = "block";
} else {
sunIcon.style.display = "block";
moonIcon.style.display = "none";
}
// Initialize search functionality
initializeSearch();
// Initialize chat button icons on page load
const isDevMode = localStorage.getItem("dev-mode") === "true";
document.body.classList.toggle("dev-mode", isDevMode);
updateChatButtonIcons(isDevMode);
});
// Search functionality
async function initializeSearch() {
try {
const response = await fetch("/prompts.csv");
const csvText = await response.text();
const prompts = parseCSV(csvText);
// Sort prompts alphabetically by act
prompts.sort((a, b) => a.act.localeCompare(b.act));
const searchInput = document.getElementById("searchInput");
const searchResults = document.getElementById("searchResults");
const promptCount = document.getElementById("promptCount");
const isDevMode = document.getElementById("devModeToggle").checked;
// Update prompt count
const totalPrompts = isDevMode
? prompts.filter((p) => p.for_devs === true).length
: prompts.length;
updatePromptCount(totalPrompts, totalPrompts);
// Show filtered prompts initially
const filteredPrompts = isDevMode
? prompts.filter((p) => p.for_devs === true)
: prompts;
displaySearchResults(filteredPrompts);
searchInput.addEventListener("input", (e) => {
const searchTerm = e.target.value.toLowerCase();
const filteredPrompts = prompts.filter((prompt) => {
const matchesSearch = prompt.act.toLowerCase().includes(searchTerm) ||
prompt.prompt.toLowerCase().includes(searchTerm);
return isDevMode
? (matchesSearch && prompt.for_devs === true)
: matchesSearch;
});
// Update count with filtered results
const totalPrompts = isDevMode
? prompts.filter((p) => p.for_devs === true).length
: prompts.length;
updatePromptCount(filteredPrompts.length, totalPrompts);
displaySearchResults(filteredPrompts);
});
} catch (error) {
console.error("Error loading prompts:", error);
}
}
function updatePromptCount(filteredCount, totalCount) {
const promptCount = document.getElementById("promptCount");
const countLabel = promptCount.querySelector(".count-label");
const countNumber = promptCount.querySelector(".count-number");
if (filteredCount === totalCount) {
promptCount.classList.remove("filtered");
countLabel.textContent = "All Prompts";
countNumber.textContent = totalCount;
} else {
promptCount.classList.add("filtered");
countLabel.textContent = `Found ${filteredCount} of ${totalCount}`;
countNumber.textContent = filteredCount;
}
}
function parseCSV(csv) {
const lines = csv.split("\n");
const headers = lines[0].split(",").map((header) =>
header.replace(/"/g, "").trim()
);
return lines.slice(1).map((line) => {
const values = line.match(/(".*?"|[^",\s]+)(?=\s*,|\s*$)/g) || [];
const entry = {};
headers.forEach((header, index) => {
let value = values[index] ? values[index].replace(/"/g, "").trim() : "";
// Remove backticks from the act/title
if (header === "act") {
value = value.replace(/`/g, "");
}
// Convert 'TRUE'/'FALSE' strings to boolean for for_devs
if (header === "for_devs") {
value = value.toUpperCase() === "TRUE";
}
entry[header] = value;
});
return entry;
}).filter((entry) => entry.act && entry.prompt);
}
function displaySearchResults(results) {
const searchResults = document.getElementById("searchResults");
const searchInput = document.getElementById("searchInput");
const isDevMode = document.getElementById("devModeToggle").checked;
// Filter results based on dev mode
if (isDevMode) {
results = results.filter((result) => result.for_devs === true);
}
searchResults.innerHTML = "";
if (window.innerWidth <= 768 && !searchInput.value.trim()) {
return;
}
if (results.length === 0) {
const li = document.createElement("li");
li.className = "search-result-item add-prompt";
li.innerHTML = `
<a href="https://github.com/f/awesome-chatgpt-prompts/pulls" target="_blank" style="text-decoration: none; color: inherit; display: flex; align-items: center; gap: 8px;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="16"></line>
<line x1="8" y1="12" x2="16" y2="12"></line>
</svg>
Add this prompt
</a>
`;
searchResults.appendChild(li);
return;
}
results.forEach((result) => {
const li = document.createElement("li");
li.className = "search-result-item";
li.textContent = result.act;
li.addEventListener("click", () => {
// Find the prompt card with matching title
const cards = document.querySelectorAll(".prompt-card");
const targetCard = Array.from(cards).find((card) => {
const cardTitle = card.querySelector(".prompt-title").textContent
.replace(/\s+/g, " ") // Normalize whitespace
.replace(/[\n\r]/g, "") // Remove newlines
.trim();
const searchTitle = result.act
.replace(/\s+/g, " ") // Normalize whitespace
.replace(/[\n\r]/g, "") // Remove newlines
.trim();
return cardTitle.toLowerCase().includes(searchTitle.toLowerCase()) ||
searchTitle.toLowerCase().includes(cardTitle.toLowerCase());
});
if (targetCard) {
// Remove highlight from all cards
cards.forEach((card) => {
card.style.transition = "all 0.3s ease";
card.style.transform = "none";
card.style.boxShadow = "none";
card.style.borderColor = "";
});
// Different scroll behavior for mobile and desktop
const isMobile = window.innerWidth <= 768;
const headerHeight =
document.querySelector(".site-header").offsetHeight;
if (isMobile) {
// On mobile, scroll the window
const cardRect = targetCard.getBoundingClientRect();
const scrollTop = window.pageYOffset + cardRect.top - headerHeight -
20;
window.scrollTo({
top: scrollTop,
behavior: "smooth",
});
} else {
// On desktop, scroll the main-content container
const mainContent = document.querySelector(".main-content");
const cardRect = targetCard.getBoundingClientRect();
const scrollTop = mainContent.scrollTop + cardRect.top -
headerHeight - 20;
mainContent.scrollTo({
top: scrollTop,
behavior: "smooth",
});
}
// Add highlight effect after scrolling completes
setTimeout(() => {
targetCard.style.transform = "scale(1.02)";
targetCard.style.boxShadow = "0 0 0 2px var(--accent-color)";
targetCard.style.borderColor = "var(--accent-color)";
// Remove highlight after animation
setTimeout(() => {
targetCard.style.transform = "none";
targetCard.style.boxShadow = "none";
targetCard.style.borderColor = "";
}, 2000);
}, 500); // Wait for scroll to complete
} else {
console.log("Card not found for:", result.act);
}
});
searchResults.appendChild(li);
});
}
// Function to filter prompts based on dev mode
function filterPrompts() {
const isDevMode = document.getElementById("devModeToggle").checked;
const searchInput = document.getElementById("searchInput");
const searchTerm = searchInput.value.toLowerCase();
// Re-fetch and filter prompts
fetch("/prompts.csv")
.then((response) => response.text())
.then((csvText) => {
const prompts = parseCSV(csvText);
const filteredPrompts = prompts.filter((prompt) => {
const matchesSearch = !searchTerm ||
prompt.act.toLowerCase().includes(searchTerm) ||
prompt.prompt.toLowerCase().includes(searchTerm);
return isDevMode
? (matchesSearch && prompt.for_devs === true)
: matchesSearch;
});
// Update count with filtered results
updatePromptCount(
filteredPrompts.length,
isDevMode
? prompts.filter((p) => p.for_devs === true).length
: prompts.length,
);
displaySearchResults(filteredPrompts);
// Update prompt cards visibility
const promptsGrid = document.querySelector(".prompts-grid");
if (promptsGrid) {
const cards = promptsGrid.querySelectorAll(
".prompt-card:not(.contribute-card)",
);
cards.forEach((card) => {
const title = card.querySelector(".prompt-title").textContent.trim();
const matchingPrompt = prompts.find((p) => {
const pTitle = p.act.replace(/\s+/g, " ").replace(/[\n\r]/g, "")
.trim();
const cardTitle = title.replace(/\s+/g, " ").replace(/[\n\r]/g, "")
.trim();
return pTitle.toLowerCase() === cardTitle.toLowerCase() ||
pTitle.toLowerCase().includes(cardTitle.toLowerCase()) ||
cardTitle.toLowerCase().includes(pTitle.toLowerCase());
});
// Show card if not in dev mode or if it's a dev prompt in dev mode
card.style.display =
(!isDevMode || (matchingPrompt && matchingPrompt.for_devs === true))
? ""
: "none";
});
}
});
}
// Update the modal initialization and event listeners
function createPromptCards() {
const container = document.querySelector(".container-lg.markdown-body");
const promptsGrid = document.createElement("div");
promptsGrid.className = "prompts-grid";
// Add contribute box
const contributeCard = document.createElement("div");
contributeCard.className = "prompt-card contribute-card";
contributeCard.innerHTML = `
<a href="https://github.com/f/awesome-chatgpt-prompts/pulls" target="_blank" style="text-decoration: none; color: inherit; height: 100%; display: flex; flex-direction: column;">
<div class="prompt-title" style="display: flex; align-items: center; gap: 8px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="16"></line>
<line x1="8" y1="12" x2="16" y2="12"></line>
</svg>
Add Your Prompt
</div>
<p class="prompt-content" style="flex-grow: 1;">
Share your creative prompts with the community! Submit a pull request to add your prompts to the collection.
</p>
<span class="contributor-badge">Contribute Now</span>
</a>
`;
promptsGrid.appendChild(contributeCard);
// Fetch prompts.csv to get for_devs information
fetch("/prompts.csv")
.then((response) => response.text())
.then((csvText) => {
const prompts = parseCSV(csvText);
const isDevMode = document.getElementById("devModeToggle").checked;
const promptElements = document.querySelectorAll(
"h2[id^=act] + p + blockquote",
);
promptElements.forEach((blockquote) => {
const title = blockquote.previousElementSibling.previousElementSibling
.textContent.trim();
const content = blockquote.textContent.trim();
// Find matching prompt in CSV
const matchingPrompt = prompts.find((p) => {
const csvTitle = p.act.replace(/\s+/g, " ").replace(/[\n\r]/g, "")
.trim();
const elementTitle = title.replace(/\s+/g, " ").replace(/[\n\r]/g, "")
.trim();
return csvTitle.toLowerCase() === elementTitle.toLowerCase() ||
csvTitle.toLowerCase().includes(elementTitle.toLowerCase()) ||
elementTitle.toLowerCase().includes(csvTitle.toLowerCase());
});
// Extract contributor from the paragraph element
const contributorParagraph = blockquote.previousElementSibling;
const contributorText = contributorParagraph.textContent;
let contributor = null;
// Try different contributor formats
const formats = [
/Contributed by: \[([^\]]+)\]/i,
/Contributed by \[([^\]]+)\]/i,
/Contributed by: @([^\s]+)/i,
/Contributed by @([^\s]+)/i,
/Contributed by: \[@([^\]]+)\]/i,
/Contributed by \[@([^\]]+)\]/i,
];
for (const format of formats) {
const match = contributorText.match(format);
if (match) {
contributor = match[1];
// Remove @ if it exists at the start
contributor = contributor.replace(/^@/, "");
break;
}
}
// Set default contributor to 'f' if none found
if (!contributor) {
contributor = "f";
}
const card = document.createElement("div");
card.className = "prompt-card";
// Set initial visibility based on dev mode
if (isDevMode && (!matchingPrompt || !matchingPrompt.for_devs)) {
card.style.display = "none";
}
card.innerHTML = `
<div class="prompt-title">
${title}
<div class="action-buttons">
<button class="chat-button" title="Open in AI Chat" onclick="openInChat(this, '${
encodeURIComponent(content.trim())
}')">
<svg class="chat-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
<svg class="terminal-icon" style="display: none;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
</button>
<button class="copy-button" title="Copy prompt" onclick="copyPrompt(this, '${
encodeURIComponent(content.trim())
}')">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path>
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect>
</svg>
</button>
</div>
</div>
<p class="prompt-content">${content}</p>
<a href="https://github.com/${contributor}" class="contributor-badge" target="_blank" rel="noopener">@${contributor}</a>
`;
// Add click event for showing modal
card.addEventListener("click", (e) => {
if (
!e.target.closest(".copy-button") &&
!e.target.closest(".contributor-badge")
) {
showModal(title, content);
}
});
const copyButton = card.querySelector(".copy-button");
copyButton.addEventListener("click", async (e) => {
e.stopPropagation();
try {
await navigator.clipboard.writeText(content);
copyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
`;
setTimeout(() => {
copyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
`;
}, 2000);
} catch (err) {
alert("Failed to copy prompt to clipboard");
}
});
promptsGrid.appendChild(card);
});
container.innerHTML = "";
container.appendChild(promptsGrid);
// Initialize modal event listeners
initializeModalListeners();
})
.catch((error) => {
console.error("Error loading prompts:", error);
});
}
function initializeModalListeners() {
const modalOverlay = document.getElementById("modalOverlay");
const modalClose = document.querySelector(".modal-close");
if (!modalOverlay || !modalClose) return;
modalClose.addEventListener("click", hideModal);
modalOverlay.addEventListener("click", (e) => {
if (e.target === modalOverlay) {
hideModal();
}
});
}
// Add global event listener for Escape key
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
hideModal();
}
});
function createModal() {
const modalHTML = `
<div class="modal-overlay" id="modalOverlay">
<div class="modal">
<div class="modal-header">
<h2 class="modal-title"></h2>
<div class="modal-actions">
<button class="modal-copy-button" title="Copy prompt">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
</button>
<button class="modal-close" title="Close">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
</div>
<div class="modal-content"></div>
<div class="modal-footer">
<div class="modal-footer-left">
<a class="modal-contributor" target="_blank" rel="noopener"></a>
</div>
<div class="modal-footer-right">
<button class="modal-chat-button" onclick="openModalChat()">
<svg class="chat-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
<svg class="terminal-icon" style="display: none;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
Start Chat
</button>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML("beforeend", modalHTML);
initializeModalListeners();
}
function showModal(title, content) {
let modalOverlay = document.getElementById("modalOverlay");
if (!modalOverlay) {
createModal();
modalOverlay = document.getElementById("modalOverlay");
}
const modalTitle = modalOverlay.querySelector(".modal-title");
const modalContent = modalOverlay.querySelector(".modal-content");
const modalCopyButton = modalOverlay.querySelector(".modal-copy-button");
const modalContributor = modalOverlay.querySelector(".modal-contributor");
const modalChatButton = modalOverlay.querySelector(".modal-chat-button");
if (!modalTitle || !modalContent) return;
modalTitle.textContent = title;
modalContent.textContent = content;
// Update chat button text with platform name and handle visibility
const platform = document.querySelector(".platform-tag.active");
const isDevMode = document.getElementById("devModeToggle").checked;
if (platform) {
const shouldHideChat = ["gemini", "llama"].includes(
platform.dataset.platform,
);
modalChatButton.style.display = shouldHideChat ? "none" : "flex";
if (!shouldHideChat) {
const chatIcon = modalChatButton.querySelector(".chat-icon");
const terminalIcon = modalChatButton.querySelector(".terminal-icon");
if (chatIcon && terminalIcon) {
chatIcon.style.display = isDevMode ? "none" : "block";
terminalIcon.style.display = isDevMode ? "block" : "none";
}
modalChatButton.innerHTML = `
<svg class="chat-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: ${
isDevMode ? "none" : "block"
}">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
<svg class="terminal-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: ${
isDevMode ? "block" : "none"
}">
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
Chat with ${platform.textContent}
`;
}
}
// Store content for chat button
modalChatButton.dataset.content = content;
// Find the contributor for this prompt
const promptCard = Array.from(document.querySelectorAll(".prompt-card")).find(
(card) =>
card.querySelector(".prompt-title").textContent.trim() === title.trim(),
);
if (promptCard) {
const contributorBadge = promptCard.querySelector(".contributor-badge");
if (contributorBadge) {
modalContributor.href = contributorBadge.href;
modalContributor.textContent =
`Contributed by ${contributorBadge.textContent}`;
}
}
// Add copy functionality
modalCopyButton.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(content);
modalCopyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
`;
setTimeout(() => {
modalCopyButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
`;
}, 2000);
} catch (err) {
alert("Failed to copy prompt to clipboard");
}
});
modalOverlay.style.display = "block";
document.body.style.overflow = "hidden";
}
function hideModal() {
const modalOverlay = document.getElementById("modalOverlay");
if (!modalOverlay) return;
modalOverlay.style.display = "none";
document.body.style.overflow = "";
// Optional: Remove modal from DOM when hidden
modalOverlay.remove();
}
let selectedPlatform = localStorage.getItem("selected-platform") ||
"github-copilot"; // Get from localStorage or default to github
// Platform toggle functionality
document.querySelectorAll(".platform-tag").forEach((button) => {
button.addEventListener("click", () => {
document.querySelectorAll(".platform-tag").forEach((btn) =>
btn.classList.remove("active")
);
button.classList.add("active");
selectedPlatform = button.dataset.platform;
localStorage.setItem("selected-platform", selectedPlatform);
// Hide/show chat buttons based on platform
const chatButtons = document.querySelectorAll(
".chat-button, .modal-chat-button",
);
const shouldHideChat = ["gemini", "llama"].includes(selectedPlatform);
chatButtons.forEach((btn) => {
btn.style.display = shouldHideChat ? "none" : "flex";
});
});
});
// Set active platform from localStorage and handle initial button visibility
const platformToActivate =
document.querySelector(`[data-platform="${selectedPlatform}"]`) ||
document.querySelector('[data-platform="github-copilot"]');
platformToActivate.classList.add("active");
// Set initial chat button visibility
const shouldHideChat = ["gemini", "llama"].includes(selectedPlatform);
document.querySelectorAll(".chat-button, .modal-chat-button").forEach((btn) => {
btn.style.display = shouldHideChat ? "none" : "flex";
});
// Function to open prompt in selected AI chat platform
function openInChat(button, encodedPrompt) {
const promptText = decodeURIComponent(encodedPrompt);
const platform = document.querySelector(".platform-tag.active");
if (!platform) return;
const baseUrl = platform.dataset.url;
let url;
switch (platform.dataset.platform) {
case "github-copilot":
url = `${baseUrl}?prompt=${encodeURIComponent(promptText)}`;
break;
case "chatgpt":
url = `${baseUrl}?prompt=${encodeURIComponent(promptText)}`;
break;
case "claude":
url = `${baseUrl}?q=${encodeURIComponent(promptText)}`;
break;
case "perplexity":
url = `${baseUrl}/search?q=${encodeURIComponent(promptText)}`;
break;
case "mistral":
url = `${baseUrl}?q=${encodeURIComponent(promptText)}`;
break;
default:
url = `${baseUrl}?q=${encodeURIComponent(promptText)}`;
}
window.open(url, "_blank");
}
// Existing copy function
async function copyPrompt(button, encodedPrompt) {
const promptText = decodeURIComponent(encodedPrompt);
try {
await navigator.clipboard.writeText(promptText);
const originalHTML = button.innerHTML;
button.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17 4 12"/></svg>';
setTimeout(() => {
button.innerHTML = originalHTML;
}, 1000);
} catch (err) {
console.error("Failed to copy text: ", err);
}
}
// Function to handle chat button click in modal
function openModalChat() {
const modalContent = document.querySelector(".modal-content");
if (modalContent) {
const content = modalContent.textContent;
openInChat(null, encodeURIComponent(content.trim()));
}
}
// Add these functions before the closing script tag
function showCopilotSuggestion() {
const modal = document.getElementById("copilotSuggestionModal");
const backdrop = document.querySelector(".copilot-suggestion-backdrop");
if (modal) {
if (!backdrop) {
const backdropDiv = document.createElement("div");
backdropDiv.className = "copilot-suggestion-backdrop";
document.body.appendChild(backdropDiv);
}
modal.style.display = "block";
backdrop.style.display = "block";
document.body.style.overflow = "hidden";
}
}
function hideCopilotSuggestion(switchToCopilot) {
const modal = document.getElementById("copilotSuggestionModal");
const backdrop = document.querySelector(".copilot-suggestion-backdrop");
const doNotShowCheckbox = document.getElementById("doNotShowAgain");
if (doNotShowCheckbox && doNotShowCheckbox.checked) {
localStorage.setItem("copilot-suggestion-hidden", "true");
}
if (switchToCopilot) {
const copilotButton = document.querySelector(
'[data-platform="github-copilot"]',
);
if (copilotButton) {
copilotButton.click();
}
}
if (modal) {
modal.style.display = "none";
if (backdrop) {
backdrop.style.display = "none";
}
document.body.style.overflow = "";
}
}
// Function to update chat button icons based on dev mode
function updateChatButtonIcons(isDevMode) {
document.querySelectorAll(".chat-button, .modal-chat-button").forEach(
(button) => {
const chatIcon = button.querySelector(".chat-icon");
const terminalIcon = button.querySelector(".terminal-icon");
if (chatIcon && terminalIcon) {
chatIcon.style.display = isDevMode ? "none" : "block";
terminalIcon.style.display = isDevMode ? "block" : "none";
}
},
);
}