17}
1819export default function App() {
20const [state, setState] = useState<AppState>({
21view: 'search',
122});
123124async function syncData() {
125// Get pending data from IndexedDB and sync when online
126console.log('Background sync triggered');
tourguideitinerary.ts1 match
14const openai = new OpenAI();
1516function generateId(): string {
17return Math.random().toString(36).substring(2) + Date.now().toString(36);
18}
tourguidequeries.ts6 matches
3import type { Itinerary, TourProgress } from "../../shared/types.ts";
45export async function saveItinerary(itinerary: Itinerary): Promise<void> {
6await sqlite.execute(`
7INSERT INTO ${ITINERARIES_TABLE} (
25}
2627export async function getItinerary(id: string): Promise<Itinerary | null> {
28const result = await sqlite.execute(`
29SELECT * FROM ${ITINERARIES_TABLE} WHERE id = ?
49}
5051export async function getAllItineraries(): Promise<Itinerary[]> {
52const result = await sqlite.execute(`
53SELECT * FROM ${ITINERARIES_TABLE} ORDER BY created_at DESC
70}
7172export async function deleteItinerary(id: string): Promise<boolean> {
73const result = await sqlite.execute(`
74DELETE FROM ${ITINERARIES_TABLE} WHERE id = ?
78}
7980export async function saveTourProgress(progress: TourProgress): Promise<void> {
81await sqlite.execute(`
82INSERT OR REPLACE INTO ${TOUR_PROGRESS_TABLE} (
93}
9495export async function getTourProgress(itineraryId: string): Promise<TourProgress | null> {
96const result = await sqlite.execute(`
97SELECT * FROM ${TOUR_PROGRESS_TABLE} WHERE itinerary_id = ?
tourguidemigrations.ts1 match
4const TOUR_PROGRESS_TABLE = 'tour_guide_progress_v1';
56export async function runMigrations() {
7// Create itineraries table
8await sqlite.execute(`
charmaineValSearchdb.ts25 matches
910/**
11* Wraps an async function to measure its execution time
12*/
13export async function withTiming<T>(
14fn: () => Promise<T>,
15): Promise<[T, number]> {
2627// Load all usernames and project paths into memory for fast typeahead
28export async function loadTypeaheadDataIntoMemory(): Promise<void> {
29console.log("Loading typeahead data into memory...");
3060* Search typeahead data by prefix
61*/
62export function searchTypeahead(query: string, limit: number = 10): string[] {
63const lowerQuery = query.toLowerCase();
64const results: string[] = [];
77* Get activity data for the last 6 months
78*/
79export async function getActivityHeatmap(): Promise<{
80date: string;
81count: number;
114* Get top contributors based on recency
115*/
116export async function getTopContributors(limit: number = 10): Promise<{
117username: string;
118projectCount: number;
152* Get most active projects based on recency and file count
153*/
154export async function getMostActiveProjects(limit: number = 10): Promise<{
155name: string;
156username: string;
192* Get database statistics for the homepage
193*/
194export async function getSearchStats(): Promise<{
195totalProjects: number;
196totalFiles: number;
402};
403404// Helper functions for project and file management
405406/**
407* Get a user by ID
408*/
409export async function getUser(userId: string): Promise<User | null> {
410const result = await sqlite.execute(
411`SELECT * FROM ${tablePrefix}_users WHERE id = ?`,
426* Insert or update a user if it's newer than existing data
427*/
428export async function upsertUser(user: User): Promise<boolean> {
429// Check if user exists and compare timestamps
430const existingUser = await getUser(user.id);
469* Get a project by ID
470*/
471async function getProject(projectId: string): Promise<Project | null> {
472const result = await sqlite.execute(
473`SELECT * FROM ${tablePrefix}_projects WHERE id = ?`,
488* Insert or update a project if it's newer than existing data
489*/
490export async function upsertProject(project: Project): Promise<boolean> {
491// Convert Date object to string if needed
492const updatedAt = project.updated_at;
540* Get a file by ID
541*/
542async function getFile(fileId: string): Promise<File | null> {
543const result = await sqlite.execute(
544`SELECT * FROM ${tablePrefix}_files WHERE id = ?`,
559* Insert or update a file if it's newer than existing data
560*/
561export async function upsertFile(file: File): Promise<boolean> {
562// Convert Date object to string if needed
563608* Extract matched lines with context around matches
609*/
610function extractMatchedLines(
611content: string,
612searchText: string,
668* Search for files containing specific text
669*/
670export async function searchFileContent(
671searchText: string,
672): Promise<FileSearchResult[]> {
716* Count total file search results
717*/
718export async function countFileSearchResults(searchText: string): Promise<number> {
719const searchPattern = `%${searchText}%`;
720734* Count total project search results
735*/
736export async function countProjectSearchResults(searchText: string): Promise<number> {
737const searchPattern = `%${searchText}%`;
738751* Count total user search results
752*/
753export async function countUserSearchResults(searchText: string): Promise<number> {
754const searchPattern = `%${searchText}%`;
755768* Search for projects matching the query
769*/
770export async function searchProjects(
771searchText: string,
772page: number = 1,
803* Search for users matching the query
804*/
805export async function searchUsers(
806searchText: string,
807page: number = 1,
844* Enhanced search that returns matched content with context and pagination
845*/
846export async function searchFileContentWithContext(
847searchText: string,
848contextLines: number = 2,
1049* Get most recently edited vals (files) within a time period for newsletter curation
1050*/
1051export async function getMostEditedVals(
1052daysBack: number = 30,
1053limit: number = 50
1113* Activity is measured by number of distinct edit sessions, not total file changes
1114*/
1115export async function getMostActiveProjectsForNewsletter(
1116daysBack: number = 30,
1117limit: number = 50
charmaineValSearchcomponents.tsx25 matches
1920// Define the Activity Heatmap component
21export function ActivityHeatmap({ activityData }: { activityData: { date: string; count: number }[] }) {
22// Convert activity data to a map for easier lookup
23const activityMap = new Map(activityData.map(item => [item.date, item.count]));
159160// Helper to highlight the search terms in the code
161export function highlightText(text: string, searchTerm: string): JSX.Element {
162if (!searchTerm) return <>{text}</>;
163180181// CodeBlock component for displaying code with line numbers
182export function CodeBlock(
183{ matchedLines, searchTerm, totalMatches: _totalMatches }: {
184matchedLines: EnhancedSearchResult["matchedLines"];
206207// File search result component
208export function FileSearchResultComponent(
209{ result, searchTerm }: { result: EnhancedSearchResult; searchTerm: string },
210) {
270271// Project search result component
272export function ProjectSearchResultComponent(
273{ result, searchTerm }: { result: ProjectSearchResult; searchTerm: string },
274) {
336337// User search result component
338export function UserSearchResultComponent(
339{ result, searchTerm }: { result: UserSearchResult; searchTerm: string },
340) {
395396// Sub-section result for docs
397export function SubDocResultComponent(
398{ result, _searchTerm }: { result: SubDocResult; _searchTerm: string },
399) {
416417// Doc search result component
418export function DocSearchResultComponent(
419{ result, searchTerm }: { result: DocSearchResult; searchTerm: string },
420) {
471472// Result count tabs component
473export function ResultTypeTabs({
474totalFileResults,
475totalProjectResults,
519520// Pagination component
521export function Pagination({
522currentPage,
523totalPages,
624625// Sample results component for preview of other result types
626export function SampleResultsSection({
627title,
628linkText,
661662// Main search page component
663export function SearchPage({
664fileResults,
665projectResults,
1225<a href="?q=database" className="example-link">database</a>
1226<a href="?q=image" className="example-link">image</a>
1227<a href="?q=function" className="example-link">function</a>
1228<a href="?q=discord" className="example-link">discord</a>
1229<a href="?q=openai" className="example-link">openai</a>
1379<a href="?q=database" className="example-link">database</a>
1380<a href="?q=image" className="example-link">image</a>
1381<a href="?q=function" className="example-link">function</a>
1382<a href="?q=discord" className="example-link">discord</a>
1383<a href="?q=openai" className="example-link">openai</a>
13971398// Newsletter curation components
1399export function EditedValCard({ val }: {
1400val: EditedValResult;
1401}) {
1448}
14491450export function NewsletterProjectCard({ project }: {
1451project: NewsletterProjectResult;
1452}) {
1500}
15011502export function NewsletterCurationPage({
1503activeProjects,
1504daysBack,
2096const SELECTED_PROJECTS_KEY = 'newsletter_selected_projects';
2097
2098function getSelectedProjects() {
2099try {
2100return JSON.parse(localStorage.getItem(SELECTED_PROJECTS_KEY) || '[]');
2104}
2105
2106function setSelectedProjects(projects) {
2107localStorage.setItem(SELECTED_PROJECTS_KEY, JSON.stringify(projects));
2108}
2109
2110function toggleSelectedProject(id) {
2111const selected = getSelectedProjects();
2112const index = selected.indexOf(id);
2122}
2123
2124function selectAllOnPage() {
2125const projectButtons = document.querySelectorAll('.corner-select');
2126const selected = getSelectedProjects();
2137}
2138
2139function clearSelection() {
2140setSelectedProjects([]);
2141updateSelectedUI();
2142}
2143
2144function exportSelectedToMarkdown() {
2145const selected = getSelectedProjects();
2146if (selected.length === 0) return;
2201}
2202
2203function updateSelectedUI() {
2204const selectedProjects = getSelectedProjects();
2205
22342235// Initialize on page load
2236document.addEventListener('DOMContentLoaded', function() {
2237// Add click handlers to select buttons
2238document.querySelectorAll('.corner-select').forEach(button => {
charmaineValSearchclient.tsx12 matches
1// Client-side script for typeahead and keyboard navigation
2export const clientScript = `
3document.addEventListener('DOMContentLoaded', function() {
4const searchInput = document.getElementById('search-input');
5const resultsContainer = document.getElementById('typeahead-results');
11let selectedIndex = -1;
1213// Function to fetch typeahead results
14async function fetchTypeahead(query) {
15if (query.length < 1) {
16hideResults();
61}
6263// Function to display results
64function displayResults(results, query) {
65// Clear previous results
66resultsContainer.innerHTML = '';
102}
103104// Function to hide results
105function hideResults() {
106resultsContainer.classList.remove('active');
107selectedIndex = -1;
109110// Input event to trigger typeahead
111searchInput.addEventListener('input', function() {
112const query = this.value.trim();
113135136// Handle keyboard navigation
137searchInput.addEventListener('keydown', function(e) {
138const items = resultsContainer.querySelectorAll('.typeahead-item');
139167168// Update selection highlight
169function updateSelection(items) {
170items.forEach((item, i) => {
171if (i === selectedIndex) {
178179// Close results when clicking outside
180document.addEventListener('click', function(e) {
181if (!searchInput.contains(e.target) && !resultsContainer.contains(e.target)) {
182hideResults();
185186// Handle mouse movement to keep the search term item highlighted
187resultsContainer.addEventListener('mouseover', function(e) {
188// Find the search term item (last child)
189const searchItem = resultsContainer.querySelector('.search-term');
charmaineValSearchapi.tsx3 matches
1516// Handle typeahead API requests
17export function handleTypeahead(req: Request): Response {
18const url = new URL(req.url);
19const searchTerm = url.searchParams.get("q") || "";
4748// Newsletter curation route
49export async function handleNewsletterCuration(req: Request): Promise<Response> {
50const url = new URL(req.url);
51const daysParam = url.searchParams.get("days") || "30";
115116// Main request handler
117export async function handler(req: Request): Promise<Response> {
118const url = new URL(req.url);
119
LoopsNewsletterFormform.ts1 match
1import { serveFile } from "https://esm.town/v/std/utils@85-main/index.ts";
23export default async function(req: Request): Promise<Response> {
4// serve public files at the root
5const url = new URL(req.url);