לדלג לתוכן

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/core @mantine/hooks

התקנות נוספות לפי צורך

# טפסים
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:

npm install -D postcss postcss-preset-mantine postcss-simple-vars
// 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 מאפשרים עיצוב מהיר ישירות על כל קומפוננטה