8.3 מנטין בסיסי הרצאה
מנטין בסיסי - Mantine Basics¶
בשיעור זה נלמד את הבסיס של ספריית Mantine - ספרית קומפוננטות מודרנית לריאקט. נתקין אותה, נגדיר את ה-Theme, ונכיר את הקומפוננטות הבסיסיות ביותר.
מה זה Mantine¶
Mantine היא ספרית קומפוננטות מקיפה לריאקט שכוללת:
- מעל 100 קומפוננטות מוכנות לשימוש
- הוקים שימושיים (form, disclosure, media queries ועוד)
- מערכת theme גמישה
- תמיכה מלאה ב-TypeScript
- נגישות (a11y) מובנית
- תמיכה ב-SSR ו-dark mode
למה Mantine¶
- API נקי ואינטואיטיבי - קל ללמוד ולהשתמש
- תיעוד מצוין עם דוגמאות חיות
- קהילה פעילה ושחרורים קבועים
- הוקים מובנים שחוסכים הרבה קוד
- מערכת theme חזקה שמאפשרת התאמה אישית מלאה
- גודל bundle סביר עם תמיכה ב-tree-shaking
התקנה¶
התקנה בסיסית¶
התקנות נוספות לפי צורך¶
# טפסים
npm install @mantine/form
# התראות
npm install @mantine/notifications
# עורך טקסט עשיר
npm install @mantine/tiptap
# תאריכים
npm install @mantine/dates dayjs
# גרפים
npm install @mantine/charts recharts
# קוד עם הדגשת תחביר
npm install @mantine/code-highlight
הגדרת PostCSS¶
Mantine דורש PostCSS preset:
// postcss.config.cjs
module.exports = {
plugins: {
"postcss-preset-mantine": {},
"postcss-simple-vars": {
variables: {
"mantine-breakpoint-xs": "36em",
"mantine-breakpoint-sm": "48em",
"mantine-breakpoint-md": "62em",
"mantine-breakpoint-lg": "75em",
"mantine-breakpoint-xl": "88em",
},
},
},
};
הגדרת MantineProvider¶
// main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { MantineProvider } from "@mantine/core";
import "@mantine/core/styles.css";
import App from "./App";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<MantineProvider>
<App />
</MantineProvider>
</StrictMode>
);
- חייבים לעטוף את האפליקציה ב-MantineProvider
- חייבים לייבא את styles.css של Mantine
- בלי MantineProvider הקומפוננטות לא יעבדו כראוי
הגדרת Theme¶
Theme בסיסי¶
import { createTheme, MantineProvider } from "@mantine/core";
const theme = createTheme({
primaryColor: "blue",
fontFamily: "Rubik, sans-serif",
headings: {
fontFamily: "Rubik, sans-serif",
},
defaultRadius: "md",
cursorType: "pointer",
});
function App() {
return (
<MantineProvider theme={theme}>
{/* האפליקציה */}
</MantineProvider>
);
}
צבעים מותאמים¶
import { createTheme, MantineColorsTuple } from "@mantine/core";
const brand: MantineColorsTuple = [
"#f0f4ff",
"#dce4f5",
"#b4c6e7",
"#8aa7db",
"#668dd0",
"#4e7dc9",
"#4275c7",
"#3363b0",
"#29589e",
"#1a4b8c",
];
const theme = createTheme({
colors: {
brand,
},
primaryColor: "brand",
});
- כל צבע הוא מערך של 10 גוונים (מבהיר לכהה)
- ניתן להשתמש בכלי Mantine Colors Generator ליצירת סקלת צבעים
פונטים¶
const theme = createTheme({
fontFamily: "Rubik, Arial, sans-serif",
fontFamilyMonospace: "JetBrains Mono, monospace",
headings: {
fontFamily: "Heebo, sans-serif",
fontWeight: "700",
sizes: {
h1: { fontSize: "2.5rem" },
h2: { fontSize: "2rem" },
h3: { fontSize: "1.5rem" },
},
},
fontSizes: {
xs: "0.75rem",
sm: "0.875rem",
md: "1rem",
lg: "1.125rem",
xl: "1.25rem",
},
});
קומפוננטות טקסט¶
Text - טקסט רגיל¶
import { Text } from "@mantine/core";
function TextExamples() {
return (
<>
{/* טקסט בסיסי */}
<Text>טקסט רגיל</Text>
{/* גודל */}
<Text size="xs">קטן מאוד</Text>
<Text size="sm">קטן</Text>
<Text size="md">רגיל</Text>
<Text size="lg">גדול</Text>
<Text size="xl">גדול מאוד</Text>
{/* משקל */}
<Text fw={400}>רגיל</Text>
<Text fw={500}>בינוני</Text>
<Text fw={700}>מודגש</Text>
{/* צבע */}
<Text c="blue">כחול</Text>
<Text c="red.6">אדום כהה</Text>
<Text c="dimmed">עמום</Text>
<Text c="gray.5">אפור</Text>
{/* קיצור טקסט */}
<Text truncate="end" w={200}>
טקסט ארוך מאוד שייחתך עם שלוש נקודות בסוף
</Text>
{/* שורות מוגבלות */}
<Text lineClamp={2}>
טקסט ארוך שיוצג בשתי שורות בלבד ואחר כך ייחתך עם שלוש נקודות
</Text>
{/* עיצוב */}
<Text td="underline">קו תחתון</Text>
<Text td="line-through">קו חוצה</Text>
<Text fs="italic">נטוי</Text>
<Text tt="uppercase">uppercase text</Text>
{/* שימוש כ-span */}
<Text span c="blue" fw={700}>
טקסט מודגש בתוך שורה
</Text>
</>
);
}
Title - כותרות¶
import { Title } from "@mantine/core";
function TitleExamples() {
return (
<>
<Title order={1}>כותרת H1</Title>
<Title order={2}>כותרת H2</Title>
<Title order={3}>כותרת H3</Title>
<Title order={4}>כותרת H4</Title>
{/* גודל מותאם */}
<Title order={2} size="h4">
H2 בגודל של H4
</Title>
{/* צבע */}
<Title order={1} c="blue.7">
כותרת צבעונית
</Title>
{/* יישור */}
<Title order={2} ta="center">
כותרת ממורכזת
</Title>
</>
);
}
קומפוננטת Button - כפתור¶
import { Button, Group } from "@mantine/core";
function ButtonExamples() {
return (
<>
{/* Variants */}
<Group>
<Button variant="filled">מלא</Button>
<Button variant="light">בהיר</Button>
<Button variant="outline">מתאר</Button>
<Button variant="subtle">עדין</Button>
<Button variant="transparent">שקוף</Button>
<Button variant="default">ברירת מחדל</Button>
</Group>
{/* צבעים */}
<Group>
<Button color="blue">כחול</Button>
<Button color="red">אדום</Button>
<Button color="green">ירוק</Button>
<Button color="orange">כתום</Button>
<Button color="grape">סגול</Button>
</Group>
{/* גדלים */}
<Group>
<Button size="xs">קטן מאוד</Button>
<Button size="sm">קטן</Button>
<Button size="md">רגיל</Button>
<Button size="lg">גדול</Button>
<Button size="xl">גדול מאוד</Button>
</Group>
{/* רדיוס */}
<Group>
<Button radius="xs">חד</Button>
<Button radius="md">בינוני</Button>
<Button radius="xl">מעוגל</Button>
</Group>
{/* מצבים */}
<Group>
<Button disabled>מושבת</Button>
<Button loading>טוען</Button>
</Group>
{/* רוחב מלא */}
<Button fullWidth>כפתור ברוחב מלא</Button>
{/* כפתור עם אייקון */}
<Button leftSection="+" rightSection=">">
הוסף פריט
</Button>
{/* כפתור כקישור */}
<Button component="a" href="https://example.com">
קישור
</Button>
</>
);
}
קומפוננטות Layout - פריסה¶
Container - מיכל¶
import { Container, Text } from "@mantine/core";
function ContainerExample() {
return (
<>
{/* מיכל ברירת מחדל - רוחב מקסימלי מוגבל */}
<Container>
<Text>תוכן ממורכז עם רוחב מקסימלי</Text>
</Container>
{/* גדלים */}
<Container size="xs">רוחב 540px</Container>
<Container size="sm">רוחב 720px</Container>
<Container size="md">רוחב 960px</Container>
<Container size="lg">רוחב 1140px</Container>
<Container size="xl">רוחב 1320px</Container>
{/* ריפוד */}
<Container p="md">עם ריפוד</Container>
{/* ללא רוחב מקסימלי */}
<Container fluid>רוחב מלא</Container>
</>
);
}
Group - קבוצה אופקית¶
import { Group, Button } from "@mantine/core";
function GroupExamples() {
return (
<>
{/* יישור */}
<Group justify="flex-start">תחילה</Group>
<Group justify="center">מרכז</Group>
<Group justify="flex-end">סוף</Group>
<Group justify="space-between">מפוזר</Group>
{/* רווח */}
<Group gap="xs">רווח קטן</Group>
<Group gap="md">רווח בינוני</Group>
<Group gap="xl">רווח גדול</Group>
{/* גלישה */}
<Group wrap="wrap">
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
<Button>4</Button>
<Button>5</Button>
</Group>
{/* שימוש נפוץ - כפתורי פעולה */}
<Group justify="flex-end" mt="md">
<Button variant="default">ביטול</Button>
<Button>שמירה</Button>
</Group>
</>
);
}
Stack - ערימה אנכית¶
import { Stack, Text, Button } from "@mantine/core";
function StackExamples() {
return (
<>
{/* ערימה בסיסית */}
<Stack>
<Text>שורה 1</Text>
<Text>שורה 2</Text>
<Text>שורה 3</Text>
</Stack>
{/* רווח */}
<Stack gap="xs">רווחים קטנים</Stack>
<Stack gap="xl">רווחים גדולים</Stack>
{/* יישור */}
<Stack align="center">ממורכז</Stack>
<Stack align="flex-end">לשמאל</Stack>
{/* שימוש נפוץ - טופס */}
<Stack gap="md" maw={400}>
<Text size="lg" fw={700}>טופס התחברות</Text>
<input placeholder="אימייל" />
<input placeholder="סיסמה" type="password" />
<Button fullWidth>התחבר</Button>
</Stack>
</>
);
}
Grid ו-SimpleGrid¶
import { Grid, SimpleGrid, Paper, Text } from "@mantine/core";
function GridExamples() {
return (
<>
{/* SimpleGrid - הכי פשוט */}
<SimpleGrid cols={3}>
<Paper p="md" shadow="xs">עמודה 1</Paper>
<Paper p="md" shadow="xs">עמודה 2</Paper>
<Paper p="md" shadow="xs">עמודה 3</Paper>
</SimpleGrid>
{/* SimpleGrid רספונסיבי */}
<SimpleGrid
cols={{ base: 1, sm: 2, lg: 3 }}
spacing={{ base: "sm", sm: "md", lg: "lg" }}
>
<Paper p="md" shadow="xs">1</Paper>
<Paper p="md" shadow="xs">2</Paper>
<Paper p="md" shadow="xs">3</Paper>
<Paper p="md" shadow="xs">4</Paper>
<Paper p="md" shadow="xs">5</Paper>
<Paper p="md" shadow="xs">6</Paper>
</SimpleGrid>
{/* Grid - שליטה מלאה */}
<Grid>
<Grid.Col span={8}>
<Paper p="md" shadow="xs">תוכן ראשי - 8/12</Paper>
</Grid.Col>
<Grid.Col span={4}>
<Paper p="md" shadow="xs">סיידבר - 4/12</Paper>
</Grid.Col>
</Grid>
{/* Grid רספונסיבי */}
<Grid>
<Grid.Col span={{ base: 12, md: 6, lg: 4 }}>
<Paper p="md" shadow="xs">כרטיס 1</Paper>
</Grid.Col>
<Grid.Col span={{ base: 12, md: 6, lg: 4 }}>
<Paper p="md" shadow="xs">כרטיס 2</Paper>
</Grid.Col>
<Grid.Col span={{ base: 12, md: 12, lg: 4 }}>
<Paper p="md" shadow="xs">כרטיס 3</Paper>
</Grid.Col>
</Grid>
{/* Grid עם offset */}
<Grid>
<Grid.Col span={6} offset={3}>
<Paper p="md" shadow="xs">ממורכז</Paper>
</Grid.Col>
</Grid>
</>
);
}
Flex¶
import { Flex, Button } from "@mantine/core";
function FlexExamples() {
return (
<>
{/* Flex בסיסי */}
<Flex gap="md" justify="center" align="center" direction="row" wrap="wrap">
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
</Flex>
{/* עמודה */}
<Flex direction="column" gap="sm">
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
</Flex>
{/* רספונסיבי */}
<Flex
direction={{ base: "column", sm: "row" }}
gap={{ base: "sm", sm: "lg" }}
justify={{ sm: "center" }}
>
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
</Flex>
</>
);
}
AppShell - מבנה אפליקציה¶
AppShell הוא layout component שמספק מבנה אפליקציה מוכן עם header, sidebar, footer ותוכן ראשי.
import { AppShell, Burger, Group, NavLink, Text } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
function AppLayout() {
const [opened, { toggle }] = useDisclosure();
return (
<AppShell
header={{ height: 60 }}
navbar={{
width: 250,
breakpoint: "sm",
collapsed: { mobile: !opened },
}}
padding="md"
>
{/* Header */}
<AppShell.Header>
<Group h="100%" px="md">
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
<Text size="lg" fw={700}>האפליקציה שלי</Text>
</Group>
</AppShell.Header>
{/* Navbar (Sidebar) */}
<AppShell.Navbar p="md">
<NavLink label="בית" active />
<NavLink label="הגדרות" />
<NavLink label="משתמשים" />
<NavLink
label="ניהול"
childrenOffset={28}
>
<NavLink label="תפקידים" />
<NavLink label="הרשאות" />
</NavLink>
</AppShell.Navbar>
{/* תוכן ראשי */}
<AppShell.Main>
<Text>תוכן האפליקציה</Text>
</AppShell.Main>
</AppShell>
);
}
- AppShell מטפל אוטומטית ב-layout, spacing, ורספונסיביות
- הסיידבר מתכווץ אוטומטית בטלפון ומופיע עם כפתור Burger
- collapsedBreakpoint מגדיר מתי הסיידבר הופך להמבורגר
System Props - תכונות מערכת¶
כל קומפוננטה של Mantine תומכת בתכונות מערכת לעיצוב מהיר:
import { Box, Text, Button } from "@mantine/core";
function SystemPropsExample() {
return (
<>
{/* Margin & Padding */}
<Box p="md" m="lg" mt="xl" pb="xs">תוכן</Box>
{/* רוחב וגובה */}
<Box w={200} h={100} maw={500} mah={300}>תוכן</Box>
{/* צבעים */}
<Box bg="blue.1" c="blue.9">רקע כחול בהיר</Box>
{/* רדיוס */}
<Box style={{ borderRadius: "var(--mantine-radius-md)" }}>מעוגל</Box>
{/* גלוי/נסתר */}
<Box visibleFrom="sm">נראה רק מ-sm ומעלה</Box>
<Box hiddenFrom="md">נסתר מ-md ומעלה</Box>
{/* דוגמה מעשית */}
<Box
p="xl"
bg="gray.0"
mt="lg"
mb="lg"
style={{ borderRadius: "var(--mantine-radius-lg)" }}
>
<Text size="xl" fw={700} mb="md">כותרת</Text>
<Text c="dimmed" mb="lg">תיאור ארוך יותר</Text>
<Button>פעולה</Button>
</Box>
</>
);
}
- קיצורים: m (margin), p (padding), mt (margin-top), px (padding horizontal)
- w (width), h (height), maw (max-width), mah (max-height), miw (min-width), mih (min-height)
- bg (background), c (color)
- ta (text-align), fw (font-weight), fz (font-size)
Paper - משטח¶
import { Paper, Text } from "@mantine/core";
function PaperExamples() {
return (
<>
{/* Paper בסיסי */}
<Paper shadow="xs" p="md">
<Text>כרטיס עם צל קל</Text>
</Paper>
{/* עם גבול */}
<Paper shadow="sm" p="xl" withBorder>
<Text>כרטיס עם גבול</Text>
</Paper>
{/* רדיוס */}
<Paper shadow="md" p="lg" radius="lg">
<Text>פינות מעוגלות</Text>
</Paper>
{/* צבע רקע */}
<Paper shadow="sm" p="md" bg="blue.0">
<Text c="blue.9">רקע כחול בהיר</Text>
</Paper>
</>
);
}
דוגמה מלאה - דף בית¶
import {
AppShell,
Burger,
Group,
NavLink,
Title,
Text,
Button,
SimpleGrid,
Paper,
Container,
Stack,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
function Dashboard() {
const [opened, { toggle }] = useDisclosure();
const stats = [
{ title: "משתמשים", value: "1,234", change: "+12%" },
{ title: "הזמנות", value: "567", change: "+8%" },
{ title: "הכנסות", value: "45,678 ש\"ח", change: "+23%" },
{ title: "ביקורים", value: "12,345", change: "+5%" },
];
return (
<AppShell
header={{ height: 60 }}
navbar={{ width: 250, breakpoint: "sm", collapsed: { mobile: !opened } }}
padding="md"
>
<AppShell.Header>
<Group h="100%" px="md" justify="space-between">
<Group>
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
<Title order={3}>דשבורד</Title>
</Group>
<Button variant="light" size="sm">
התנתק
</Button>
</Group>
</AppShell.Header>
<AppShell.Navbar p="md">
<Stack gap="xs">
<NavLink label="דשבורד" active />
<NavLink label="משתמשים" />
<NavLink label="הזמנות" />
<NavLink label="מוצרים" />
<NavLink label="הגדרות" />
</Stack>
</AppShell.Navbar>
<AppShell.Main>
<Container fluid>
<Title order={2} mb="lg">
ברוך הבא
</Title>
{/* סטטיסטיקות */}
<SimpleGrid cols={{ base: 1, sm: 2, lg: 4 }} mb="xl">
{stats.map((stat) => (
<Paper key={stat.title} shadow="xs" p="md" withBorder>
<Text size="sm" c="dimmed" mb="xs">
{stat.title}
</Text>
<Group justify="space-between" align="flex-end">
<Text size="xl" fw={700}>
{stat.value}
</Text>
<Text size="sm" c="green">
{stat.change}
</Text>
</Group>
</Paper>
))}
</SimpleGrid>
{/* תוכן */}
<SimpleGrid cols={{ base: 1, md: 2 }}>
<Paper shadow="xs" p="lg" withBorder>
<Title order={4} mb="md">
פעילות אחרונה
</Title>
<Stack gap="sm">
<Text size="sm">משתמש חדש נרשם - לפני 5 דקות</Text>
<Text size="sm">הזמנה חדשה - לפני 12 דקות</Text>
<Text size="sm">תשלום התקבל - לפני 30 דקות</Text>
</Stack>
</Paper>
<Paper shadow="xs" p="lg" withBorder>
<Title order={4} mb="md">
פעולות מהירות
</Title>
<Stack gap="sm">
<Button variant="light" fullWidth>
הוסף משתמש
</Button>
<Button variant="light" fullWidth>
צור הזמנה
</Button>
<Button variant="light" fullWidth>
הפק דוח
</Button>
</Stack>
</Paper>
</SimpleGrid>
</Container>
</AppShell.Main>
</AppShell>
);
}
סיכום¶
- Mantine היא ספרית קומפוננטות מקיפה ומודרנית לריאקט
- ההתקנה דורשת את חבילת core, hooks, ו-PostCSS preset
- MantineProvider עוטף את האפליקציה ומספק theme ו-context
- createTheme מאפשר התאמה אישית של צבעים, פונטים וברירות מחדל
- Text ו-Title הם הקומפוננטות הבסיסיות לתצוגת טקסט
- Button תומך ב-variants, צבעים, גדלים ומצבים שונים
- Group מסדר אלמנטים אופקית, Stack אנכית
- Grid ו-SimpleGrid מאפשרים פריסה רספונסיבית
- AppShell מספק מבנה אפליקציה מלא עם header, sidebar ותוכן
- System props מאפשרים עיצוב מהיר ישירות על כל קומפוננטה