Sıfırdan ileriye ReactJs yeni konusuna hoş geldiniz. En son Material UI componentlerinden Feedback bölümünü bitirmiştik. Bugün ise Surfaces bölümünü göreceğiz iyi okumalar.
Accordion
Material UI Accordion bileşeni, çeşitli kullanım durumlarını ele almak için çeşitli tamamlayıcı yardımcı bileşenler içerir:
Accordion: İlgili bileşenleri gruplamak için kullanılan sarmalayıcı.
Accordion Summary: Tıklandığında içeriği genişleten veya daraltan Accordion başlığı için sarmalayıcı.
Accordion Details: Accordion içeriği için sarmalayıcı.
Accordion Actions: Bir dizi düğmeyi gruplayan isteğe bağlı bir sarmalayıcı
Accordion: İlgili bileşenleri gruplamak için kullanılan sarmalayıcı.
Accordion Summary: Tıklandığında içeriği genişleten veya daraltan Accordion başlığı için sarmalayıcı.
Accordion Details: Accordion içeriği için sarmalayıcı.
Accordion Actions: Bir dizi düğmeyi gruplayan isteğe bağlı bir sarmalayıcı
JavaScript:
import * as React from 'react';
import Accordion, { accordionClasses } from '@mui/material/Accordion';
import AccordionSummary from '@mui/material/AccordionSummary';
import AccordionDetails, {
accordionDetailsClasses,
} from '@mui/material/AccordionDetails';
import Typography from '@mui/material/Typography';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import Fade from '@mui/material/Fade';
function App() {
const [expanded, setExpanded] = React.useState(false);
const handleExpansion = () => {
setExpanded((prevExpanded) => !prevExpanded);
};
const handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const formJson = Object.fromEntries(formData.entries());
const email = formJson.email;
console.log(email);
handleClose();
};
return (
<div>
<Accordion
expanded={expanded}
onChange={handleExpansion}
slots={{ transition: Fade }}
slotProps={{ transition: { timeout: 400 } }}
sx={[
expanded
? {
[`& .${accordionClasses.region}`]: {
height: 'auto',
},
[`& .${accordionDetailsClasses.root}`]: {
display: 'block',
},
}
: {
[`& .${accordionClasses.region}`]: {
height: 0,
},
[`& .${accordionDetailsClasses.root}`]: {
display: 'none',
},
},
]}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1-content"
id="panel1-header"
>
<Typography component="span">Custom transition using Fade</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
malesuada lacus ex, sit amet blandit leo lobortis eget.
</Typography>
</AccordionDetails>
</Accordion>
<Accordion>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel2-content"
id="panel2-header"
>
<Typography component="span">Default transition using Collapse</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
malesuada lacus ex, sit amet blandit leo lobortis eget.
</Typography>
</AccordionDetails>
</Accordion>
</div>
);
}
export default App;
Bu kodda iki tane Accordion (açılır panel) var.
expanded adında bir state tanımlanmış, bu accordion’un açık mı kapalı mı olduğunu kontrol eder.
Başlangıçta false olduğu için panel kapalıdır.
Kullanıcı accordion başlığına tıkladığında handleExpansion fonksiyonu çalışır ve expanded değerini tersine çevirir.
Yani kapalıysa açılır, açıksa kapanır.
İlk accordion’da slots ve slotProps özellikleri kullanılarak Fade geçiş efekti eklenmiş.
Bu sayede panel açılırken içerik yumuşak bir şekilde görünür hale gelir, kapanırken de kaybolur.
expanded true olduğunda detay kısmı (AccordionDetails) görünür, false olduğunda gizlenir.
Yani expanded state, panelin açık veya kapalı olma durumunu tamamen kontrol eder.
İkinci accordion ise özel bir efekt kullanmaz, varsayılan Collapse animasyonuyla açılıp kapanır.
Bu örnek, iki farklı açılma animasyonunu karşılaştırmak için hazırlanmıştır.
App Bar
App Bar aslında hepimizin bildiği header/ navbar alanıdır. Sıfırdan kendi başımıza css ile boğulmaktansa hazır olarak modern mui tasarımları mevcut. Kendinize göre kişileştirerek kullanabilirsiniz.
JavaScript:
import * as React from 'react';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Toolbar from '@mui/material/Toolbar';
import IconButton from '@mui/material/IconButton';
import Typography from '@mui/material/Typography';
import Menu from '@mui/material/Menu';
import MenuIcon from '@mui/icons-material/Menu';
import Container from '@mui/material/Container';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import Tooltip from '@mui/material/Tooltip';
import MenuItem from '@mui/material/MenuItem';
import AdbIcon from '@mui/icons-material/Adb';
function App() {
const pages = ['Products', 'Pricing', 'Blog'];
const settings = ['Profile', 'Account', 'Dashboard', 'Logout'];
const [anchorElNav, setAnchorElNav] = React.useState(null);
const [anchorElUser, setAnchorElUser] = React.useState(null);
const handleOpenNavMenu = (event) => {
setAnchorElNav(event.currentTarget);
};
const handleOpenUserMenu = (event) => {
setAnchorElUser(event.currentTarget);
};
const handleCloseNavMenu = () => {
setAnchorElNav(null);
};
const handleCloseUserMenu = () => {
setAnchorElUser(null);
};
return (
<AppBar position="static">
<Container maxWidth="xl">
<Toolbar disableGutters>
<AdbIcon sx={{ display: { xs: 'none', md: 'flex' }, mr: 1 }} />
<Typography
variant="h6"
noWrap
component="a"
href="#app-bar-with-responsive-menu"
sx={{
mr: 2,
display: { xs: 'none', md: 'flex' },
fontFamily: 'monospace',
fontWeight: 700,
letterSpacing: '.3rem',
color: 'inherit',
textDecoration: 'none',
}}
>
LOGO
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: 'flex', md: 'none' } }}>
<IconButton
size="large"
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
onClick={handleOpenNavMenu}
color="inherit"
>
<MenuIcon />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorElNav}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
open={Boolean(anchorElNav)}
onClose={handleCloseNavMenu}
sx={{ display: { xs: 'block', md: 'none' } }}
>
{pages.map((page) => (
<MenuItem key={page} onClick={handleCloseNavMenu}>
<Typography sx={{ textAlign: 'center' }}>{page}</Typography>
</MenuItem>
))}
</Menu>
</Box>
<AdbIcon sx={{ display: { xs: 'flex', md: 'none' }, mr: 1 }} />
<Typography
variant="h5"
noWrap
component="a"
href="#app-bar-with-responsive-menu"
sx={{
mr: 2,
display: { xs: 'flex', md: 'none' },
flexGrow: 1,
fontFamily: 'monospace',
fontWeight: 700,
letterSpacing: '.3rem',
color: 'inherit',
textDecoration: 'none',
}}
>
LOGO
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: 'none', md: 'flex' } }}>
{pages.map((page) => (
<Button
key={page}
onClick={handleCloseNavMenu}
sx={{ my: 2, color: 'white', display: 'block' }}
>
{page}
</Button>
))}
</Box>
<Box sx={{ flexGrow: 0 }}>
<Tooltip title="Open settings">
<IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
<Avatar alt="Remy Sharp" src="/static/images/avatar/2.jpg" />
</IconButton>
</Tooltip>
<Menu
sx={{ mt: '45px' }}
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={Boolean(anchorElUser)}
onClose={handleCloseUserMenu}
>
{settings.map((setting) => (
<MenuItem key={setting} onClick={handleCloseUserMenu}>
<Typography sx={{ textAlign: 'center' }}>{setting}</Typography>
</MenuItem>
))}
</Menu>
</Box>
</Toolbar>
</Container>
</AppBar>
);
}
export default App;
Bu kod, ekrana göre uyum sağlayan bir AppBar oluşturuyor. Büyük ekranlarda logo ve yatay menü butonları görünürken, küçük ekranlarda hamburger menü ile aynı öğelere erişiliyor. Sağ üstteki avatar butonuna tıklayınca kullanıcı menüsü açılıyor ve menüden bir öğeye tıklandığında veya dışarı tıklandığında menüler kapanıyor. anchorElNav ve anchorElUser state’leri menülerin açık veya kapalı olma durumunu kontrol ediyor. Kısaca, AppBar hem mobil hem masaüstünde çalışıyor ve açılır-kapanır navigasyon ile kullanıcı menüsü sağlıyor.
Card
Kartlar, tek bir konu hakkındaki içerik ve eylemleri görüntüleyen yüzeylerdir. Malzeme Kullanıcı Arayüzü Kartı bileşeni, çeşitli kullanım durumlarını ele almak için çeşitli tamamlayıcı yardımcı bileşenler içerir
JavaScript:
import Card from '@mui/material/Card';
import CardActions from '@mui/material/CardActions';
import CardContent from '@mui/material/CardContent';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
function App() {
return (
<div className='app'>
<Card sx={{ minWidth: 275 }}>
<CardContent>
<Typography gutterBottom sx={{ color: 'text.secondary', fontSize: 14 }}>
Günün Bilgisi
</Typography>
<Typography variant="h5" component="div">
Türk Hack Team
</Typography>
<Typography sx={{ color: 'text.secondary', mb: 1.5 }}>Siber Güvenlik Forumu</Typography>
<Typography variant="body2">
İstediğimiz Zaman, İstediğimiz Yerde
<br />
</Typography>
</CardContent>
<CardActions>
<Button size="small">Learn More</Button>
</CardActions>
</Card>
</div>
)
}
export default App
Bu kod, basit bir Card (kart) bileşeni oluşturuyor. Kartın içinde önce küçük bir başlık, sonra ana başlık ve alt başlık yer alıyor. Alt kısımda kısa bir açıklama (body2) ve bir buton bulunuyor. Kart, kullanıcıya bilgiyi düzenli ve okunabilir şekilde sunuyor; örneğin burada “Günün Bilgisi” başlığıyla tht gösteriliyor. CardContent içerikleri gösterirken, CardActions kısmı buton gibi etkileşimli öğeleri barındırıyor. Kısaca, bu kod bir bilgiyi ve ilgili işlemi görsel olarak şık bir kartta sunmayı sağlıyor.
Paper
Paper içeriğin yükseltilmiş bir yüzeyde görüntülenmesi için bir kaptır.
JavaScript:
import Grid from '@mui/material/Grid';
import Paper from '@mui/material/Paper';
import Box from '@mui/material/Box';
import { createTheme, ThemeProvider, styled } from '@mui/material/styles';
function App() {
const Item = styled(Paper)(({ theme }) => ({
...theme.typography.body2,
textAlign: 'center',
color: theme.palette.text.secondary,
height: 60,
lineHeight: '60px',
}));
const darkTheme = createTheme({ palette: { mode: 'dark' } });
const lightTheme = createTheme({ palette: { mode: 'light' } });
return (
<div className='app'>
<Box sx={{ flexGrow: 1 }}>
<Grid container spacing={2}>
{[lightTheme, darkTheme].map((theme, index) => (
<Grid key={index} size={6}>
<ThemeProvider theme={theme}>
<Box
sx={{
p: 2,
borderRadius: 2,
bgcolor: 'background.default',
display: 'grid',
gridTemplateColumns: { md: '1fr 1fr' },
gap: 2,
}}
>
{[0, 1, 2, 3, 4, 6, 8, 12, 16, 24].map((elevation) => (
<Item key={elevation} elevation={elevation}>
{`elevation=${elevation}`}
</Item>
))}
</Box>
</ThemeProvider>
</Grid>
))}
</Grid>
</Box>
</div>
)
}
export default App
Bu kod, Grid ve Paper bileşenleriyle bir kart düzeni oluşturuyor ve her bir kartın farklı elevation (gölgelendirme) değerlerini gösteriyor. Item adlı stilize edilmiş Paper, merkezi hizalanmış metin ve sabit yükseklik ile her kutuyu temsil ediyor. Kodda iki tema kullanılıyor: lightTheme ve darkTheme, böylece her iki tema altında elevation farkları gözlemlenebiliyor. Grid sistemi ile kutular düzenli bir şekilde yan yana ve alt alta yerleştiriliyor. Kısaca, bu örnek, farklı gölgelendirme seviyelerini ve tema farklarını görsel olarak karşılaştırmayı sağlıyor.
Bugün Surface bölümünü bitirdik. Componentlerden bunlardan ibaret ama daha fazla tasarım vs bakmak isterseniz resmi dokümantasyona bakmanızı öneririm. Okuduğunuz için teşekkürler bir başka konuda görüşürüz.
