15}
16
17export function TopicList() {
18 const navigation = useNavigation();
19 const { topics } = useLoaderData<TopicListProps>();
12}
13
14export function TopicDetail() {
15 const { topic, messages } = useLoaderData() as TopicDetailData;
16 const { messageId } = useParams();
1import { ActionFunctionArgs } from "https://esm.sh/react-router@7.5.0?deps=react@18.2.0,react-dom@18.2.0";
2import { createMessage } from "../backend/database/queries.ts";
3
4export async function action({ request }: ActionFunctionArgs) {
5 console.log("HERE!");
6 const formData = await request.formData();
5import { SearchForm } from "../frontend/components/SearchForm.tsx";
6
7export function Search() {
8 const { topics, messages, query } = useLoaderData() as SearchResultsType;
9 const hasResults = topics.length > 0 || messages.length > 0;
5import { SearchForm } from "./SearchForm.tsx";
6
7export function SearchResults() {
8 const { topics, messages, query } = useLoaderData() as SearchResultsType;
9 const hasResults = topics.length > 0 || messages.length > 0;
1import { LoaderFunctionArgs } from "https://esm.sh/react-router@7.5.0?deps=react@18.2.0,react-dom@18.2.0";
2import { search } from "../backend/database/queries.ts";
3
4export async function loader({ request }: LoaderFunctionArgs) {
5 const url = new URL(request.url);
6 const query = url.searchParams.get("q") || "";
4import { LoadingSpinner } from "./LoadingSpinner.tsx";
5
6export function SearchForm() {
7 const navigation = useNavigation();
8 const [searchParams] = useSearchParams();
10- **Messaging System**: Post messages in topics
11- **Direct Message Links**: Link directly to specific messages via timestamps
12- **Search Functionality**: Search topics and messages with URL parameters
13- **Loading Indicators**: Visual feedback during async operations
14
6 * Get all topics ordered by creation date (newest first)
7 */
8export async function getAllTopics(): Promise<Topic[]> {
9 const result = await sqlite.execute(`
10 SELECT id, title, createdAt
18 * Get a single topic by ID
19 */
20export async function getTopicById(id: number): Promise<Topic | null> {
21 const result = await sqlite.execute(
22 `
34 * Create a new topic
35 */
36export async function createTopic(title: string): Promise<Topic> {
37 const createdAt = new Date().toISOString();
38
52 * Get all messages for a topic
53 */
54export async function getMessagesByTopicId(topicId: number): Promise<Message[]> {
55 const result = await sqlite.execute(
56 `
69 * Get a single message by ID
70 */
71export async function getMessageById(id: number): Promise<Message | null> {
72 const result = await sqlite.execute(
73 `
85 * Create a new message in a topic
86 */
87export async function createMessage(topicId: number, content: string): Promise<Message> {
88 const createdAt = new Date().toISOString();
89
103 * Search for topics and messages containing the query string
104 */
105export async function search(query: string): Promise<SearchResults> {
106 // Search in topics
107 const topicsResult = await sqlite.execute(
8 * Initialize the database schema
9 */
10export async function initializeDatabase() {
11 // Create topics table
12 await sqlite.execute(`
46 * Seed the database with initial data for demonstration
47 */
48async function seedInitialData() {
49 // Insert sample topics
50 await sqlite.execute(`
68 (${welcomeTopicId}, 'Welcome to our community message board! Feel free to browse around and join the discussions.', '${new Date().toISOString()}'),
69 (${welcomeTopicId}, 'If you have any questions, just post them here!', '${new Date(Date.now() - 3600000).toISOString()}'),
70 (${tipsTopicId}, 'Val Town makes it easy to build and share serverless functions.', '${new Date().toISOString()}'),
71 (${tipsTopicId}, 'You can use TypeScript for better type safety in your projects.', '${new Date(Date.now() - 7200000).toISOString()}'),
72 (${introTopicId}, 'Hi everyone! I\'m the creator of this message board example.', '${new Date().toISOString()}')
Helper function to send Discord messages
Simple functional CSS library for Val Town
import { OpenAI } from "https://esm.town/v/std/openai";
export default async function(req: Request): Promise<Response> {
if (req.method === "OPTIONS") {
return new Response(null, {
headers: {
"Access-Control-Allow-Origin": "*",
LangChain (https://langchain.com) Ambassador, KubeSphere (https://kubesphere.io) Ambassador, CNCF OpenFunction (https://openfunction.dev) TOC Member.