Codespace değişiklikleri kaydedildi

pull/8418/head
Halovisionx 3 weeks ago
parent 6c6c9ea85d
commit ddde6db491
  1. 1
      .astro/types.d.ts
  2. 2
      astro.config.mjs
  3. 7434
      package-lock.json
  4. 96
      package.json
  5. 7228
      pnpm-lock.yaml
  6. 7
      postcss.config.cjs
  7. 7
      postcss.config.js
  8. BIN
      public/og-images/guides/ai-data-scientist-career-path.png
  9. BIN
      public/og-images/guides/ai-data-scientist-lifecycle.png
  10. BIN
      public/og-images/guides/ai-data-scientist-skills.png
  11. BIN
      public/og-images/guides/ai-data-scientist-tools.png
  12. BIN
      public/og-images/roadmaps/ai-engineer.png
  13. BIN
      public/og-images/roadmaps/api-design.png
  14. BIN
      public/og-images/roadmaps/cloudflare.png
  15. BIN
      public/og-images/roadmaps/devrel.png
  16. BIN
      public/og-images/roadmaps/engineering-manager.png
  17. BIN
      public/og-images/roadmaps/git-github.png
  18. BIN
      public/og-images/roadmaps/ios.png
  19. BIN
      public/og-images/roadmaps/php.png
  20. BIN
      public/og-images/roadmaps/product-manager.png
  21. BIN
      public/og-images/roadmaps/redis.png
  22. BIN
      public/og-images/roadmaps/terraform.png
  23. 86
      server.cjs
  24. 18
      src/components/AccountStreak/AccountStreakHeatmap.tsx
  25. 2
      src/components/Activity/ResourceProgress.tsx
  26. 1
      src/components/Dashboard/DashboardAiRoadmaps.tsx
  27. 4
      src/components/Dashboard/DashboardPage.tsx
  28. 2
      src/components/Dashboard/DashboardProgressCard.tsx
  29. 1
      src/components/Dashboard/ListDashboardCustomProgress.tsx
  30. 36
      src/components/GenerateCourse/AICourseRoadmapView.tsx
  31. 5
      src/components/GenerateCourse/FAQs.ts
  32. 2
      src/components/GenerateCourse/ModifyCoursePrompt.tsx
  33. 9
      src/components/GenerateCourse/RegenerateLesson.tsx
  34. 2
      src/components/GenerateCourse/RegenerateOutline.tsx
  35. 13
      src/components/GenerateRoadmap/GenerateRoadmap.tsx
  36. 11
      src/components/Projects/StatusStepper/ProjectStepper.tsx
  37. 42
      src/components/SQLCourse/ReviewsSection.tsx
  38. 4
      src/components/TeamProgress/MemberProgressModal.tsx
  39. 6
      src/components/Toast.tsx
  40. 2
      src/components/UserProgress/UserProgressModal.tsx
  41. 16
      src/components/UserPublicProfile/UserPublicActivityHeatmap.tsx
  42. 1
      src/components/UserPublicProfile/UserPublicProfileHeader.tsx
  43. 7
      src/lib/jsonld-schema.ts
  44. 7
      src/utils/classname.ts
  45. 1
      src/utils/roadmapUtils.d.ts
  46. 11
      src/utils/roadmapUtils.ts
  47. 63
      test-ai-tutor.html
  48. 6
      tsconfig.json

1
.astro/types.d.ts vendored

@ -1 +1,2 @@
/// <reference types="astro/client" />
/// <reference path="content.d.ts" />

@ -51,7 +51,7 @@ export default defineConfig({
],
],
},
output: 'hybrid',
output: 'static',
adapter: node({
mode: 'standalone',
}),

7434
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -6,7 +6,7 @@
"scripts": {
"dev": "astro dev --port 3000",
"start": "astro dev",
"build": "astro build",
"build": "astro build",
"preview": "astro preview",
"format": "prettier --write .",
"gh-labels": "./scripts/create-roadmap-labels.sh",
@ -29,81 +29,85 @@
"test:e2e": "playwright test"
},
"dependencies": {
"@astrojs/node": "^8.3.4",
"@astrojs/react": "^3.6.2",
"@astrojs/sitemap": "^3.2.0",
"@astrojs/tailwind": "^5.1.2",
"@fingerprintjs/fingerprintjs": "^4.5.0",
"@astrojs/node": "^9.1.3",
"@astrojs/react": "^4.2.2",
"@astrojs/sitemap": "^3.3.0",
"@astrojs/tailwind": "^6.0.2",
"@fingerprintjs/fingerprintjs": "^4.6.1",
"@microsoft/clarity": "^1.0.0",
"@nanostores/react": "^0.8.0",
"@nanostores/react": "^0.8.4",
"@napi-rs/image": "^1.9.2",
"@resvg/resvg-js": "^2.6.2",
"@tanstack/react-query": "^5.59.16",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.1",
"astro": "^4.16.1",
"@tanstack/react-query": "^5.69.0",
"@types/react": "^19.0.12",
"@types/react-dom": "^19.0.4",
"astro": "^5.5.5",
"clsx": "^2.1.1",
"compression": "^1.8.0",
"cors": "^2.8.5",
"dayjs": "^1.11.13",
"dom-to-image": "^2.6.0",
"dracula-prism": "^2.1.16",
"express": "^4.21.2",
"gray-matter": "^4.0.3",
"htm": "^3.1.1",
"image-size": "^1.1.1",
"jose": "^5.9.4",
"image-size": "^2.0.1",
"jose": "^6.0.10",
"js-cookie": "^3.0.5",
"lucide-react": "^0.452.0",
"luxon": "^3.5.0",
"markdown-it-async": "^2.0.0",
"nanoid": "^5.0.7",
"nanostores": "^0.11.3",
"node-html-parser": "^6.1.13",
"npm-check-updates": "^17.1.3",
"playwright": "^1.48.0",
"prismjs": "^1.29.0",
"react": "^18.3.1",
"react-calendar-heatmap": "^1.9.0",
"react-confetti": "^6.1.0",
"react-dom": "^18.3.1",
"react-textarea-autosize": "^8.5.7",
"jsonwebtoken": "^9.0.2",
"lucide-react": "^0.484.0",
"luxon": "^3.6.0",
"markdown-it-async": "^2.2.0",
"nanoid": "^5.1.5",
"nanostores": "^0.11.4",
"node-html-parser": "^7.0.1",
"npm-check-updates": "^17.1.16",
"playwright": "^1.51.1",
"prismjs": "^1.30.0",
"react": "^19.0.0",
"react-calendar-heatmap": "^1.10.0",
"react-confetti": "^6.4.0",
"react-dom": "^19.0.0",
"react-textarea-autosize": "^8.5.8",
"react-tooltip": "^5.28.0",
"reactflow": "^11.11.4",
"rehype-external-links": "^3.0.0",
"remark-parse": "^11.0.0",
"roadmap-renderer": "^1.0.6",
"sanitize-html": "^2.13.1",
"satori": "^0.11.2",
"roadmap-renderer": "^1.0.7",
"sanitize-html": "^2.15.0",
"satori": "^0.12.1",
"satori-html": "^0.3.2",
"sharp": "^0.33.5",
"shiki": "^3.1.0",
"shiki": "^3.2.1",
"slugify": "^1.6.6",
"tailwind-merge": "^2.5.3",
"tailwindcss": "^3.4.13",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^3.4.17",
"tiptap-markdown": "^0.8.10",
"turndown": "^7.2.0",
"unified": "^11.0.5",
"zustand": "^4.5.5"
"zustand": "^5.0.3"
},
"devDependencies": {
"@ai-sdk/google": "^1.1.19",
"@playwright/test": "^1.48.0",
"@tailwindcss/typography": "^0.5.15",
"@ai-sdk/google": "^1.2.3",
"@playwright/test": "^1.51.1",
"@tailwindcss/typography": "^0.5.16",
"@types/dom-to-image": "^2.6.7",
"@types/js-cookie": "^3.0.6",
"@types/luxon": "^3.4.2",
"@types/prismjs": "^1.26.4",
"@types/react-calendar-heatmap": "^1.6.7",
"@types/prismjs": "^1.26.5",
"@types/react-calendar-heatmap": "^1.9.0",
"@types/react-slick": "^0.23.13",
"@types/sanitize-html": "^2.13.0",
"@types/turndown": "^5.0.5",
"ai": "^4.1.51",
"csv-parser": "^3.0.0",
"gh-pages": "^6.2.0",
"ai": "^4.2.5",
"csv-parser": "^3.2.0",
"gh-pages": "^6.3.0",
"js-yaml": "^4.1.0",
"markdown-it": "^14.1.0",
"openai": "^4.67.3",
"prettier": "^3.3.3",
"openai": "^4.89.1",
"prettier": "^3.5.3",
"prettier-plugin-astro": "^0.14.1",
"prettier-plugin-tailwindcss": "^0.6.8",
"tsx": "^4.19.1"
"prettier-plugin-tailwindcss": "^0.6.11",
"tsx": "^4.19.3"
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,7 @@
module.exports = {
plugins: [
require('@tailwindcss/postcss'),
require('autoprefixer'),
// ...existing plugins...
],
};

@ -0,0 +1,7 @@
module.exports = {
plugins: {
'@tailwindcss/postcss7-compat': {},
tailwindcss: {},
autoprefixer: {},
},
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

@ -0,0 +1,86 @@
const express = require('express');
const cors = require('cors');
const compression = require('compression');
const jwt = require('jsonwebtoken'); // JWT kütüphanesini ekleyin
const app = express();
const SECRET_KEY = 'your_secret_key'; // Güvenli bir anahtar belirleyin
// Middleware'ler
app.use(cors({
origin: ['https://legendary-disco-pjww576pvjpq37xg7-4321.app.github.dev', 'https://legendary-disco-pjww576pvjpq37xg7-5500.app.github.dev'], // İzin verilen kökenler
methods: ['GET', 'POST'], // İzin verilen HTTP metodları
credentials: true, // Çerezlerin gönderilmesine izin ver
}));
app.use(express.json()); // JSON gövdesini ayrıştırmak için
app.use(compression());
app.use((req, res, next) => {
res.cookie('exampleCookie', 'value', {
httpOnly: true,
secure: true,
sameSite: 'None', // Üçüncü taraf çerezler için gerekli
});
next();
});
// Kök URL için bir uç nokta
app.get('/', (req, res) => {
res.send('Welcome to the AI Tutor API!');
});
// Login uç noktası
app.post('/login', (req, res) => {
const { username, password } = req.body;
// Basit bir kullanıcı doğrulama (örnek)
if (username === 'admin' && password === 'password') {
// Kullanıcı bilgileriyle bir JWT oluştur
const token = jwt.sign({ username }, SECRET_KEY, { expiresIn: '1h' });
return res.json({ token });
}
res.status(401).json({ message: 'Invalid credentials' });
});
// JWT doğrulama middleware'i
function authenticateToken(req, res, next) {
const token = req.headers['authorization']?.split(' ')[1] || req.query.token; // Bearer token veya URL parametresi
if (!token) {
return res.status(403).json({ message: 'Token is required' });
}
jwt.verify(token, SECRET_KEY, (err, user) => {
if (err) {
return res.status(403).json({ message: 'Invalid token' });
}
req.user = user; // Doğrulanmış kullanıcıyı isteğe ekle
next();
});
}
// Korunan bir uç nokta
app.get('/protected', authenticateToken, (req, res) => {
res.json({ message: `Hello, ${req.user.username}! This is a protected route.` });
});
// AI Tutor uç noktası
app.get('/ai-tutor', authenticateToken, (req, res) => {
res.json({ message: `Welcome to AI Tutor, ${req.user.username}!` });
});
// Yeni bir AI Tutor fonksiyonu
app.post('/ai-tutor/calculate', authenticateToken, (req, res) => {
const { input } = req.body;
if (!input) {
return res.status(400).json({ message: 'Input is required' });
}
// Örnek bir hesaplama işlemi
const result = `Processed input: ${input}`;
res.json({ result });
});
// Sunucuyu başlat
const PORT = process.env.PORT || 3001; // 3001 numaralı portu kullan
app.listen(PORT, () => console.log(`Server is running on http://localhost:${PORT}`));

@ -1,4 +1,5 @@
import CalendarHeatmap from 'react-calendar-heatmap';
import type { ReactCalendarHeatmapValue } from 'react-calendar-heatmap';
import dayjs from 'dayjs';
import { formatActivityDate } from '../../lib/date';
import { Tooltip as ReactTooltip } from 'react-tooltip';
@ -13,6 +14,8 @@ const legends = [
{ count: 20, color: 'bg-slate-200' },
];
type TooltipDataAttrs = { /* TooltipDataAttrs türünü burada tanımlayın */ };
type AccountStreakHeatmapProps = {};
export function AccountStreakHeatmap(props: AccountStreakHeatmapProps) {
@ -144,21 +147,16 @@ export function AccountStreakHeatmap(props: AccountStreakHeatmapProps) {
return 'fill-slate-600 rounded-md [rx:2px] focus:outline-none';
}
}}
tooltipDataAttrs={(value: any) => {
if (!value || !value.date) {
return null;
}
const formattedDate = formatActivityDate(value.date);
tooltipDataAttrs={(value: ReactCalendarHeatmapValue<string> | undefined): TooltipDataAttrs => {
return {
'data-tooltip-id': 'user-activity-tip',
'data-tooltip-content': `${value.count} Updates - ${formattedDate}`,
'data-tooltip-id': 'heatmap-tooltip',
'data-tooltip-content': value ? value.date : '',
};
}}
/>
<ReactTooltip
id="user-activity-tip"
id="heatmap-tooltip" // Düzeltilmiş id
className="!rounded-lg !bg-slate-900 !p-1 !px-2 !text-xs"
/>
@ -179,7 +177,7 @@ export function AccountStreakHeatmap(props: AccountStreakHeatmapProps) {
))}
<span className="ml-2 text-xs text-slate-500">More</span>
<ReactTooltip
id="user-activity-tip"
id="user-activity-tip" // Aynı id kullanımı düzeltildi
className="!rounded-lg !bg-slate-900 !p-1 !px-2 !text-sm"
/>
</div>

@ -75,7 +75,7 @@ export function ResourceProgress(props: ResourceProgressType) {
>
<span className="flex-grow truncate">{title}</span>
<span className="text-xs text-gray-400">
{parseInt(progressPercentage, 10)}%
{parseInt(progressPercentage.toString(), 10)}%
</span>
<span

@ -3,7 +3,6 @@ import { DashboardCustomProgressCard } from './DashboardCustomProgressCard';
import { DashboardCardLink } from './DashboardCardLink';
import { useState } from 'react';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
import { Simulate } from 'react-dom/test-utils';
import {
ArrowUpRight,
Bot,

@ -1,6 +1,6 @@
import { useStore } from '@nanostores/react';
import { useEffect, useState } from 'react';
import { cn } from '../../../editor/utils/classname';
import classNames from 'classnames'; // clsx yerine classnames kullanımı
import { useParams } from '../../hooks/use-params';
import { useToast } from '../../hooks/use-toast';
import { httpGet } from '../../lib/http';
@ -78,7 +78,7 @@ export function DashboardPage(props: DashboardPageProps) {
return (
<>
<div
className={cn('bg-slate-900', {
className={classNames('bg-slate-900', {
'striped-loader-slate': isLoading,
})}
>

@ -39,7 +39,7 @@ export function DashboardProgressCard(props: DashboardProgressCardProps) {
>
<span className="flex-grow truncate">{resourceTitle}</span>
<span className="text-xs text-gray-400">
{parseInt(progressPercentage, 10)}%
{parseInt(progressPercentage.toString(), 10)}%
</span>
<span

@ -3,7 +3,6 @@ import { DashboardCustomProgressCard } from './DashboardCustomProgressCard';
import { DashboardCardLink } from './DashboardCardLink';
import { useState } from 'react';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
import { Simulate } from 'react-dom/test-utils';
import {
ArrowUpRight,
Bot,

@ -1,20 +1,7 @@
import '../GenerateRoadmap/GenerateRoadmap.css';
import { renderFlowJSON } from '../../../editor/renderer/renderer';
import { generateAIRoadmapFromText } from '../../../editor/utils/roadmap-generator';
import {
generateAICourseRoadmapStructure,
readAIRoadmapStream,
type ResultItem,
} from '../../lib/ai';
import {
useCallback,
useEffect,
useRef,
useState,
type Dispatch,
type SetStateAction,
type MouseEvent,
} from 'react';
import { generateAICourseRoadmapStructure, readAIRoadmapStream, type ResultItem } from '../../lib/ai';
import { useCallback, useEffect, useRef, useState, type Dispatch, type SetStateAction, type MouseEvent } from 'react';
import type { AICourseViewMode } from './AICourseContent';
import { replaceChildren } from '../../lib/dom';
import { Frown, Loader2Icon } from 'lucide-react';
@ -24,6 +11,7 @@ import { useQuery } from '@tanstack/react-query';
import { billingDetailsOptions } from '../../queries/billing';
import { AICourseOutlineHeader } from './AICourseOutlineHeader';
import type { AiCourse } from '../../lib/ai';
import { generateAIRoadmapFromText } from '../../utils/roadmapUtils'; // 'someUtilityFunction' kaldırıldı
export type AICourseRoadmapViewProps = {
done: string[];
@ -101,15 +89,25 @@ export function AICourseRoadmapView(props: AICourseRoadmapViewProps) {
await readAIRoadmapStream(reader, {
onStream: async (result) => {
const roadmap = generateAICourseRoadmapStructure(result, true);
const { nodes, edges } = generateAIRoadmapFromText(roadmap);
const { nodes, edges } = generateAIRoadmapFromText({
nodes: roadmap.filter((item) => item.type === 'node' as any) as ResultItem[],
edges: roadmap.filter((item) => item.type === 'edge' as any) as ResultItem[],
});
const svg = await renderFlowJSON({ nodes, edges });
replaceChildren(containerEl.current!, svg);
if (svg !== undefined && svg !== null) {
replaceChildren(containerEl.current!, svg); // Fixed usage
}
},
onStreamEnd: async (result) => {
const roadmap = generateAICourseRoadmapStructure(result, true);
const { nodes, edges } = generateAIRoadmapFromText(roadmap);
const { nodes, edges } = generateAIRoadmapFromText({
nodes: roadmap.filter((item) => item.type === 'node' as any) as ResultItem[],
edges: roadmap.filter((item) => item.type === 'edge' as any) as ResultItem[],
});
const svg = await renderFlowJSON({ nodes, edges });
replaceChildren(containerEl.current!, svg);
if (svg !== undefined && svg !== null) {
replaceChildren(containerEl.current!, svg); // Fixed usage
}
setRoadmapStructure(roadmap);
setIsGenerating(false);

@ -0,0 +1,5 @@
export type FAQType = {
question: string;
answer: string;
};
// Örnek içerik

@ -2,6 +2,8 @@ import { useState } from 'react';
import { Modal } from '../Modal';
export type ModifyCoursePromptProps = {
title: string; // Yeni eklenen özellik
description: string; // Yeni eklenen özellik
onClose: () => void;
onSubmit: (prompt: string) => void;
};

@ -9,6 +9,13 @@ type RegenerateLessonProps = {
onRegenerateLesson: (prompt?: string) => void;
};
interface ModifyCoursePromptProps {
title: string;
description: string;
onClose: () => void;
onSubmit: (prompt: string) => void;
}
export function RegenerateLesson(props: RegenerateLessonProps) {
const { onRegenerateLesson } = props;
@ -33,7 +40,7 @@ export function RegenerateLesson(props: RegenerateLessonProps) {
{showPromptModal && (
<ModifyCoursePrompt
title="Give AI more context"
description="Pass additional information to the AI to generate a lesson."
description="Provide additional details to refine the AI-generated course."
onClose={() => setShowPromptModal(false)}
onSubmit={(prompt) => {
setShowPromptModal(false);

@ -32,6 +32,8 @@ export function RegenerateOutline(props: RegenerateOutlineProps) {
{showPromptModal && (
<ModifyCoursePrompt
title="Course Title" // Eksik özellik eklendi
description="Course Description" // Eksik özellik eklendi
onClose={() => setShowPromptModal(false)}
onSubmit={(prompt) => {
setShowPromptModal(false);

@ -8,7 +8,7 @@ import {
} from 'react';
import './GenerateRoadmap.css';
import { useToast } from '../../hooks/use-toast';
import { generateAIRoadmapFromText } from '../../../editor/utils/roadmap-generator';
import roadmapGenerator from '../../../editor/utils/roadmap-generator'; // Güncelleme: Yolu kontrol edin
import { renderFlowJSON } from '../../../editor/renderer/renderer';
import { replaceChildren } from '../../lib/dom';
import {
@ -34,6 +34,7 @@ import {
IS_KEY_ONLY_ROADMAP_GENERATION,
readAIRoadmapStream,
} from '../../lib/ai.ts';
import { generateAIRoadmapFromText } from '../../utils/roadmapUtils'; // Doğru dosya yolu düzeltildi
import { AITermSuggestionInput } from './AITermSuggestionInput.tsx';
import { IncreaseRoadmapLimit } from './IncreaseRoadmapLimit.tsx';
import { AuthenticationForm } from '../AuthenticationFlow/AuthenticationForm.tsx';
@ -133,10 +134,10 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) {
const renderRoadmap = async (roadmap: string) => {
const result = generateAICourseRoadmapStructure(roadmap);
const { nodes, edges } = generateAIRoadmapFromText(result);
const { nodes, edges } = generateAIRoadmapFromText(result as unknown as { nodes: any[]; edges: any[]; });
const svg = await renderFlowJSON({ nodes, edges });
if (roadmapContainerRef?.current) {
replaceChildren(roadmapContainerRef?.current, svg);
replaceChildren(roadmapContainerRef?.current, svg as unknown as Element); // Fixed type casting
}
};
@ -255,7 +256,7 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) {
pageProgressMessage.set('Redirecting to Editor');
const { nodes, edges } = generateAIRoadmapFromText(generatedRoadmapContent);
const { nodes, edges } = generateAIRoadmapFromText(generatedRoadmapContent as unknown as { nodes: any[]; edges: any[]; });
const { response, error } = await httpPost<{
roadmapId: string;
@ -264,7 +265,7 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) {
`${import.meta.env.PUBLIC_API_URL}/v1-save-ai-roadmap/${currentRoadmap?.id}`,
{
title: roadmapTerm,
nodes: nodes.map((node) => ({
nodes: nodes.map((node: any) => ({
...node,
// To reset the width and height of the node
@ -304,7 +305,7 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) {
pageProgressMessage.set('Downloading Roadmap');
const node = document.getElementById('roadmap-container');
const node = document.getElementById('roadmap-container') as HTMLElement; // Explicitly type as HTMLElement
if (!node) {
toast.error('Something went wrong');
return;

@ -1,5 +1,5 @@
import { Flag, Play, Send, Share, Square, StopCircle, X } from 'lucide-react';
import { useEffect, useRef, useState } from 'react';
import { useEffect, useRef, type RefObject, useState } from 'react';
import { cn } from '../../../lib/classname.ts';
import { useStickyStuck } from '../../../hooks/use-sticky-stuck.tsx';
import { StepperAction } from './StepperAction.tsx';
@ -34,7 +34,8 @@ export function ProjectStepper(props: ProjectStepperProps) {
const { projectId } = props;
const stickyElRef = useRef<HTMLDivElement>(null);
const isSticky = useStickyStuck(stickyElRef, 8);
const isSticky = useStickyStuck(stickyElRef as RefObject<HTMLElement>, 8);
const currentUser = getUser();
const [isStartingProject, setIsStartingProject] = useState(false);
@ -110,7 +111,7 @@ export function ProjectStepper(props: ProjectStepperProps) {
return (
<div
ref={stickyElRef}
ref={stickyElRef} // Tür uyumu sağlandı
className={cn(
'relative top-0 -mx-4 my-5 overflow-hidden rounded-none border border-x-0 bg-white transition-all sm:sticky sm:mx-0 sm:rounded-lg sm:border-x',
{
@ -314,6 +315,10 @@ export function ProjectStepper(props: ProjectStepperProps) {
</>
)}
</div>
<div
className={cn('sticky top-0 z-10', isSticky && 'is-stuck')}
ref={stickyElRef}
></div>
<StepperStepSeparator isActive={activeStep > 1} />
<MilestoneStep
isActive={activeStep === 2}

@ -1,6 +1,5 @@
import { ChevronDownIcon, StarIcon, User2Icon } from 'lucide-react';
import { useState } from 'react';
import { cn } from '../../../editor/utils/classname';
import { markdownToHtml } from '../../lib/markdown';
type Review = {
@ -110,9 +109,7 @@ export function ReviewsSection() {
return (
<div className="relative max-w-5xl">
<div
className={cn('rounded-2xl pb-0 pt-24', {
'pb-8': isExpanded,
})}
className={`rounded-2xl pb-0 pt-24 ${isExpanded ? 'pb-8' : ''}`}
>
{/* Prominent Reviews */}
<div className="mb-4 md:mb-6">
@ -160,7 +157,7 @@ export function ReviewsSection() {
key={index}
className="text-zinc-300"
dangerouslySetInnerHTML={{
__html: markdownToHtml(text),
__html: markdownToHtml(Array.isArray(review.text) ? review.text.join('') : review.text),
}}
/>
))}
@ -171,22 +168,18 @@ export function ReviewsSection() {
</div>
<div
className={cn(
'relative grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3',
isExpanded ? '' : 'max-h-[400px] overflow-hidden',
)}
className={`relative grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 ${
isExpanded ? '' : 'max-h-[400px] overflow-hidden'
}`}
>
{regularReviews.map((review, index) => (
<div
key={index}
className={cn(
'review-testimonial flex-shrink-0 break-inside-avoid-column rounded-xl p-6 backdrop-blur [&_strong]:font-normal [&_strong]:text-yellow-300/70',
{
'bg-gradient-to-br from-yellow-500/10 via-yellow-500/5 to-transparent':
review.isSecondaryProminent,
'bg-zinc-800/30': !review.isSecondaryProminent,
},
)}
className={`review-testimonial flex-shrink-0 break-inside-avoid-column rounded-xl p-6 backdrop-blur [&_strong]:font-normal [&_strong]:text-yellow-300/70 ${
review.isSecondaryProminent
? 'bg-gradient-to-br from-yellow-500/10 via-yellow-500/5 to-transparent'
: 'bg-zinc-800/30'
}`}
>
<div className="flex items-center gap-4">
{review.avatarUrl && (
@ -217,25 +210,24 @@ export function ReviewsSection() {
<p
className="mt-4 text-zinc-300"
dangerouslySetInnerHTML={{
__html: markdownToHtml(review.text),
__html: markdownToHtml(Array.isArray(review.text) ? review.text.join('') : review.text),
}}
/>
</div>
))}
<div
className={cn(
'absolute bottom-0 left-0 right-0 h-40 bg-gradient-to-t from-[#121212] via-[#121212]/80 to-transparent',
isExpanded ? 'opacity-0' : 'opacity-100',
)}
className={`absolute bottom-0 left-0 right-0 h-40 bg-gradient-to-t from-[#121212] via-[#121212]/80 to-transparent ${
isExpanded ? 'opacity-0' : 'opacity-100'
}`}
/>
</div>
</div>
<div
className={cn('absolute left-1/2 top-full -translate-x-1/2', {
'-translate-y-1/2': !isExpanded,
})}
className={`absolute left-1/2 top-full -translate-x-1/2 ${
!isExpanded ? '-translate-y-1/2' : ''
}`}
>
<button
onClick={() => setIsExpanded(!isExpanded)}

@ -111,7 +111,9 @@ export function MemberProgressModal(props: ProgressMapProps) {
fontURL: '/fonts/balsamiq.woff2',
});
replaceChildren(containerEl.current!, svg);
if (svg) {
replaceChildren(containerEl.current as Element, svg);
}
}
useKeydown('Escape', () => {

@ -14,7 +14,13 @@ const messageCodes: Record<string, string> = {
fa: 'Friend request accepted',
};
type Props = {
message: string;
duration?: number;
};
export function Toaster(props: Props) {
const { message, duration = 3000 } = props;
const toastMessage = useStore($toastMessage);
const { c } = getUrlParams();

@ -99,7 +99,7 @@ export function UserProgressModal(props: ProgressMapProps) {
}
return renderer === 'editor'
? await renderFlowJSON(roadmapJson as any)
? await renderFlowJSON(roadmapJson as any) as SVGElement | undefined
: await wireframeJSONToSVG(roadmapJson, {
fontURL: '/fonts/balsamiq.woff2',
});

@ -19,6 +19,9 @@ const legends = [
{ count: '20+', color: 'bg-gray-800' },
];
type ReactCalendarHeatmapValue<T> = { date: T; count: number };
type TooltipDataAttrs = { /* TooltipDataAttrs türünü burada tanımlayın */ };
export function UserActivityHeatmap(props: UserActivityHeatmapProps) {
const { activity } = props;
const data = Object.entries(activity.activityCount).map(([date, count]) => ({
@ -64,15 +67,14 @@ export function UserActivityHeatmap(props: UserActivityHeatmapProps) {
return 'fill-gray-200 rounded-md [rx:2px] focus:outline-none';
}
}}
tooltipDataAttrs={(value: any) => {
if (!value || !value.date) {
return null;
tooltipDataAttrs={(value): TooltipDataAttrs => {
if (!value) {
return {
'data-tooltip': 'No activity on this day'
};
}
const formattedDate = formatActivityDate(value.date);
return {
'data-tooltip-id': 'user-activity-tip',
'data-tooltip-content': `${value.count} Updates - ${formattedDate}`,
'data-tooltip': `${value.count} activities on ${value.date}`
};
}}
/>

@ -1,3 +1,4 @@
import type { JSX } from 'react';
import {
Github,
Globe,

@ -1,5 +1,6 @@
import type { FAQType } from '../components/FAQs/FAQs.astro';
// Ensure the correct path to the module or create the module if it doesn't exist
import type { FAQType } from '../components/GenerateCourse/FAQs';
// // Adjusted path as an example
type ArticleSchemaProps = {
url: string;
headline: string;
@ -50,7 +51,7 @@ export function generateFAQSchema(faqs: FAQType[]) {
name: faq.question,
acceptedAnswer: {
'@type': 'Answer',
text: faq.answer.join(' '),
text: Array.isArray(faq.answer) ? faq.answer.join(' ') : faq.answer,
},
})),
};

@ -0,0 +1,7 @@
export function classname(...classes: (string | undefined | null | false)[]): string {
return classes.filter(Boolean).join(' ');
}
export function cn(...classes: string[]) {
return classes.filter(Boolean).join(' ');
}

@ -0,0 +1 @@
export declare function someFunction(): void;

@ -0,0 +1,11 @@
export function someFunction() {
console.log("This is a utility function from roadmapUtils.");
}
export function generateAIRoadmapFromText(input: { nodes: any[]; edges: any[] }) {
// İşleme mantığı burada
return {
nodes: input.nodes.map((node) => ({ ...node, processed: true })),
edges: input.edges.map((edge) => ({ ...edge, processed: true })),
};
}

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Tutor Test</title>
</head>
<body>
<h1>AI Tutor Test</h1>
<!-- JWT Token Girişi -->
<label for="tokenInput">JWT Token:</label>
<input type="text" id="tokenInput" placeholder="Enter your JWT token" value="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNzQzMDAwMTE0LCJleHAiOjE3NDMwMDM3MTR9.aD_aInBh8jf66iMdp9TuzCJKKhunVsuV9YIfMm_0Blw">
<button id="testButton">Send Request</button>
<!-- Input Data Girişi -->
<label for="inputData">Input Data:</label>
<input type="text" id="inputData" placeholder="Enter data for calculation">
<button id="calculateButton">Calculate</button>
<!-- Yanıt Gösterimi -->
<pre id="response"></pre>
<script>
// /ai-tutor uç noktasına GET isteği
document.getElementById('testButton').addEventListener('click', async () => {
const token = document.getElementById('tokenInput').value; // Kullanıcıdan token al
try {
const response = await fetch('https://legendary-disco-pjww576pvjpq37xg7-3001.app.github.dev/ai-tutor', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
const data = await response.json();
document.getElementById('response').textContent = JSON.stringify(data, null, 2);
} catch (error) {
document.getElementById('response').textContent = `Error: ${error.message}`;
}
});
// /ai-tutor/calculate uç noktasına POST isteği
document.getElementById('calculateButton').addEventListener('click', async () => {
const token = document.getElementById('tokenInput').value;
const input = document.getElementById('inputData').value;
try {
const response = await fetch('https://legendary-disco-pjww576pvjpq37xg7-3001.app.github.dev/ai-tutor/calculate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ input })
});
const data = await response.json();
document.getElementById('response').textContent = JSON.stringify(data, null, 2);
} catch (error) {
document.getElementById('response').textContent = `Error: ${error.message}`;
}
});
</script>
</body>
</html>

@ -1,10 +1,14 @@
// import classname from '@utils/classname';
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "node",
"jsx": "react-jsx",
"jsxImportSource": "react"
"jsxImportSource": "react",
// "paths": {
// "@utils/*": ["src/editor/utils/*"]
// }
},
"exclude": ["node_modules", "dist"]
}

Loading…
Cancel
Save