W Metropolii Quantum, inżynierowie kwantowi potrzebują zaawansowanych stacji roboczych, precyzyjnych narzędzi i zoptymalizowanych procesów, aby efektywnie projektować i utrzymywać zaawansowane systemy miasta. Podobnie, jako deweloper Next.js 15, twoje środowisko deweloperskie jest fundamentem twojej produktywności i jakości kodu.
Zacznijmy od skonfigurowania idealnego środowiska deweloperskiego - twojego osobistego Centrum Dowodzenia dla projektów Next.js 15.
Sercem każdej stacji roboczej inżyniera kwantowego jest Quantum Terminal. Dla deweloperów Next.js 15, Visual Studio Code (VS Code) z dodatkami jest najlepszym wyborem:
1# Zainstaluj podstawowy edytor
2code --install-extension dbaeumer.vscode-eslint
3code --install-extension esbenp.prettier-vscode
4code --install-extension bradlc.vscode-tailwindcss
5code --install-extension ms-vscode.vscode-typescript-next
6code --install-extension dsznajder.es7-react-js-snippetsKonfiguracja VSCode dla projektów Next.js 15 - plik
.vscode/settings.json:1{
2 "editor.formatOnSave": true,
3 "editor.defaultFormatter": "esbenp.prettier-vscode",
4 "editor.codeActionsOnSave": {
5 "source.fixAll.eslint": true
6 },
7 "typescript.tsdk": "node_modules/typescript/lib",
8 "typescript.enablePromptUseWorkspaceTsdk": true,
9 "tailwindCSS.includeLanguages": {
10 "typescript": "javascript",
11 "typescriptreact": "javascript"
12 },
13 "tailwindCSS.experimental.classRegex": [
14 TODO
15 ],
16 "files.associations": {
17 "*.css": "tailwindcss"
18 }
19}W Metropolii Quantum każda zmiana w systemach miasta jest starannie rejestrowana i przechowywana w Kwantowych Archiwach. W naszym świecie używamy Git:
1# Inicjalizacja repozytorium Git dla projektu
2git init
3
4# Tworzenie pliku .gitignore dla projektów Next.js
5npx create-next-app --example with-tailwindcss dummy-app
6cp dummy-app/.gitignore .
7rm -rf dummy-appPlik
.gitignore dla projektu Next.js 15:1# dependencies
2/node_modules
3/.pnp
4.pnp.js
5
6# testing
7/coverage
8
9# next.js
10/.next/
11/out/
12
13# production
14/build
15
16# misc
17.DS_Store
18*.pem
19
20# debug
21npm-debug.log*
22yarn-debug.log*
23yarn-error.log*
24
25# local env files
26.env*.local
27
28# vercel
29.vercel
30
31# typescript
32*.tsbuildinfo
33next-env.d.tsInżynierowie w Metropolii Quantum korzystają z Matrycy Zasobów Kwantowych, aby uzyskiwać dokładnie te komponenty, których potrzebują. My korzystamy z npm, yarn lub pnpm:
1# Inicjalizacja projektu Next.js 15 z Tailwind CSS i TypeScript
2npx create-next-app@latest quantum-project
3# Wybierz opcje: TypeScript: Yes, ESLint: Yes, Tailwind CSS: Yes,
4# App Router: Yes, Import Alias: @/* itd.Opcjonalnie, możesz skonfigurować pnpm dla lepszej wydajności:
1# Instalacja pnpm
2npm install -g pnpm
3
4# Inicjalizacja projektu z pnpm
5pnpm dlx create-next-app@latest quantum-projectW Metropolii Quantum, zaawansowane skanery nieustannie monitorują kod w poszukiwaniu potencjalnych błędów i nieoptymalnych wzorców. W świecie Next.js 15, ESLint pełni tę funkcję:
1npm install --save-dev eslint-plugin-react-hooks eslint-plugin-jsx-a11y eslint-plugin-reactKonfiguracja ESLint w pliku
.eslintrc.json:1{
2 "extends": [
3 "next/core-web-vitals",
4 "plugin:react/recommended",
5 "plugin:react-hooks/recommended",
6 "plugin:jsx-a11y/recommended"
7 ],
8 "rules": {
9 "react/react-in-jsx-scope": "off",
10 "react/prop-types": "off",
11 "no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }],
12 "jsx-a11y/anchor-is-valid": ["error", {
13 "components": ["Link"],
14 "specialLink": ["hrefLeft", "hrefRight"],
15 "aspects": ["invalidHref", "preferButton"]
16 }]
17 },
18 "settings": {
19 "react": {
20 "version": "detect"
21 }
22 }
23}Tak jak w Metropolii Quantum wszystkie struktury muszą być idealnie zharmonizowane, tak twój kod powinien być spójnie sformatowany:
1npm install --save-dev prettier eslint-config-prettierKonfiguracja Prettier w pliku
.prettierrc:1{
2 "semi": true,
3 "singleQuote": true,
4 "tabWidth": 2,
5 "printWidth": 100,
6 "trailingComma": "es5",
7 "bracketSpacing": true,
8 "arrowParens": "avoid"
9}I dodaj
prettier do pliku .eslintrc.json:1{
2 "extends": [
3 "next/core-web-vitals",
4 "plugin:react/recommended",
5 "plugin:react-hooks/recommended",
6 "plugin:jsx-a11y/recommended",
7 "prettier"
8 ],
9 // reszta konfiguracji...
10}W Metropolii Quantum, zanim jakikolwiek kod zostanie wprowadzony do systemów miasta, przechodzi przez szereg automatycznych testów i walidacji. Podobnie możemy skonfigurować Husky i lint-staged:
1npm install --save-dev husky lint-staged
2npx husky install
3npx husky add .husky/pre-commit "npx lint-staged"Konfiguracja lint-staged w
package.json:1{
2 "lint-staged": {
3 "*.{js,jsx,ts,tsx}": [
4 "eslint --fix",
5 "prettier --write"
6 ],
7 "*.{json,css,md}": [
8 "prettier --write"
9 ]
10 }
11}W Metropolii Quantum wszystkie komponenty muszą dokładnie przestrzegać swoich specyfikacji, aby zapewnić bezpieczeństwo całego systemu. TypeScript zapewnia podobne bezpieczeństwo dla twojego kodu:
1# TypeScript jest już zainstalowany w projekcie Next.js 15
2# Skonfigurujmy ściślejsze reguły TypeScriptKonfiguracja
tsconfig.json:1{
2 "compilerOptions": {
3 "target": "es5",
4 "lib": ["dom", "dom.iterable", "esnext"],
5 "allowJs": true,
6 "skipLibCheck": true,
7 "strict": true,
8 "noImplicitAny": true,
9 "strictNullChecks": true,
10 "forceConsistentCasingInFileNames": true,
11 "noEmit": true,
12 "esModuleInterop": true,
13 "module": "esnext",
14 "moduleResolution": "node",
15 "resolveJsonModule": true,
16 "isolatedModules": true,
17 "jsx": "preserve",
18 "incremental": true,
19 "plugins": [
20 {
21 "name": "next"
22 }
23 ],
24 "paths": {
25 "@/*": ["./src/*"]
26 }
27 },
28 "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
29 "exclude": ["node_modules"]
30}Inżynierowie w Metropolii Quantum przeprowadzają tysiące symulacji przed każdą zmianą, aby zapewnić, że systemy miasta będą działać bez zarzutu. Odpowiednikiem w świecie Next.js 15 są narzędzia testowe:
1npm install --save-dev jest @testing-library/react @testing-library/jest-dom jest-environment-jsdomPlik konfiguracyjny
jest.config.js:1const nextJest = require('next/jest');
2
3const createJestConfig = nextJest({
4 // Folder, gdzie znajduje się plik next.config.js i folder node_modules
5 dir: './',
6});
7
8// Konfiguracja Jest
9const customJestConfig = {
10 setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
11 testEnvironment: 'jest-environment-jsdom',
12 moduleNameMapper: {
13 '^@/(.*)$': '<rootDir>/src/$1',
14 },
15};
16
17// exportujemy tę konfigurację
18module.exports = createJestConfig(customJestConfig);Plik setupu
jest.setup.js:1// Rozszerzenia dla Jest
2import '@testing-library/jest-dom';Skrypty testowe w
package.json:1{
2 "scripts": {
3 "test": "jest",
4 "test:watch": "jest --watch"
5 }
6}1npm install --save-dev cypressInicjalizacja Cypress:
1npx cypress openDodaj skrypty do
package.json:1{
2 "scripts": {
3 "cypress": "cypress open",
4 "cypress:headless": "cypress run"
5 }
6}1npx storybook initSkonfiguruj Storybook dla Next.js 15 w pliku
.storybook/main.js:1module.exports = {
2 stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
3 addons: [
4 '@storybook/addon-links',
5 '@storybook/addon-essentials',
6 '@storybook/addon-interactions',
7 {
8 name: '@storybook/addon-styling',
9 options: {
10 postCss: true,
11 },
12 },
13 ],
14 framework: '@storybook/react-webpack5',
15 core: {
16 builder: '@storybook/builder-webpack5',
17 },
18 staticDirs: ['../public'],
19};W Metropolii Quantum, każdy inżynier przestrzega ściśle określonych standardów i procedur. Przyjrzyjmy się najlepszym praktykom dla deweloperów Next.js 15.
Podobnie jak Metropolia Quantum jest podzielona na precyzyjnie zaprojektowane sektory, twój projekt Next.js 15 powinien mieć przejrzystą strukturę:
1quantum-voyages/
2 ├── .husky/ # Konfiguracja Husky
3 ├── .vscode/ # Konfiguracja VS Code
4 ├── public/ # Statyczne zasoby
5 ├── src/
6 │ ├── app/ # App Router - trasy i strony
7 │ │ ├── (auth)/ # Grupowanie logiczne dla autoryzacji
8 │ │ │ ├── login/
9 │ │ │ └── register/
10 │ │ ├── destinations/ # Trasa dla destynacji
11 │ │ ├── bookings/ # Trasa dla rezerwacji
12 │ │ ├── api/ # Endpointy API
13 │ │ └── layout.tsx # Główny layout
14 │ ├── components/ # Komponenty React
15 │ │ ├── ui/ # Elementy interfejsu
16 │ │ └── features/ # Komponenty specyficzne dla funkcji
17 │ ├── hooks/ # Niestandardowe hooki React
18 │ ├── lib/ # Funkcje narzędziowe i logika biznesowa
19 │ ├── styles/ # Globalne style i motywy
20 │ ├── types/ # Definicje typów TypeScript
21 │ └── utils/ # Funkcje narzędziowe
22 ├── tests/ # Testy integracyjne i end-to-end
23 │ ├── e2e/ # Testy Cypress
24 │ └── integration/ # Testy integracyjne
25 ├── .env.example # Przykładowy plik zmiennych środowiskowych
26 ├── .eslintrc.json # Konfiguracja ESLint
27 ├── .gitignore # Ignorowane pliki Git
28 ├── .prettierrc # Konfiguracja Prettier
29 ├── jest.config.js # Konfiguracja Jest
30 ├── next.config.js # Konfiguracja Next.js
31 ├── package.json # Zależności i skrypty
32 ├── postcss.config.js # Konfiguracja PostCSS (dla Tailwind)
33 ├── tailwind.config.js # Konfiguracja Tailwind CSS
34 └── tsconfig.json # Konfiguracja TypeScriptW Metropolii Quantum, każdy element ma swoją precyzyjną nazwę, która odzwierciedla jego funkcję. Podobnie w kodzie:
1// Komponenty: PascalCase, pliki .tsx
2// components/ui/QuantumButton.tsx
3export default function QuantumButton() {
4 return <button className="bg-blue-500 text-white px-4 py-2 rounded">Quantum</button>;
5}
6
7// Funkcje narzędziowe: camelCase, pliki .ts
8// utils/formatDate.ts
9export function formatDate(date: Date): string {
10 return new Intl.DateTimeFormat('pl-PL').format(date);
11}
12
13// Hooki: nazwa zaczyna się od 'use', camelCase, pliki .ts
14// hooks/useQuantumState.ts
15export function useQuantumState(initialValue: number) {
16 const [state, setState] = useState(initialValue);
17 //
18 return { state, increment, decrement };
19}
20
21// Konteksty: nazwa kończy się na 'Context', PascalCase
22// contexts/QuantumContext.tsx
23export const QuantumContext = createContext<QuantumContextType | null>(null);W Metropolii Quantum każda zmiana w systemach miasta musi przejść przez precyzyjny proces zatwierdzania i wdrażania. W świecie programistycznym, warto stosować flow Gitflow:
1# Tworzenie nowej funkcji
2git checkout -b feature/quantum-navigation
3
4# Commity z opisowymi wiadomościami
5git commit -m "feat: Add quantum navigation component"
6git commit -m "fix: Repair positioning in quantum nav"
7git commit -m "docs: Add JSdoc comments to navigation functions"
8
9# Zakończenie funkcji i merge do developa
10git checkout develop
11git merge feature/quantum-navigationStandardy wiadomości commit (Conventional Commits):
W Metropolii Quantum, wszystkie systemy są budowane z podstawowych cząstek kwantowych, które łączą się w coraz bardziej złożone struktury. Podobny model - Atomic Design - możemy zastosować w projektowaniu interfejsu:
1components/
2 ├── atoms/
3 │ ├── Button.tsx
4 │ ├── Input.tsx
5 │ └── Label.tsx
6 ├── molecules/
7 │ ├── SearchForm.tsx
8 │ └── NavLink.tsx
9 ├── organisms/
10 │ ├── Header.tsx
11 │ └── Footer.tsx
12 └── templates/
13 ├── DashboardLayout.tsx
14 └── AuthLayout.tsxTak jak w Metropolii Quantum każdy moduł ma swój interfejs i może być łączony z innymi modułami, nasze komponenty powinny być zaprojektowane modułowo:
1// Przykład komponentu z wzorcem kompozycji
2import { ReactNode } from 'react';
3
4interface CardProps {
5 className?: string;
6 children: ReactNode;
7}
8
9export function Card({ className, children }: CardProps) {
10 return <div className={`rounded-lg shadow ${className}`}>{children}</div>;
11}
12
13Card.Header = function CardHeader({ className, children }: CardProps) {
14 return <div className={`p-4 border-b ${className}`}>{children}</div>;
15};
16
17Card.Body = function CardBody({ className, children }: CardProps) {
18 return <div className={`p-4 ${className}`}>{children}</div>;
19};
20
21Card.Footer = function CardFooter({ className, children }: CardProps) {
22 return <div className={`p-4 border-t ${className}`}>{children}</div>;
23};
24
25// Użycie
26<Card className="bg-white">
27 <Card.Header>Quantum Navigation</Card.Header>
28 <Card.Body>Zawartość karty</Card.Body>
29 <Card.Footer>Actions</Card.Footer>
30</Card>W Metropolii Quantum, wiele procesów jest zautomatyzowanych, aby inżynierowie mogli skupić się na innowacjach. Podobnie w projekcie Next.js 15:
1// package.json
2{
3 "scripts": {
4 "dev": "next dev",
5 "build": "next build",
6 "start": "next start",
7 "lint": "next lint",
8 "format": "prettier --write .",
9 "test": "jest",
10 "test:watch": "jest --watch",
11 "e2e": "cypress open",
12 "storybook": "storybook dev -p 6006",
13 "build-storybook": "storybook build",
14 "prepare": "husky install",
15 "type-check": "tsc --noEmit",
16 "validate": "npm-run-all --parallel lint type-check test"
17 }
18}W Metropolii Quantum, dane przepływają przez miasto za pomocą złożonego systemu kwantowego. W aplikacji Next.js 15 również potrzebujemy efektywnego zarządzania stanem:
1// Korzystanie z useState i useReducer dla prostego zarządzania stanem
2"use client";
3
4import { useState } from 'react';
5
6export default function QuantumCounter() {
7 const [count, setCount] = useState(0);
8
9 return (
10 <div className="flex items-center gap-4">
11 <button
12 onClick={() => setCount(c => c - 1)}
13 className="px-3 py-1 bg-red-500 text-white rounded"
14 >
15 -
16 </button>
17 <span className="text-xl">{count}</span>
18 <button
19 onClick={() => setCount(c => c + 1)}
20 className="px-3 py-1 bg-green-500 text-white rounded"
21 >
22 +
23 </button>
24 </div>
25 );
26}1// Context API - dla średniej wielkości aplikacji
2// contexts/QuantumStateContext.tsx
3"use client";
4
5import { createContext, useContext, useReducer, ReactNode } from 'react';
6
7type State = {
8 destinations: string[];
9 selectedDestination: string | null;
10};
11
12type Action =
13 | { type: 'ADD_DESTINATION'; payload: string }
14 | { type: 'SELECT_DESTINATION'; payload: string };
15
16const initialState: State = {
17 destinations: ['Mars', 'Europa', 'Titan'],
18 selectedDestination: null,
19};
20
21function reducer(state: State, action: Action): State {
22 switch (action.type) {
23 case 'ADD_DESTINATION':
24 return {
25 ...state,
26 destinations: [...state.destinations, action.payload],
27 };
28 case 'SELECT_DESTINATION':
29 return {
30 ...state,
31 selectedDestination: action.payload,
32 };
33 default:
34 return state;
35 }
36}
37
38const QuantumStateContext = createContext<{
39 state: State;
40 dispatch: React.Dispatch<Action>;
41} | undefined>(undefined);
42
43export function QuantumStateProvider({ children }: { children: ReactNode }) {
44 const [state, dispatch] = useReducer(reducer, initialState);
45
46 return (
47 <QuantumStateContext.Provider value={{ state, dispatch }}>
48 {children}
49 </QuantumStateContext.Provider>
50 );
51}
52
53export function useQuantumState() {
54 const context = useContext(QuantumStateContext);
55 if (context === undefined) {
56 throw new Error('useQuantumState must be used within a QuantumStateProvider');
57 }
58 return context;
59}Dla większych aplikacji, warto rozważyć biblioteki zarządzania stanem, takie jak Zustand, Jotai czy Redux Toolkit.
W Metropolii Quantum, systemy komunikują się za pomocą precyzyjnych protokołów. W Next.js 15 mamy kilka opcji implementacji API:
1// app/api/destinations/route.ts
2import { NextResponse } from 'next/server';
3
4export async function GET() {
5 // Pobieranie danych z bazy danych lub zewnętrznego API
6 const destinations = [
7 { id: 1, name: 'Mars', distance: '54.6M km' },
8 { id: 2, name: 'Europa', distance: '628.3M km' },
9 { id: 3, name: 'Titan', distance: '1.2B km' },
10 ];
11
12 return NextResponse.json(destinations);
13}
14
15export async function POST(request: Request) {
16 const body = await request.json();
17
18 // Walidacja i logika biznesowa
19 if (!body.name) {
20 return NextResponse.json(
21 { error: 'Name is required' },
22 { status: 400 }
23 );
24 }
25
26 // Zapisywanie do bazy danych...
27
28 return NextResponse.json(
29 { id: 4, name: body.name, distance: body.distance },
30 { status: 201 }
31 );
32}1// app/destinations/actions.ts
2'use server';
3
4import { revalidatePath } from 'next/cache';
5import { redirect } from 'next/navigation';
6
7export async function addDestination(formData: FormData) {
8 const name = formData.get('name') as string;
9 const distance = formData.get('distance') as string;
10
11 if (!name || !distance) {
12 return { error: 'Name and distance are required' };
13 }
14
15 // Zapisywanie do bazy danych...
16
17 // Odświeżenie danych
18 revalidatePath('/destinations');
19 redirect('/destinations');
20}1npm install @tanstack/react-query1// app/providers.tsx
2'use client';
3
4import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
5import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
6import { useState, ReactNode } from 'react';
7
8export function Providers({ children }: { children: ReactNode }) {
9 const [queryClient] = useState(() => new QueryClient());
10
11 return (
12 <QueryClientProvider client={queryClient}>
13 {children}
14 <ReactQueryDevtools initialIsOpen={false} />
15 </QueryClientProvider>
16 );
17}1// components/DestinationsList.tsx
2'use client';
3
4import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
5
6async function fetchDestinations() {
7 const res = await fetch('/api/destinations');
8 if (!res.ok) throw new Error('Failed to fetch destinations');
9 return res.json();
10}
11
12export default function DestinationsList() {
13 const queryClient = useQueryClient();
14
15 const { data: destinations, isLoading, error } = useQuery({
16 queryKey: ['destinations'],
17 queryFn: fetchDestinations,
18 });
19
20 const mutation = useMutation({
21 mutationFn: async (newDestination) => {
22 const res = await fetch('/api/destinations', {
23 method: 'POST',
24 headers: { 'Content-Type': 'application/json' },
25 body: JSON.stringify(newDestination),
26 });
27 return res.json();
28 },
29 onSuccess: () => {
30 queryClient.invalidateQueries({ queryKey: ['destinations'] });
31 },
32 });
33
34 if (isLoading) return <div>Ładowanie destynacji...</div>;
35 if (error) return <div>Błąd: {error.message}</div>;
36
37 return (
38 <div>
39 <h2 className="text-2xl font-bold mb-4">Dostępne destynacje</h2>
40 <ul className="space-y-2">
41 {destinations.map((dest) => (
42 <li key={dest.id} className="p-3 bg-gray-100 rounded">
43 {dest.name} - {dest.distance}
44 </li>
45 ))}
46 </ul>
47 </div>
48 );
49}W Metropolii Quantum, nowe technologie są systematycznie testowane i wdrażane za pomocą w pełni zautomatyzowanego procesu. Podobnie możemy skonfigurować CI/CD dla naszego projektu:
Plik
.github/workflows/ci.yml:1name: CI
2
3on:
4 push:
5 branches: [ main, develop ]
6 pull_request:
7 branches: [ main, develop ]
8
9jobs:
10 build:
11 runs-on: ubuntu-latest
12
13 steps:
14 - uses: actions/checkout@v3
15
16 - name: Setup Node.js
17 uses: actions/setup-node@v3
18 with:
19 node-version: '18'
20 cache: 'npm'
21
22 - name: Install dependencies
23 run: npm ci
24
25 - name: Lint
26 run: npm run lint
27
28 - name: Type check
29 run: npm run type-check
30
31 - name: Test
32 run: npm test
33
34 - name: Build
35 run: npm run buildSkonfiguruj integrację z Vercel, aby każdy push do głównej gałęzi automatycznie wdrażał aplikację:
W Metropolii Quantum, inżynierowie stale monitorują wydajność wszystkich systemów. W naszej aplikacji Next.js 15:
1// app/layout.tsx
2import { SpeedInsights } from '@vercel/speed-insights/next';
3import { Analytics } from '@vercel/analytics/react';
4
5export default function RootLayout({
6 children,
7}: {
8 children: React.ReactNode;
9}) {
10 return (
11 <html lang="pl">
12 <body>
13 {children}
14 <SpeedInsights />
15 <Analytics />
16 </body>
17 </html>
18 );
19}W Metropolii Quantum, każdy obywatel musi mieć dostęp do systemów miasta, niezależnie od swoich ograniczeń. Podobnie, nasza aplikacja powinna być dostępna dla wszystkich:
1// components/ui/QuantumButton.tsx z ulepszoną dostępnością
2"use client";
3
4import { ButtonHTMLAttributes, forwardRef } from 'react';
5
6interface QuantumButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
7 variant?: 'primary' | 'secondary' | 'danger';
8 size?: 'sm' | 'md' | 'lg';
9 isLoading?: boolean;
10}
11
12export const QuantumButton = forwardRef<HTMLButtonElement, QuantumButtonProps>(
13 ({
14 variant = 'primary',
15 size = 'md',
16 className = '',
17 isLoading = false,
18 disabled,
19 children,
20 ...props
21 }, ref) => {
22 // Mapowanie wariantów na klasy
23 const variantClasses = {
24 primary: 'bg-blue-600 hover:bg-blue-700 text-white',
25 secondary: 'bg-gray-200 hover:bg-gray-300 text-gray-800',
26 danger: 'bg-red-600 hover:bg-red-700 text-white',
27 };
28
29 // Mapowanie rozmiarów na klasy
30 const sizeClasses = {
31 sm: 'text-sm px-2 py-1',
32 md: 'text-base px-4 py-2',
33 lg: 'text-lg px-6 py-3',
34 };
35
36 return (
37 <button
38 ref={ref}
39 className={`rounded font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 ${variantClasses[variant]} ${sizeClasses[size]} ${isLoading || disabled ? 'opacity-70 cursor-not-allowed' : ''} ${className}`}
40 disabled={isLoading || disabled}
41 {...props}
42 >
43 {isLoading ? (
44 <span className="flex items-center justify-center">
45 <svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-current" fill="none" viewBox="0 0 24 24">
46 <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
47 <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
48 </svg>
49 Ładowanie...
50 </span>
51 ) : children}
52 </button>
53 );
54 }
55);
56QuantumButton.displayName = 'QuantumButton';W Metropolii Quantum, każdy system jest dokładnie udokumentowany, aby przyszli inżynierowie mogli z łatwością go zrozumieć. W naszym projekcie:
1/**
2 * Komponent nawigacyjny dla podróży kosmicznych.
3 *
4 * @component
5 * @example
6 * ~~~tsx
7 * <QuantumNavigation
8 * destinations={['Mars', 'Europa', 'Titan']}
9 * onSelectDestination={(dest) => console.log(`Wybrano ${dest}`)}
10 * />
11 * ~~~
12 */
13export interface QuantumNavigationProps {
14 /** Lista dostępnych destynacji */
15 destinations: string[];
16 /** Callback wywoływany po wybraniu destynacji */
17 onSelectDestination: (destination: string) => void;
18 /** Aktualnie wybrana destynacja (opcjonalna) */
19 selectedDestination?: string;
20}
21
22export function QuantumNavigation({
23 destinations,
24 onSelectDestination,
25 selectedDestination
26}: QuantumNavigationProps) {
27 return (
28 <nav className="p-4 bg-gradient-to-r from-indigo-500 to-purple-600 rounded-lg text-white">
29 <h2 className="text-xl font-semibold mb-2">Nawigacja Quantum</h2>
30 <ul className="space-y-1">
31 {destinations.map((dest) => (
32 <li key={dest}>
33 <button
34 className={`w-full text-left px-3 py-2 rounded hover:bg-white/20 ${
35 selectedDestination === dest ? 'bg-white/30 font-medium' : ''
36 }`}
37 onClick={() => onSelectDestination(dest)}
38 >
39 {dest}
40 </button>
41 </li>
42 ))}
43 </ul>
44 </nav>
45 );
46}W Metropolii Quantum, inżynierowie pracują w zsynchronizowanych zespołach, aby osiągnąć maksymalną efektywność. Podobnie, zespół deweloperów Next.js 15 powinien mieć jasne procesy współpracy:
Podobnie jak inżynierowie Metropolii Quantum potrzebują zaawansowanych narzędzi i optymalnych procesów, deweloperzy Next.js 15 potrzebują dobrze skonfigurowanego środowiska deweloperskiego. Dzięki przedstawionym narzędziom i praktykom możesz:
Pamiętaj, że podobnie jak Metropolia Quantum nieustannie się rozwija, tak i twoje środowisko deweloperskie powinno ewoluować wraz z projektem i zespołem. Regularnie przeglądaj i aktualizuj swoje narzędzia i procesy, aby utrzymać maksymalną wydajność i jakość kodu.
Cała wiedza i narzędzia przedstawione w tym module umożliwią ci efektywne tworzenie zaawansowanych aplikacji przy użyciu Next.js 15 - podobnie jak inżynierowie kwantowi w Metropolii wykorzystują swoje narzędzia do projektowania technologii jutra.