Changeset 1b5c18b


Ignore:
Timestamp:
01/28/26 21:15:38 (5 months ago)
Author:
Mihail <mihail2.naumov@…>
Branches:
main
Children:
adc31ef
Parents:
1d8f088
Message:

Fixed specs displaying in the forge page and some scaling issues.

Files:
3 edited

Legend:

Unmodified
Added
Removed
  • components/ComponentDialog.tsx

    r1d8f088 r1b5c18b  
    11import React, {useEffect, useState} from 'react';
    22import {
    3     Dialog, DialogContent, IconButton, Box, Typography, Chip,
     3    Dialog, DialogContent, IconButton, Box, Typography,
    44    Slider, FormControl, InputLabel, Select, MenuItem, Checkbox, ListItemText,
    55    Card, CardContent, CardMedia, Button, CircularProgress, AppBar, Toolbar, InputAdornment, TextField,
    6     TextField as MuiTextField, DialogTitle, DialogActions, Snackbar, Alert
     6    TextField as MuiTextField, DialogTitle, DialogActions, Snackbar, Alert, Drawer, Badge
    77} from '@mui/material';
    88import CloseIcon from '@mui/icons-material/Close';
    99import AddCircleIcon from '@mui/icons-material/AddCircle';
     10import FilterListIcon from '@mui/icons-material/FilterList';
     11import SearchIcon from "@mui/icons-material/Search";
    1012
    1113import {onGetAllComponents, onGetAuthState, onSuggestComponent} from '../pages/+Layout.telefunc'
    1214import {onGetCompatibleComponents} from '../pages/forge/forge.telefunc';
    1315import ComponentDetailsDialog from "./ComponentDetailsDialog";
    14 import SearchIcon from "@mui/icons-material/Search";
    1516
    1617const formatMoney = (amount: number) => `$${Number(amount).toFixed(2)}`;
     
    3839    const [snackbarMessage, setSnackbarMessage] = useState("");
    3940    const [userId, setUserId] = useState<number | null>(null);
     41    const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false);
    4042
    4143    useEffect(() => {
     
    108110    }
    109111
    110 
    111 
    112112    const submitSuggestion = async () => {
    113113        if (!userId) {
     
    165165    };
    166166
     167    const activeFiltersCount = selectedBrands.length + (sortOrder !== 'default' ? 1 : 0);
     168
     169    const FilterContent = React.useMemo(() => (
     170        <Box sx={{width: {xs: 280, md: 300}, p: 3, bgcolor: 'transparent'}}>
     171            <TextField
     172                fullWidth
     173                size="small"
     174                placeholder="Search components..."
     175                value={tempSearchQuery}
     176                onChange={(e) => setTempSearchQuery(e.target.value)}
     177                sx={{mb: 2}}
     178                InputProps={{
     179                    startAdornment: <InputAdornment position="start"><SearchIcon/></InputAdornment>,
     180                }}
     181            />
     182
     183            <FormControl fullWidth size="small" sx={{mb: 2}}>
     184                <InputLabel>Sort By</InputLabel>
     185                <Select
     186                    value={sortOrder}
     187                    label="Sort By"
     188                    onChange={(e) => setSortOrder(e.target.value)}
     189                    MenuProps={{
     190                        container: typeof window !== 'undefined' ? document.body : undefined,
     191                        disablePortal: false,
     192                        sx: {
     193                            zIndex: 1500
     194                        }
     195                    }}
     196                >
     197                    <MenuItem value="price_asc">Price: Low to High</MenuItem>
     198                    <MenuItem value="price_desc">Price: High to Low</MenuItem>
     199                </Select>
     200            </FormControl>
     201
     202            <FormControl fullWidth size="small" sx={{mb: 2}}>
     203                <InputLabel>Brands</InputLabel>
     204                <Select
     205                    multiple
     206                    value={selectedBrands}
     207                    onChange={handleBrandChange}
     208                    label="Brands"
     209                    renderValue={(s) => s.join(', ')}
     210                    MenuProps={{
     211                        container: typeof window !== 'undefined' ? document.body : undefined,
     212                        disablePortal: false,
     213                        sx: {
     214                            zIndex: 1500
     215                        },
     216                        PaperProps: {
     217                            sx: {
     218                                maxHeight: 300
     219                            }
     220                        }
     221                    }}
     222                >
     223                    {availableBrands.map((brand) => (
     224                        <MenuItem key={brand} value={brand}>
     225                            <Checkbox checked={selectedBrands.indexOf(brand) > -1}/>
     226                            <ListItemText primary={brand}/>
     227                        </MenuItem>
     228                    ))}
     229                </Select>
     230            </FormControl>
     231
     232            <Typography gutterBottom fontWeight="bold">Price Range</Typography>
     233            <Slider value={priceRange} onChange={(_, v) => setPriceRange(v as number[])} min={0} max={2000}
     234                    sx={{color: '#ff8201'}}/>
     235            <Box sx={{display: 'flex', justifyContent: 'space-between', mt: 1}}>
     236                <Typography variant="caption">${priceRange[0]}</Typography>
     237                <Typography variant="caption">${priceRange[1]}+</Typography>
     238            </Box>
     239
     240            <Button
     241                fullWidth
     242                variant="contained"
     243                startIcon={<AddCircleIcon/>}
     244                onClick={() => setSuggestOpen(true)}
     245                sx={{
     246                    mt: 2,
     247                    bgcolor: '#ff8201',
     248                    fontWeight: 'bold',
     249                    fontSize: '0.875rem',
     250                    '&:hover': {bgcolor: '#e67300'}
     251                }}
     252            >
     253                Suggest Component
     254            </Button>
     255        </Box>
     256    ), [tempSearchQuery, sortOrder, selectedBrands, availableBrands, priceRange]);
     257
    167258    if (!open) return null;
    168259
    169260    return (
    170261        <>
    171             <Dialog open={open} onClose={onClose} maxWidth="xl" fullWidth sx={{height: '90vh'}}>
     262            <Dialog
     263                open={open}
     264                onClose={onClose}
     265                maxWidth="xl"
     266                fullWidth
     267                fullScreen
     268                sx={{
     269                    '& .MuiDialog-paper': {
     270                        height: {xs: '100%', md: '90vh'},
     271                        m: {xs: 0, md: 2}
     272                    }
     273                }}
     274            >
    172275                <AppBar position="relative" sx={{bgcolor: '#ff8201'}}>
    173276                    <Toolbar>
    174                         <Typography sx={{ml: 2, flex: 1, textTransform: 'capitalize'}} variant="h6" component="div">
    175                             Browsing: <b>{category === 'gpu' ? 'Graphics Cards' : category?.toUpperCase()}</b>
     277                        <IconButton
     278                            edge="start"
     279                            color="inherit"
     280                            onClick={() => setMobileFiltersOpen(true)}
     281                            sx={{
     282                                display: {xs: 'flex', md: 'none'},
     283                                mr: 2
     284                            }}
     285                        >
     286                            <Badge badgeContent={activeFiltersCount} color="error">
     287                                <FilterListIcon/>
     288                            </Badge>
     289                        </IconButton>
     290
     291                        <Typography
     292                            sx={{ml: {xs: 0, md: 2}, flex: 1, fontSize: {xs: '1rem', sm: '1.25rem'}}}
     293                            variant="h6"
     294                            component="div"
     295                        >
     296                            <Box component="span" sx={{display: {xs: 'none', sm: 'inline'}}}>
     297                                Browsing:
     298                            </Box>
     299                            <b> {category === 'gpu' ? 'Graphics Cards' : category?.toUpperCase()}</b>
    176300                            {mode === 'forge' && currentBuildId && (
    177                                 <Typography variant="caption"
    178                                             sx={{ml: 2, bgcolor: 'rgba(0,0,0,0.2)', px: 1, borderRadius: 1}}>
    179                                     COMPATIBILITY MODE ON
     301                                <Typography
     302                                    variant="caption"
     303                                    sx={{
     304                                        ml: {xs: 1, sm: 2},
     305                                        bgcolor: 'rgba(0,0,0,0.2)',
     306                                        px: 1,
     307                                        py: 0.5,
     308                                        borderRadius: 1,
     309                                        display: {xs: 'none', sm: 'inline-block'}
     310                                    }}
     311                                >
     312                                    COMPATIBILITY MODE
    180313                                </Typography>
    181314                            )}
    182315                        </Typography>
    183                         <IconButton edge="start" color="inherit" onClick={onClose}>
     316                        <IconButton edge="end" color="inherit" onClick={onClose}>
    184317                            <CloseIcon/>
    185318                        </IconButton>
     
    187320                </AppBar>
    188321
    189                 <DialogContent sx={{p: 0, display: 'flex', height: '100%'}}>
     322                <DialogContent sx={{p: 0, display: 'flex', height: '100%', overflow: 'hidden'}}>
    190323                    <Box sx={{
    191                         width: 300,
     324                        display: {xs: 'none', md: 'block'},
    192325                        borderRight: '1px solid #ddd',
    193                         p: 3,
    194                         bgcolor: '#1e1e1e',
    195                         display: {xs: 'none', md: 'block'},
    196                         overflowY: 'auto'
     326                        overflowY: 'auto',
     327                        bgcolor: '#1e1e1e'
    197328                    }}>
    198                         <TextField
    199                             fullWidth
    200                             size="small"
    201                             placeholder="Search components..."
    202                             value={tempSearchQuery}
    203                             onChange={(e) => setTempSearchQuery(e.target.value)}
    204                             sx={{mb: 2}}
    205                             InputProps={{
    206                                 startAdornment: <InputAdornment position="start"><SearchIcon/></InputAdornment>,
    207                             }}
    208                         />
    209 
    210 
    211                         <FormControl fullWidth size="small" sx={{mb: 2}}>
    212                             <InputLabel>Sort By</InputLabel>
    213                             <Select value={sortOrder} label="Sort By" onChange={(e) => setSortOrder(e.target.value)}>
    214                                 <MenuItem value="price_asc">Price: Low to High</MenuItem>
    215                                 <MenuItem value="price_desc">Price: High to Low</MenuItem>
    216                             </Select>
    217                         </FormControl>
    218 
    219                         <FormControl fullWidth size="small" sx={{mb: 2}}>
    220                             <InputLabel>Brands</InputLabel>
    221                             <Select multiple value={selectedBrands} onChange={handleBrandChange} label="Brands"
    222                                     renderValue={(s) => s.join(', ')}>
    223                                 {availableBrands.map((brand) => (
    224                                     <MenuItem key={brand} value={brand}>
    225                                         <Checkbox checked={selectedBrands.indexOf(brand) > -1}/>
    226                                         <ListItemText primary={brand}/>
    227                                     </MenuItem>
    228                                 ))}
    229                             </Select>
    230                         </FormControl>
    231 
    232                         <Typography gutterBottom fontWeight="bold">Price Range</Typography>
    233                         <Slider value={priceRange} onChange={(_, v) => setPriceRange(v as number[])} min={0} max={2000}
    234                                 sx={{color: '#ff8201'}}/>
    235                         <Box sx={{display: 'flex', justifyContent: 'space-between', mt: 1}}>
    236                             <Typography variant="caption">${priceRange[0]}</Typography>
    237                             <Typography variant="caption">${priceRange[1]}+</Typography>
    238                         </Box>
    239                         {/*TO BE FINISHED*/}
    240                         <Button
    241                             fullWidth
    242                             variant="contained"
    243                             startIcon={<AddCircleIcon/>}
    244                             onClick={() => setSuggestOpen(true)}
    245                             sx={{
    246                                 mt: 2,
    247                                 bgcolor: '#ff8201',
    248                                 fontWeight: 'bold',
    249                                 fontSize: '0.875rem',
    250                                 '&:hover': {bgcolor: '#e67300'}
    251                             }}
    252                         >
    253                             Suggest Component
    254                         </Button>
     329                        {FilterContent}
    255330                    </Box>
    256 
    257                     <Box sx={{flex: 1, p: 3, overflowY: 'auto', bgcolor: '#121212'}}>
     331                    <Box sx={{flex: 1, p: {xs: 1.5, sm: 2, md: 3}, overflowY: 'auto', bgcolor: '#121212'}}>
    258332                        {loading ? (
    259333                            <Box sx={{display: 'flex', justifyContent: 'center', mt: 10}}>
     
    266340                                    xs: '1fr',
    267341                                    sm: 'repeat(2, 1fr)',
    268                                     md: 'repeat(3, 1fr)',
    269                                     lg: 'repeat(4, 1fr)',
    270                                     xl: 'repeat(5, 1fr)'
     342                                    md: 'repeat(2, 1fr)',
     343                                    lg: 'repeat(3, 1fr)',
     344                                    xl: 'repeat(4, 1fr)'
    271345                                },
    272                                 gap: 3,
     346                                gap: {xs: 1.5, sm: 2, md: 3},
    273347                                width: '100%'
    274348                            }}>
     
    301375                                                        height: '100%',
    302376                                                        objectFit: 'contain',
    303                                                         p: 2
     377                                                        p: {xs: 1, sm: 2}
    304378                                                    }}
    305379                                                />
     
    310384                                                display: 'flex',
    311385                                                flexDirection: 'column',
    312                                                 justifyContent: 'space-between'
     386                                                justifyContent: 'space-between',
     387                                                p: {xs: 1.5, sm: 2}
    313388                                            }}>
    314389                                                <Box>
    315                                                     <Typography variant="caption" color="text.secondary"
    316                                                                 sx={{textTransform: 'uppercase', letterSpacing: 0.5}}>
     390                                                    <Typography
     391                                                        variant="caption"
     392                                                        color="text.secondary"
     393                                                        sx={{
     394                                                            textTransform: 'uppercase',
     395                                                            letterSpacing: 0.5,
     396                                                            fontSize: {xs: '0.65rem', sm: '0.75rem'}
     397                                                        }}
     398                                                    >
    317399                                                        {comp.brand}
    318400                                                    </Typography>
    319                                                     <Typography variant="subtitle1" fontWeight="bold" sx={{
    320                                                         lineHeight: 1.2,
    321                                                         mt: 0.5,
    322                                                         mb: 1,
    323                                                         overflow: 'hidden',
    324                                                         textOverflow: 'ellipsis',
    325                                                         display: '-webkit-box',
    326                                                         WebkitLineClamp: 2,
    327                                                         WebkitBoxOrient: 'vertical',
    328                                                         minHeight: '2.4em'
    329                                                     }}>
     401                                                    <Typography
     402                                                        variant="subtitle1"
     403                                                        fontWeight="bold"
     404                                                        sx={{
     405                                                            lineHeight: 1.2,
     406                                                            mt: 0.5,
     407                                                            mb: 1,
     408                                                            overflow: 'hidden',
     409                                                            textOverflow: 'ellipsis',
     410                                                            display: '-webkit-box',
     411                                                            WebkitLineClamp: 2,
     412                                                            WebkitBoxOrient: 'vertical',
     413                                                            minHeight: '2.4em',
     414                                                            fontSize: {xs: '0.875rem', sm: '1rem'}
     415                                                        }}
     416                                                    >
    330417                                                        {comp.name}
    331418                                                    </Typography>
    332419                                                </Box>
    333                                                 <Typography variant="h6" color="primary.main" fontWeight="bold">
     420                                                <Typography
     421                                                    variant="h6"
     422                                                    color="primary.main"
     423                                                    fontWeight="bold"
     424                                                    sx={{fontSize: {xs: '1rem', sm: '1.25rem'}}}
     425                                                >
    334426                                                    {formatMoney(comp.price)}
    335427                                                </Typography>
    336428                                            </CardContent>
    337429
    338                                             <Box sx={{p: 2, pt: 0, display: 'flex', flexDirection: 'column', gap: 1}}>
     430                                            <Box sx={{
     431                                                p: {xs: 1.5, sm: 2},
     432                                                pt: 0,
     433                                                display: 'flex',
     434                                                flexDirection: 'column',
     435                                                gap: 1
     436                                            }}>
    339437                                                <Button
    340438                                                    fullWidth
    341439                                                    variant="contained"
    342440                                                    onClick={() => setSelectedComponent(comp)}
     441                                                    size="small"
    343442                                                    sx={{
    344443                                                        bgcolor: '#ff8201',
    345444                                                        fontWeight: 'bold',
     445                                                        fontSize: {xs: '0.75rem', sm: '0.875rem'},
    346446                                                        '&:hover': {bgcolor: '#e67300'}
    347447                                                    }}
     
    354454                                                        variant="contained"
    355455                                                        onClick={() => onSelect(comp)}
     456                                                        size="small"
    356457                                                        sx={{
    357458                                                            bgcolor: '#4caf50',
    358459                                                            fontWeight: 'bold',
     460                                                            fontSize: {xs: '0.75rem', sm: '0.875rem'},
    359461                                                            '&:hover': {bgcolor: '#388e3c'}
    360462                                                        }}
     
    369471                                {processedComponents.length === 0 && (
    370472                                    <Box sx={{gridColumn: '1 / -1', width: '100%', textAlign: 'center', mt: 5}}>
    371                                         <Typography variant="h6" color="text.secondary">
     473                                        <Typography variant="h6" color="text.secondary"
     474                                                    sx={{fontSize: {xs: '1rem', sm: '1.25rem'}}}>
    372475                                            No compatible components found.
    373476                                        </Typography>
     
    390493                />
    391494            </Dialog>
     495
     496            <Drawer
     497                anchor="left"
     498                open={mobileFiltersOpen && open}
     499                onClose={() => setMobileFiltersOpen(false)}
     500                sx={{zIndex: 1400}}
     501                PaperProps={{
     502                    sx: {
     503                        bgcolor: '#1e1e1e'
     504                    }
     505                }}
     506                disableScrollLock={true}
     507            >
     508                <Box sx={{pt: 2, width: 280}}>
     509                    <Box sx={{
     510                        display: 'flex',
     511                        justifyContent: 'space-between',
     512                        alignItems: 'center',
     513                        px: 3,
     514                        pb: 2
     515                    }}>
     516                        <Typography variant="h6" fontWeight="bold">Filters</Typography>
     517                        <IconButton onClick={() => setMobileFiltersOpen(false)}>
     518                            <CloseIcon/>
     519                        </IconButton>
     520                    </Box>
     521                    {FilterContent}
     522                </Box>
     523            </Drawer>
    392524
    393525            <Dialog open={suggestOpen} onClose={() => setSuggestOpen(false)} maxWidth="sm" fullWidth>
  • pages/forge/+Page.tsx

    r1d8f088 r1b5c18b  
    538538                    Add Optional Component
    539539                </Button>
    540                 <Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={() => setAnchorEl(null)}>
     540                <Menu
     541                    anchorEl={anchorEl}
     542                    open={Boolean(anchorEl)}
     543                    onClose={() => setAnchorEl(null)}
     544                    anchorReference="none"
     545                    sx={{
     546                        display: 'flex',
     547                        alignItems: 'center',
     548                        justifyContent: 'center',
     549                    }}
     550                    slotProps={{
     551                        paper: {
     552                            sx: {
     553                                position: 'absolute',
     554                                top: '30%',
     555                                // left: '50%',
     556                                // transform: 'translate(50%, +50%)',
     557                            }
     558                        }
     559                    }}
     560                >
    541561                    {/*Removed RAM & Storage from optional components*/}
    542562                    <Typography sx={{px: 2, py: 1, display: 'block', color: 'text.secondary'}}>
  • pages/forge/utils/RenderSpecs.tsx

    r1d8f088 r1b5c18b  
    1 import { Chip, Typography } from '@mui/material';
     1import {Chip, Typography} from '@mui/material';
    22import React from "react";
    33
     
    1010
    1111    switch (type) {
     12
    1213        case 'cpu':
    13             if (val('socket')) specs.push(val('socket'));
     14            if (val('socket')) specs.push(`Socket: ${val('socket')}`);
    1415            if (val('cores')) specs.push(`${val('cores')} Cores / ${val('threads')} Threads`);
    1516            const base = data.baseclock || data.baseClock || data.base_clock;
    1617            const boost = data.boostclock || data.boostClock || data.boost_clock;
    17             if (base) specs.push(`Base: ${base}GHz`);
    18             if (boost) specs.push(`Boost: ${boost}GHz`);
     18            if (base) specs.push(`Base Clock Speed: ${base}GHz`);
     19            if (boost) specs.push(`Boost Clock Speed: ${boost}GHz`);
    1920            break;
    2021        case 'gpu':
    21             if (val('vram')) specs.push(`${val('vram')}GB VRAM`);
    22             if (val('chipset')) specs.push(val('chipset'));
    23             if (val('length')) specs.push(`L: ${val('length')}mm`);
     22            if (val('vram')) specs.push(`VRAM: ${val('vram')}GB`);
     23            if (val('tdp')) specs.push(`Card TDP: ${val('tdp')}W`);
     24            if (val('length')) specs.push(`Length: ${val('length')}mm`);
     25            if (val('baseClock')) specs.push(`Base Clock Speed: ${val('baseClock')}GHz`);
     26            if (val('boostClock')) specs.push(`Boost Clock Speed: ${val('boostClock')}GHz`);
    2427            break;
    2528        case 'motherboard':
    26             if (val('socket')) specs.push(val('socket'));
    27             if (val('formfactor')) specs.push(val('formfactor'));
    28             if (val('ramtype')) specs.push(val('ramtype'));
     29            if (val('socket')) specs.push(`Socket: ${val('socket')}`);
     30            if (val('formFactor')) specs.push(`Form Factor: ${val('formFactor')}`);
     31            if (val('ramType')) specs.push(`RAM Type: ${val('ramType')}`);
     32            if (val('numRamSlots')) specs.push(`RAM Slots: ${val('numRamSlots')}`);
     33            if (val('maxRamCapacity')) specs.push(`Max Ram Caacity: ${val('maxRamCapacity')}GB`);
    2934            break;
    3035        case 'memory':
    31             if (val('capacity')) specs.push(`${val('capacity')}GB`);
    32             if (val('type')) specs.push(val('type'));
    33             if (val('speed')) specs.push(`${val('speed')} MHz`);
    34             if (val('modules')) specs.push(`${val('modules')}x`);
     36            if (val('capacity')) specs.push(`Size Per Stick: ${val('capacity')}GB`);
     37            if (val('type')) specs.push(`RAM Type: ${val('type')}`);
     38            if (val('speed')) specs.push(`RAM Speed: ${val('speed')} MHz`);
     39            if (val('modules')) specs.push(`Modules: ${val('modules')}`);
    3540            break;
    3641        case 'storage':
    37             if (val('capacity')) specs.push(`${val('capacity')}GB`);
    38             if (val('type')) specs.push(val('type'));
     42            if (val('capacity')) specs.push(`Capacity: ${val('capacity')}GB`);
     43            if (val('type')) specs.push(`Type: ${val('type')}`);
    3944            break;
    4045        case 'power_supply':
    4146            if (val('wattage')) specs.push(`Wattage: ${val('wattage')}W`);
    42             if (val('type')) specs.push(val('type'));
     47            if (val('type')) specs.push(`Type: ${val('type')}`);
     48            if (val('formFactor')) specs.push(`Form Factor: ${val('formFactor')}`);
    4349            break;
    4450        case 'case':
     
    4753            break;
    4854        case 'cooler':
    49             if (val('type')) specs.push(`${val('type')} Cooler`);
    50             if (val('height')) specs.push(`${val('height')}mm`);
     55            if (val('type')) specs.push(`Cooler Type: ${val('type')} Cooler`);
     56            if (val('height')) specs.push(`Height: ${val('height')}mm`);
     57            if (val('maxTdpSupported')) specs.push(`Max TDP: ${val('maxTdpSupported')}W`);
     58            break;
     59        case 'network_card':
     60            if (val('interface')) specs.push(`Interface: ${val('interface')}`);
     61            if (val('numPorts')) specs.push(`Number of Ports: ${val('numPorts')}`);
     62            if (val('speed')) specs.push(`Speed: ${val('speed')}Mbps`);
     63            break;
     64        case 'network_adapter':
     65            if (val('interface')) specs.push(`Interface: ${val('interface')}`);
     66            if (val('numAntennas')) specs.push(`Number of Antennas: ${val('numAntennas')}`);
     67            if (val('wifiVersion')) specs.push(`Wi-Fi Version: ${val('wifiVersion')}`);
     68            break;
     69        case 'sound_card':
     70            if (val('interface')) specs.push(`Interface: ${val('interface')}`);
     71            if (val('chipset')) specs.push(`Chipset: ${val('chipset')}`);
     72            if (val('channel')) specs.push(`Channels: ${val('channel')}`);
     73            break;
     74        case 'memory_card':
     75            if (val('interface')) specs.push(`Interface: ${val('interface')}`);
     76            if (val('numSlots')) specs.push(`Number of Slots: ${val('numSlots')}`);
     77            break;
     78        case 'optical_drive':
     79            if (val('interface')) specs.push(`Interface: ${val('interface')}`);
     80            if (val('type')) specs.push(`Type: ${val('type')}`);
     81            if (val('formFactor')) specs.push(`Form Factor: ${val('formFactor')}`);
     82            break;
     83        case 'cables':
     84            if (val('type')) specs.push(`Type of Cables: ${val('type')}`);
     85            if (val('lengthCm')) specs.push(`Length: ${val('lengthCm')}cm`);
    5186            break;
    5287        default:
Note: See TracChangeset for help on using the changeset viewer.