Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
24 changes: 15 additions & 9 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Open Source Bazaar - GitHub Copilot Instructions

Open Source Bazaar is an open-source project showcase platform built with Next.js 15, TypeScript, React Bootstrap, and MobX. It includes license filters, Wiki knowledge base, volunteer showcase, Lark integration, and other features.
Open Source Bazaar is an open-source project showcase platform built with Next.js, TypeScript, Idea React 3 (Bootstrap 6), and MobX. It includes license filters, Wiki knowledge base, volunteer showcase, Lark integration, and other features.

Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.

Expand Down Expand Up @@ -48,7 +48,7 @@ After making ANY changes, ALWAYS validate by running through these scenarios:
- Volunteer page: http://localhost:3000/volunteer (contributor showcase)
- Projects: http://localhost:3000/project (GitHub repository listings)
4. **Test API endpoints**: Verify GitHub API integrations work
5. **Check responsive design**: Test mobile/desktop layouts with React Bootstrap components
5. **Check responsive design**: Test mobile/desktop layouts with Idea React components
6. **Verify i18n functionality**: Check Chinese/English language switching works

### Pre-commit Validation
Expand Down Expand Up @@ -81,7 +81,7 @@ npm test # Runs linting + staged file checks
### Key Dependencies

- **Next.js 15** - React framework
- **React Bootstrap 2.10** - UI component library
- **Idea React 3 / Bootstrap 6** - UI component library and CSS framework
- **MobX 6.13** - State management
- **MobX-GitHub 0.4** - GitHub API integration
- **MobX-i18n 0.7** - Internationalization
Expand All @@ -96,7 +96,7 @@ Based on comprehensive PR review analysis, follow these critical development sta

#### Component and Import Standards

- **ALWAYS use React Bootstrap components** instead of custom HTML elements
- **Prefer Idea React components** for Bootstrap UI patterns instead of recreating them with custom elements
- Use utilities from established libraries: 'web-utility'
- Import `'./Base'` in model files for proper configuration

Expand All @@ -110,14 +110,20 @@ Based on comprehensive PR review analysis, follow these critical development sta
#### Component Usage Patterns

```typescript
// ✅ Correct - use React Bootstrap components
import { Button, Badge, Breadcrumb, Card, Container } from 'react-bootstrap';
// ✅ Correct - use Idea React components
import { Badge, Button, Breadcrumb, BreadcrumbItem, BreadcrumbLink, Card, Container } from 'idea-react';

<Button variant="outline-primary" size="sm" href={url} target="_blank">
<Button theme="primary" variant="outline" size="sm" href={url} target="_blank">
{t('edit_on_github')}
</Button>

<Badge bg="secondary">{label}</Badge>
<Badge theme="secondary">{label}</Badge>

<Breadcrumb>
<BreadcrumbItem>
<BreadcrumbLink href="/">{t('open_source_bazaar')}</BreadcrumbLink>
</BreadcrumbItem>
</Breadcrumb>

// ❌ Wrong - custom HTML elements
<a href={url} className="btn btn-outline-primary">Edit</a>
Expand Down Expand Up @@ -242,7 +248,7 @@ pnpm test # Run tests (lint-staged + lint, 15s)

#### Component and Styling Issues

- **Custom HTML not working**: Replace with React Bootstrap components
- **Bootstrap UI not working**: Prefer Idea React components and Bootstrap 6 utilities
- **Translation not showing**: Ensure all text uses `t()` function and keys exist in all language files
- **GitHub API errors**: Verify you're using configured `githubClient` from `models/Base.ts`

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@

## 技术栈

- Language: [TypeScript v5][2]
- Language: [TypeScript v6][2]
- Component engine: [Nextjs v16][3]
- Component suite: [Bootstrap v5][4]
- Component suite: [Bootstrap v6][4]
- CI / CD: GitHub [Actions][10] + [Vercel][11]

## 开始
Expand Down
27 changes: 13 additions & 14 deletions components/Activity/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { TimeDistance } from 'idea-react';
import { Card, CardBody, CardText, CardTitle, Col, Row, TimeDistance } from 'idea-react';
import { TableCellLocation } from 'mobx-lark';
import { BadgeBar } from 'mobx-restful-table';
import type { FC } from 'react';
import { Card, Col, Row } from 'react-bootstrap';

import { type Activity, ActivityModel } from '../../models/Activity';
import { LarkImage } from '../LarkImage';
import { TimeOption } from '../data';
import { BadgeBar } from 'mobx-restful-table';
import { LarkImage } from '../LarkImage';

export interface ActivityCardProps extends Activity {
className?: string;
Expand Down Expand Up @@ -36,41 +35,41 @@ export const ActivityCard: FC<ActivityCardProps> = ({
/>
</div>
</div>
<Card.Body className="d-flex flex-column">
<Card.Title as="h3" className="h5 flex-fill">
<CardBody className="d-flex flex-column">
<CardTitle as="h3" className="h5 flex-fill">
<a
className="text-decoration-none text-secondary text-truncate-lines"
className="text-decoration-none fg-secondary text-truncate-lines"
href={ActivityModel.getLink({ id, ...activity })}
>
{name as string}
</a>
</Card.Title>
</CardTitle>

<Row className="mt-2 flex-fill">
<Row className="mt-3 flex-fill">
<Col className="text-start">
<Card.Text
<CardText
className="mt-1 text-truncate"
title={(location as TableCellLocation)?.full_address}
>
<span className="me-1">{city as string}</span>

{(location as TableCellLocation)?.full_address}
</Card.Text>
</CardText>
</Col>
</Row>
<Row as="footer" className="flex-fill small mt-1">
<Col xs={8}>
<Col span={8}>
<BadgeBar
list={(host as string[]).map(text => ({
text,
link: `/search/activity?keywords=${text}`,
}))}
/>
</Col>
<Col className="text-end" xs={4}>
<Col className="text-end" span={4}>
<TimeDistance {...TimeOption} date={startTime as number} />
</Col>
</Row>
</Card.Body>
</CardBody>
</Card>
);
26 changes: 13 additions & 13 deletions components/Activity/Hackathon/ActionHub.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Col, Container, Row } from 'idea-react';
import type { FC, PropsWithChildren, ReactNode } from 'react';
import { Col, Container, Row } from 'react-bootstrap';

import { HackathonHeroAction } from './Hero';
import styles from './ActionHub.module.less';
import { HackathonHeroAction } from './Hero';

export interface HackathonActionHubEntry {
count: number;
Expand Down Expand Up @@ -40,17 +40,17 @@ const ActionEntryCard: FC<{ entry: HackathonActionHubEntry; step: string }> = ({
<span className={styles.entryStep}>
{step} · {entry.eyebrow}
</span>
<h4 className="mt-2 mb-2">{entry.title}</h4>
<h4 className="mt-3 mb-3">{entry.title}</h4>
<p>{entry.description}</p>

<div className={`${styles.entryMetaRow} d-flex flex-wrap gap-2 my-3`}>
<div className={`${styles.entryMetaRow} d-flex flex-wrap gap-3 my-5`}>
<span className={`${styles.entryMeta} d-inline-flex align-items-center`}>{entry.count}</span>
<span className={`${styles.entryMeta} d-inline-flex align-items-center`}>
{entry.eyebrow}
</span>
</div>

<nav className={`${styles.entryLinks} d-flex flex-wrap gap-3`} aria-label={entry.title}>
<nav className={`${styles.entryLinks} d-flex flex-wrap gap-5`} aria-label={entry.title}>
{entry.links.map(link => (
<a
key={`${link.label}-${link.href}`}
Expand Down Expand Up @@ -81,15 +81,15 @@ export const HackathonActionHub: FC<PropsWithChildren<HackathonActionHubProps>>
<article className={styles.registerCard}>
<div className={styles.registerCardInner}>
<p className={`${styles.regEyebrow} mb-1`}>{title}</p>
<h2 className={`${styles.regTitle} mt-2`}>{primaryTitle}</h2>
<p className={`${styles.regDesc} mt-3 mb-4`}>{primaryDescription}</p>
<h2 className={`${styles.regTitle} mt-3`}>{primaryTitle}</h2>
<p className={`${styles.regDesc} mt-5 mb-7`}>{primaryDescription}</p>

<nav className={`${styles.regActions} d-flex flex-wrap gap-3`} aria-label={title}>
<nav className={`${styles.regActions} d-flex flex-wrap gap-5`} aria-label={title}>
{primaryAction && <HackathonActionHubLink action={primaryAction} variant="primary" />}
{children}
</nav>

<ul className={`list-unstyled ${styles.regFacts} d-flex flex-wrap gap-2 mt-4`}>
<ul className={`list-unstyled ${styles.regFacts} d-flex flex-wrap gap-3 mt-7`}>
{facts.map((fact, index) => (
<li key={index}>{fact}</li>
))}
Expand All @@ -98,14 +98,14 @@ export const HackathonActionHub: FC<PropsWithChildren<HackathonActionHubProps>>
</article>

<div className={styles.entryHub}>
<header className={`${styles.entryHubHead} mb-4`}>
<header className={`${styles.entryHubHead} mb-7`}>
<p className={`${styles.entryEyebrow} mb-1`}>{subtitle}</p>
<h3 className={`${styles.entryTitle} mt-2`}>{title}</h3>
<h3 className={`${styles.entryTitle} mt-3`}>{title}</h3>
</header>

<Row as="ol" className="list-unstyled g-3 mb-0">
<Row as="ol" className="list-unstyled g-5 mb-0">
{entries.map((entry, index) => (
<Col as="li" key={entry.title} md={6}>
<Col key={entry.title} as="li" md={6}>
<ActionEntryCard entry={entry} step={String(index + 1).padStart(2, '0')} />
</Col>
))}
Expand Down
20 changes: 10 additions & 10 deletions components/Activity/Hackathon/Awards.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Container } from 'idea-react';
import { TableCellValue } from 'mobx-lark';
import { FC } from 'react';
import { Container } from 'react-bootstrap';

import { LarkImage } from '../../LarkImage';
import type { HackathonHeroAction } from './Hero';
import styles from './Awards.module.less';
import type { HackathonHeroAction } from './Hero';

export interface HackathonAwardsMeta<Value = string> {
label: string;
Expand Down Expand Up @@ -110,23 +110,23 @@ export const HackathonAwards: FC<HackathonAwardsProps> = ({
<div className={styles.accentLine} />
</header>

<div className={`${styles.awardsGrid} gap-3`}>
<div className={`${styles.awardsGrid} gap-5`}>
{prizes.map(prize => (
<PrizeCard key={prize.id} {...prize} />
))}
</div>

{criteria?.[0] && (
<article className={`${styles.judgingCard} mt-4`}>
<h3 className={`${styles.judgingTitle} mb-3`}>{subtitle}</h3>
<article className={`${styles.judgingCard} mt-7`}>
<h3 className={`${styles.judgingTitle} mb-5`}>{subtitle}</h3>

<ul className={`list-unstyled ${styles.criteriaGrid}`}>
{criteria.map(({ description, id, title, weight }) => (
<li key={id} className={`${styles.criterion} d-grid align-items-start gap-3`}>
<li key={id} className={`${styles.criterion} d-grid align-items-start gap-5`}>
<span className={styles.criterionWeight}>{weight}</span>
<div>
<strong className={styles.criterionTitle}>{title}</strong>
<p className={`${styles.criterionDescription} mt-2 mb-0`}>{description}</p>
<p className={`${styles.criterionDescription} mt-3 mb-0`}>{description}</p>
</div>
</li>
))}
Expand All @@ -137,10 +137,10 @@ export const HackathonAwards: FC<HackathonAwardsProps> = ({
)}

{organizations[0] && (
<div className={`${styles.supportCard} mt-4`}>
<div className={`${styles.supportCard} mt-7`}>
<div className={`${styles.supportCopy} d-flex flex-column justify-content-center`}>
<p className={`${styles.supportEyebrow} mb-1`}>{supportEyebrow}</p>
<h3 className={`${styles.supportTitle} mt-2`}>{supportTitle}</h3>
<h3 className={`${styles.supportTitle} mt-3`}>{supportTitle}</h3>
<p className={styles.supportDescription}>{supportDescription}</p>
</div>

Expand All @@ -152,7 +152,7 @@ export const HackathonAwards: FC<HackathonAwardsProps> = ({

{supportAction && (
<a
className={`${styles.supportLink} d-inline-flex align-items-center mt-2`}
className={`${styles.supportLink} d-inline-flex align-items-center mt-3`}
href={supportAction.href}
{...(supportAction.external && { target: '_blank', rel: 'noreferrer' })}
>
Expand Down
6 changes: 3 additions & 3 deletions components/Activity/Hackathon/FAQ.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Container } from 'idea-react';
import { FC } from 'react';
import { Container } from 'react-bootstrap';

import styles from './FAQ.module.less';

Expand All @@ -20,11 +20,11 @@ export const HackathonFAQ: FC<HackathonFAQProps> = ({ items, subtitle, title })
<div className={styles.accentLine} />
</header>

<div className={`${styles.faqGrid} d-grid gap-3`}>
<div className={`${styles.faqGrid} d-grid gap-5`}>
{items.map(({ answer, id, question }) => (
<details key={id} className={styles.faqItem}>
<summary className={styles.faqQuestion}>{question}</summary>
<p className={`${styles.faqAnswer} mt-3 mb-0`}>{answer}</p>
<p className={`${styles.faqAnswer} mt-5 mb-0`}>{answer}</p>
</details>
))}
</div>
Expand Down
Loading
Loading