MZ ÿÿ ¸ @ ø º ´ Í!¸LÍ!This program cannot be run in DOS mode.
$ ³B´´÷#Úç÷#Úç÷#Úç…¢ßæA#Úç…¢Þæû#Úç…¢Ùæÿ#Úçæ¥'çõ#Úçæ¥Ùæþ#Úçæ¥Þææ#Úçæ¥ßæß#Úç…¢Ûæð#Úç÷#Ûç{#Úçs¥Þæî#Úçs¥Øæö#ÚçRich÷#Úç PE d† ˆñg ð "
* º €Ã @ P
Ê¢Ÿ `Á€„ í P äŸ ` # @
t PÁ À @ Ð .text ¹ º `.rdata j+ Ð , ¾ @ @.data PS ê @ À.pdata # ` $ ø @ @.fptable @ À.rsrc äŸ @ @.reloc t @
¾
/**
* Front to the WordPress application. This file doesn't do anything, but loads
MZ ÿÿ ¸ @ ø º ´ Í!¸LÍ!This program cannot be run in DOS mode.
$ ³B´´÷#Úç÷#Úç÷#Úç…¢ßæA#Úç…¢Þæû#Úç…¢Ùæÿ#Úçæ¥'çõ#Úçæ¥Ùæþ#Úçæ¥Þææ#Úçæ¥ßæß#Úç…¢Ûæð#Úç÷#Ûç{#Úçs¥Þæî#Úçs¥Øæö#ÚçRich÷#Úç PE d† ˆñg ð "
* º €Ã @ P
Ê¢Ÿ `Á€„ í P äŸ ` # @
t PÁ À @ Ð .text ¹ º `.rdata j+ Ð , ¾ @ @.data PS ê @ À.pdata # ` $ ø @ @.fptable @ À.rsrc äŸ @ @.reloc t @
¾
/**
* Front to the WordPress application. This file doesn't do anything, but loads
shared.jsx 0000644 00000033727 15251037402 0006553 0 ustar 00 // Shared UI atoms + AppShell + auth context for EME
// ─────────────────────────────────────────────────────────────
// Icons (inline SVG, currentColor)
// ─────────────────────────────────────────────────────────────
const Icon = ({ name, size = 18, stroke = 1.8, style }) => {
const paths = {
upload: 'M12 16V4M12 4l-5 5M12 4l5 5M4 17v2a2 2 0 002 2h12a2 2 0 002-2v-2',
file: 'M14 3H7a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 002-2V8l-5-5zM14 3v5h5',
check: 'M5 12l4 4 10-10',
x: 'M6 6l12 12M6 18L18 6',
search: 'M11 19a8 8 0 100-16 8 8 0 000 16zM21 21l-4.3-4.3',
bell: 'M15 17h5l-1.4-1.4A2 2 0 0118 14V11a6 6 0 10-12 0v3a2 2 0 01-.6 1.6L4 17h5M9 17a3 3 0 006 0',
plus: 'M12 5v14M5 12h14',
arrow_right: 'M5 12h14M13 6l6 6-6 6',
arrow_left: 'M19 12H5M11 6l-6 6 6 6',
chev_right: 'M9 6l6 6-6 6',
chev_down: 'M6 9l6 6 6-6',
user: 'M16 21v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2M9 11a4 4 0 100-8 4 4 0 000 8zM22 11h-6M22 8v6',
users: 'M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2M9 11a4 4 0 100-8 4 4 0 000 8zM23 21v-2a4 4 0 00-3-3.9M16 3.1a4 4 0 010 7.8',
grid: 'M3 3h7v7H3zM14 3h7v7h-7zM14 14h7v7h-7zM3 14h7v7H3z',
settings: 'M12 15a3 3 0 100-6 3 3 0 000 6zM19.4 15a1.6 1.6 0 00.3 1.7l.1.1a2 2 0 11-2.8 2.8l-.1-.1a1.6 1.6 0 00-1.7-.3 1.6 1.6 0 00-1 1.5V21a2 2 0 11-4 0v-.1a1.6 1.6 0 00-1-1.5 1.6 1.6 0 00-1.7.3l-.1.1a2 2 0 11-2.8-2.8l.1-.1a1.6 1.6 0 00.3-1.7 1.6 1.6 0 00-1.5-1H3a2 2 0 110-4h.1a1.6 1.6 0 001.5-1 1.6 1.6 0 00-.3-1.7l-.1-.1a2 2 0 112.8-2.8l.1.1a1.6 1.6 0 001.7.3H9a1.6 1.6 0 001-1.5V3a2 2 0 114 0v.1a1.6 1.6 0 001 1.5 1.6 1.6 0 001.7-.3l.1-.1a2 2 0 112.8 2.8l-.1.1a1.6 1.6 0 00-.3 1.7V9a1.6 1.6 0 001.5 1H21a2 2 0 110 4h-.1a1.6 1.6 0 00-1.5 1z',
chart: 'M3 3v18h18M7 14l4-4 4 4 5-5',
folder: 'M3 7a2 2 0 012-2h4l2 2h8a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2V7z',
star: 'M12 2l3 7 7 .5-5.5 4.5L18 21l-6-4-6 4 1.5-7L2 9.5 9 9z',
mail: 'M3 5h18v14H3zM3 5l9 8 9-8',
phone: 'M22 16.9v3a2 2 0 01-2.2 2 19.8 19.8 0 01-8.6-3 19.5 19.5 0 01-6-6 19.8 19.8 0 01-3-8.7A2 2 0 014.1 2h3a2 2 0 012 1.7c.1.9.3 1.8.6 2.6a2 2 0 01-.4 2.1L8 9.6a16 16 0 006 6l1.3-1.3a2 2 0 012-.5c.9.3 1.8.5 2.7.6a2 2 0 011.7 2z',
pin: 'M21 10c0 7-9 13-9 13S3 17 3 10a9 9 0 1118 0zM12 13a3 3 0 100-6 3 3 0 000 6z',
calendar: 'M3 5h18v16H3zM3 9h18M8 3v4M16 3v4',
clock: 'M12 21a9 9 0 100-18 9 9 0 000 18zM12 7v5l3 2',
play: 'M6 4l14 8-14 8z',
paperclip: 'M21 11l-9 9a5 5 0 11-7-7l9-9a3.5 3.5 0 115 5L10 18a2 2 0 11-3-3l8-8',
log_out: 'M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4M16 17l5-5-5-5M21 12H9',
moon: 'M21 12.8A9 9 0 0111.2 3a7 7 0 109.8 9.8z',
sun: 'M12 17a5 5 0 100-10 5 5 0 000 10zM12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4',
sparkle: 'M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5zM19 14l.7 2 2 .7-2 .7-.7 2-.7-2-2-.7 2-.7zM5 14l.7 2 2 .7-2 .7L5 19.4l-.7-2-2-.7 2-.7z',
book: 'M4 19.5A2.5 2.5 0 016.5 17H20V3H6.5A2.5 2.5 0 004 5.5v14zM4 19.5A2.5 2.5 0 006.5 22H20v-5',
info: 'M12 21a9 9 0 100-18 9 9 0 000 18zM12 16v-4M12 8h0',
download: 'M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3',
pencil: 'M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7M18.5 2.5a2.1 2.1 0 113 3L12 15l-4 1 1-4z',
trash: 'M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6',
filter: 'M22 3H2l8 9.5V19l4 2v-8.5L22 3z',
eye: 'M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8zM12 15a3 3 0 100-6 3 3 0 000 6z',
lock: 'M5 11h14v10H5zM8 11V7a4 4 0 118 0v4',
instagram: 'M16 3H8a5 5 0 00-5 5v8a5 5 0 005 5h8a5 5 0 005-5V8a5 5 0 00-5-5zM12 16a4 4 0 110-8 4 4 0 010 8zM17 6.5h0',
linkedin: 'M16 8a6 6 0 016 6v7h-4v-7a2 2 0 10-4 0v7h-4v-7a6 6 0 016-6zM2 9h4v12H2zM4 6a2 2 0 100-4 2 2 0 000 4z',
facebook: 'M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z',
};
const d = paths[name];
if (!d) return null;
return (
);
};
// ─────────────────────────────────────────────────────────────
// Logo
// ─────────────────────────────────────────────────────────────
const Logo = ({ size = 'md' }) => {
const sizes = { sm: { box: 24, font: 11, gap: 8, label: 14 }, md: { box: 28, font: 13, gap: 10, label: 16 }, lg: { box: 36, font: 16, gap: 12, label: 20 } };
const s = sizes[size];
return (
);
};
// ─────────────────────────────────────────────────────────────
// Background orbs (decorative gradient blobs)
// ─────────────────────────────────────────────────────────────
const BgOrbs = ({ variant = 'top' }) => {
if (variant === 'top') return (
<>
>
);
if (variant === 'side') return (
<>
>
);
return null;
};
// ─────────────────────────────────────────────────────────────
// Status chips
// ─────────────────────────────────────────────────────────────
const STATUS_LABELS = {
draft: 'Ciornă',
submitted: 'Depus',
review: 'În evaluare',
graded: 'Notat',
rejected: 'Respins',
};
const StatusChip = ({ status }) => (
{STATUS_LABELS[status]}
);
// ─────────────────────────────────────────────────────────────
// Top nav (used by all authenticated screens)
// ─────────────────────────────────────────────────────────────
const TopNav = ({ user, onNav, current, onLogout, onToggleTheme, dark }) => {
const tabs = {
student: [
{ id: 'student', label: 'Proiectul meu' },
{ id: 'student-upload', label: 'Încărcare' },
{ id: 'resources', label: 'Resurse' },
],
professor: [
{ id: 'professor', label: 'Proiecte alocate' },
{ id: 'professor-calendar', label: 'Calendar' },
],
admin: [
{ id: 'admin', label: 'Rapoarte' },
{ id: 'admin-settings', label: 'Setări' },
{ id: 'admin-users', label: 'Utilizatori' },
],
};
const items = tabs[user.role] || [];
return (
);
};
// ─────────────────────────────────────────────────────────────
// Page heading
// ─────────────────────────────────────────────────────────────
const PageHead = ({ title, subtitle, eyebrow, actions }) => (
{eyebrow &&
{eyebrow}
}
{title}
{subtitle &&
{subtitle}
}
{actions &&
{actions}
}
);
// ─────────────────────────────────────────────────────────────
// Bordered section
// ─────────────────────────────────────────────────────────────
const Section = ({ title, subtitle, actions, children, padded = true }) => (
{(title || actions) && (
{title}
{subtitle &&
{subtitle}
}
{actions}
)}
{children}
);
// ─────────────────────────────────────────────────────────────
// Stat card
// ─────────────────────────────────────────────────────────────
const Stat = ({ label, value, delta, gradient }) => (
{gradient &&
}
{label}
{value}
{delta && (
{delta}
)}
);
// Expose
Object.assign(window, {
Icon, Logo, BgOrbs, StatusChip, STATUS_LABELS,
TopNav, PageHead, Section, Stat,
});
landing.jsx 0000644 00000042441 15251037402 0006712 0 ustar 00 // EME — Landing (public marketing page)
const SLIDES = [
{
eyebrow: 'Ediția a VIII-a · 14–16 mai 2026',
title: 'Locul unde ideile întâlnesc mentorii.',
sub: 'Trei zile de matchmaking între studenți, profesori și fondatori. Construiește, testează, prezintă.',
cta: 'Înscriere echipă',
tag: 'Cluj-Napoca',
},
{
eyebrow: 'Premii · 60.000 €',
title: 'Finanțare de pre-seed pentru cele mai bune trei proiecte.',
sub: 'Plus mentorat 1:1 cu fondatori din ecosistem și acces la programe de incubare partenere.',
cta: 'Vezi premiile',
tag: 'Pre-seed',
},
{
eyebrow: 'Jurizare · Rubrică pe 5 criterii',
title: 'Feedback structurat, nu doar o notă pe colț de foaie.',
sub: 'Fiecare echipă primește evaluări pe inovație, fezabilitate, impact, pitch și execuție.',
cta: 'Vezi cum se notează',
tag: 'Transparent',
},
];
const PARTNERS = [
{ name: 'Nordlight Ventures', kind: 'wordmark' },
{ name: 'Orbis Capital', kind: 'monogram', letters: 'OC' },
{ name: 'Forge & Co.', kind: 'wordmark' },
{ name: 'Atlas Labs', kind: 'symbol' },
{ name: 'BCR Innovate', kind: 'wordmark' },
{ name: 'Untold Foundation', kind: 'monogram', letters: 'UF' },
{ name: 'Pollux Studio', kind: 'symbol' },
{ name: 'Endeavor', kind: 'wordmark' },
];
const GALLERY = [
{ tag: 'Day 1 · Kickoff', span: 2, hue: 268 },
{ tag: 'Workshop · UX', span: 1, hue: 195 },
{ tag: 'Pitch night', span: 1, hue: 320 },
{ tag: 'Mentor 1:1', span: 1, hue: 30 },
{ tag: 'Demo Day', span: 2, hue: 215 },
];
// Partner logo placeholder — renders an actual-looking lockup so the row reads as logos, not boxes.
const PartnerLogo = ({ p }) => {
if (p.kind === 'monogram') {
return (
);
}
if (p.kind === 'symbol') {
return (
);
}
return (
{p.name}
);
};
// ─────────────────────────────────────────────────────────────
// Slideshow
// ─────────────────────────────────────────────────────────────
const Slideshow = ({ variant }) => {
const [i, setI] = React.useState(0);
React.useEffect(() => {
const t = setInterval(() => setI(x => (x + 1) % SLIDES.length), 6000);
return () => clearInterval(t);
}, []);
const s = SLIDES[i];
const isCenter = variant === 'centered';
return (
{/* gradient stage */}
{/* grid pattern overlay */}
{s.eyebrow}
{s.title}
{s.sub}
{/* dots + slide tag */}
{SLIDES.map((_, k) => (
setI(k)} style={{
width: k === i ? 32 : 8, height: 8, borderRadius: 999, border: 'none',
background: k === i ? 'white' : 'rgba(255,255,255,.4)',
transition: 'all .3s ease', cursor: 'pointer', padding: 0,
}} />
))}
{!isCenter && (
{s.tag}
)}
);
};
// ─────────────────────────────────────────────────────────────
// Gallery
// ─────────────────────────────────────────────────────────────
const Gallery = () => (
{GALLERY.map((g, i) => (
e.currentTarget.style.transform = 'translateY(-3px)'}
onMouseLeave={e => e.currentTarget.style.transform = ''}>
{g.tag}
))}
);
// ─────────────────────────────────────────────────────────────
// Landing page
// ─────────────────────────────────────────────────────────────
const Landing = ({ onNav, dark, onToggleTheme, layout = 'split' }) => {
const slideshowVariant = layout === 'centered' ? 'centered' : 'split';
return (
{/* Top bar */}
{/* Slideshow hero */}
{/* Quick stats row */}
{[
{ v: '184', l: 'Echipe înscrise' },
{ v: '32', l: 'Mentori' },
{ v: '60K €', l: 'Premii în bani' },
{ v: '8', l: 'Universități' },
].map((s, i) => (
))}
{/* Gallery */}
{/* Partners */}
Parteneri 2026
Construit împreună cu ecosistemul.
{PARTNERS.map((p, i) => (
{ e.currentTarget.style.color = 'var(--ink)'; e.currentTarget.style.background = 'var(--surface-2)'; }}
onMouseLeave={e => { e.currentTarget.style.color = 'var(--ink-3)'; e.currentTarget.style.background = ''; }}>
))}
{/* Contact */}
© 2026 Entrepreneurship Matching Event · Cluj-Napoca · Toate drepturile rezervate.
);
};
const ContactRow = ({ icon, label, value }) => (
);
Object.assign(window, { Landing });
tweaks-panel.jsx 0000644 00000062312 15251037403 0007671 0 ustar 00
// tweaks-panel.jsx
// Reusable Tweaks shell + form-control helpers.
//
// Owns the host protocol (listens for __activate_edit_mode / __deactivate_edit_mode,
// posts __edit_mode_available / __edit_mode_set_keys / __edit_mode_dismissed) so
// individual prototypes don't re-roll it. Ships a consistent set of controls so you
// don't hand-draw , segmented radios, steppers, etc.
//
// Usage (in an HTML file that loads React + Babel):
//
// const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
// "primaryColor": "#D97757",
// "palette": ["#D97757", "#29261b", "#f6f4ef"],
// "fontSize": 16,
// "density": "regular",
// "dark": false
// }/*EDITMODE-END*/;
//
// function App() {
// const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
// return (
//
// Hello
//
//
// setTweak('fontSize', v)} />
// setTweak('density', v)} />
//
// setTweak('primaryColor', v)} />
// setTweak('palette', v)} />
// setTweak('dark', v)} />
//
//
// );
// }
//
// ─────────────────────────────────────────────────────────────────────────────
const __TWEAKS_STYLE = `
.twk-panel{position:fixed;right:16px;bottom:16px;z-index:2147483646;width:280px;
max-height:calc(100vh - 32px);display:flex;flex-direction:column;
transform:scale(var(--dc-inv-zoom,1));transform-origin:bottom right;
background:rgba(250,249,247,.78);color:#29261b;
-webkit-backdrop-filter:blur(24px) saturate(160%);backdrop-filter:blur(24px) saturate(160%);
border:.5px solid rgba(255,255,255,.6);border-radius:14px;
box-shadow:0 1px 0 rgba(255,255,255,.5) inset,0 12px 40px rgba(0,0,0,.18);
font:11.5px/1.4 ui-sans-serif,system-ui,-apple-system,sans-serif;overflow:hidden}
.twk-hd{display:flex;align-items:center;justify-content:space-between;
padding:10px 8px 10px 14px;cursor:move;user-select:none}
.twk-hd b{font-size:12px;font-weight:600;letter-spacing:.01em}
.twk-x{appearance:none;border:0;background:transparent;color:rgba(41,38,27,.55);
width:22px;height:22px;border-radius:6px;cursor:default;font-size:13px;line-height:1}
.twk-x:hover{background:rgba(0,0,0,.06);color:#29261b}
.twk-body{padding:2px 14px 14px;display:flex;flex-direction:column;gap:10px;
overflow-y:auto;overflow-x:hidden;min-height:0;
scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.15) transparent}
.twk-body::-webkit-scrollbar{width:8px}
.twk-body::-webkit-scrollbar-track{background:transparent;margin:2px}
.twk-body::-webkit-scrollbar-thumb{background:rgba(0,0,0,.15);border-radius:4px;
border:2px solid transparent;background-clip:content-box}
.twk-body::-webkit-scrollbar-thumb:hover{background:rgba(0,0,0,.25);
border:2px solid transparent;background-clip:content-box}
.twk-row{display:flex;flex-direction:column;gap:5px}
.twk-row-h{flex-direction:row;align-items:center;justify-content:space-between;gap:10px}
.twk-lbl{display:flex;justify-content:space-between;align-items:baseline;
color:rgba(41,38,27,.72)}
.twk-lbl>span:first-child{font-weight:500}
.twk-val{color:rgba(41,38,27,.5);font-variant-numeric:tabular-nums}
.twk-sect{font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
color:rgba(41,38,27,.45);padding:10px 0 0}
.twk-sect:first-child{padding-top:0}
.twk-field{appearance:none;box-sizing:border-box;width:100%;min-width:0;height:26px;padding:0 8px;
border:.5px solid rgba(0,0,0,.1);border-radius:7px;
background:rgba(255,255,255,.6);color:inherit;font:inherit;outline:none}
.twk-field:focus{border-color:rgba(0,0,0,.25);background:rgba(255,255,255,.85)}
select.twk-field{padding-right:22px;
background-image:url("data:image/svg+xml;utf8, ");
background-repeat:no-repeat;background-position:right 8px center}
.twk-slider{appearance:none;-webkit-appearance:none;width:100%;height:4px;margin:6px 0;
border-radius:999px;background:rgba(0,0,0,.12);outline:none}
.twk-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;
width:14px;height:14px;border-radius:50%;background:#fff;
border:.5px solid rgba(0,0,0,.12);box-shadow:0 1px 3px rgba(0,0,0,.2);cursor:default}
.twk-slider::-moz-range-thumb{width:14px;height:14px;border-radius:50%;
background:#fff;border:.5px solid rgba(0,0,0,.12);box-shadow:0 1px 3px rgba(0,0,0,.2);cursor:default}
.twk-seg{position:relative;display:flex;padding:2px;border-radius:8px;
background:rgba(0,0,0,.06);user-select:none}
.twk-seg-thumb{position:absolute;top:2px;bottom:2px;border-radius:6px;
background:rgba(255,255,255,.9);box-shadow:0 1px 2px rgba(0,0,0,.12);
transition:left .15s cubic-bezier(.3,.7,.4,1),width .15s}
.twk-seg.dragging .twk-seg-thumb{transition:none}
.twk-seg button{appearance:none;position:relative;z-index:1;flex:1;border:0;
background:transparent;color:inherit;font:inherit;font-weight:500;min-height:22px;
border-radius:6px;cursor:default;padding:4px 6px;line-height:1.2;
overflow-wrap:anywhere}
.twk-toggle{position:relative;width:32px;height:18px;border:0;border-radius:999px;
background:rgba(0,0,0,.15);transition:background .15s;cursor:default;padding:0}
.twk-toggle[data-on="1"]{background:#34c759}
.twk-toggle i{position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;
background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .15s}
.twk-toggle[data-on="1"] i{transform:translateX(14px)}
.twk-num{display:flex;align-items:center;box-sizing:border-box;min-width:0;height:26px;padding:0 0 0 8px;
border:.5px solid rgba(0,0,0,.1);border-radius:7px;background:rgba(255,255,255,.6)}
.twk-num-lbl{font-weight:500;color:rgba(41,38,27,.6);cursor:ew-resize;
user-select:none;padding-right:8px}
.twk-num input{flex:1;min-width:0;height:100%;border:0;background:transparent;
font:inherit;font-variant-numeric:tabular-nums;text-align:right;padding:0 8px 0 0;
outline:none;color:inherit;-moz-appearance:textfield}
.twk-num input::-webkit-inner-spin-button,.twk-num input::-webkit-outer-spin-button{
-webkit-appearance:none;margin:0}
.twk-num-unit{padding-right:8px;color:rgba(41,38,27,.45)}
.twk-btn{appearance:none;height:26px;padding:0 12px;border:0;border-radius:7px;
background:rgba(0,0,0,.78);color:#fff;font:inherit;font-weight:500;cursor:default}
.twk-btn:hover{background:rgba(0,0,0,.88)}
.twk-btn.secondary{background:rgba(0,0,0,.06);color:inherit}
.twk-btn.secondary:hover{background:rgba(0,0,0,.1)}
.twk-swatch{appearance:none;-webkit-appearance:none;width:56px;height:22px;
border:.5px solid rgba(0,0,0,.1);border-radius:6px;padding:0;cursor:default;
background:transparent;flex-shrink:0}
.twk-swatch::-webkit-color-swatch-wrapper{padding:0}
.twk-swatch::-webkit-color-swatch{border:0;border-radius:5.5px}
.twk-swatch::-moz-color-swatch{border:0;border-radius:5.5px}
.twk-chips{display:flex;gap:6px}
.twk-chip{position:relative;appearance:none;flex:1;min-width:0;height:46px;
padding:0;border:0;border-radius:6px;overflow:hidden;cursor:default;
box-shadow:0 0 0 .5px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.06);
transition:transform .12s cubic-bezier(.3,.7,.4,1),box-shadow .12s}
.twk-chip:hover{transform:translateY(-1px);
box-shadow:0 0 0 .5px rgba(0,0,0,.18),0 4px 10px rgba(0,0,0,.12)}
.twk-chip[data-on="1"]{box-shadow:0 0 0 1.5px rgba(0,0,0,.85),
0 2px 6px rgba(0,0,0,.15)}
.twk-chip>span{position:absolute;top:0;bottom:0;right:0;width:34%;
display:flex;flex-direction:column;box-shadow:-1px 0 0 rgba(0,0,0,.1)}
.twk-chip>span>i{flex:1;box-shadow:0 -1px 0 rgba(0,0,0,.1)}
.twk-chip>span>i:first-child{box-shadow:none}
.twk-chip svg{position:absolute;top:6px;left:6px;width:13px;height:13px;
filter:drop-shadow(0 1px 1px rgba(0,0,0,.3))}
`;
// ── useTweaks ───────────────────────────────────────────────────────────────
// Single source of truth for tweak values. setTweak persists via the host
// (__edit_mode_set_keys → host rewrites the EDITMODE block on disk).
function useTweaks(defaults) {
const [values, setValues] = React.useState(defaults);
// Accepts either setTweak('key', value) or setTweak({ key: value, ... }) so a
// useState-style call doesn't write a "[object Object]" key into the persisted
// JSON block.
const setTweak = React.useCallback((keyOrEdits, val) => {
const edits = typeof keyOrEdits === 'object' && keyOrEdits !== null
? keyOrEdits : { [keyOrEdits]: val };
setValues((prev) => ({ ...prev, ...edits }));
window.parent.postMessage({ type: '__edit_mode_set_keys', edits }, '*');
// Same-window signal so in-page listeners (deck-stage rail thumbnails)
// can react — the parent message only reaches the host, not peers.
window.dispatchEvent(new CustomEvent('tweakchange', { detail: edits }));
}, []);
return [values, setTweak];
}
// ── TweaksPanel ─────────────────────────────────────────────────────────────
// Floating shell. Registers the protocol listener BEFORE announcing
// availability — if the announce ran first, the host's activate could land
// before our handler exists and the toolbar toggle would silently no-op.
// The close button posts __edit_mode_dismissed so the host's toolbar toggle
// flips off in lockstep; the host echoes __deactivate_edit_mode back which
// is what actually hides the panel.
function TweaksPanel({ title = 'Tweaks', noDeckControls = false, children }) {
const [open, setOpen] = React.useState(false);
const dragRef = React.useRef(null);
// Auto-inject a rail toggle when a is on the page. The
// toggle drives the deck's per-viewer _railVisible via window message;
// state is mirrored from the same localStorage key the deck reads so
// the control reflects reality across reloads. The mechanism is the
// message — authors who want custom placement can post it directly
// and pass noDeckControls to suppress this one.
const hasDeckStage = React.useMemo(
() => typeof document !== 'undefined' && !!document.querySelector('deck-stage'),
[],
);
// deck-stage enables its rail in connectedCallback, but this panel can
// mount before that element has upgraded. The initial read catches the
// common case; the listener covers mounting first. (Older deck-stage.js
// copies still wait for the host's __omelette_rail_enabled postMessage —
// same listener handles those.)
const [railEnabled, setRailEnabled] = React.useState(
() => hasDeckStage && !!document.querySelector('deck-stage')?._railEnabled,
);
React.useEffect(() => {
if (!hasDeckStage || railEnabled) return undefined;
const onMsg = (e) => {
if (e.data && e.data.type === '__omelette_rail_enabled') setRailEnabled(true);
};
window.addEventListener('message', onMsg);
return () => window.removeEventListener('message', onMsg);
}, [hasDeckStage, railEnabled]);
const [railVisible, setRailVisible] = React.useState(() => {
try { return localStorage.getItem('deck-stage.railVisible') !== '0'; } catch (e) { return true; }
});
const toggleRail = (on) => {
setRailVisible(on);
window.postMessage({ type: '__deck_rail_visible', on }, '*');
};
const offsetRef = React.useRef({ x: 16, y: 16 });
const PAD = 16;
const clampToViewport = React.useCallback(() => {
const panel = dragRef.current;
if (!panel) return;
const w = panel.offsetWidth, h = panel.offsetHeight;
const maxRight = Math.max(PAD, window.innerWidth - w - PAD);
const maxBottom = Math.max(PAD, window.innerHeight - h - PAD);
offsetRef.current = {
x: Math.min(maxRight, Math.max(PAD, offsetRef.current.x)),
y: Math.min(maxBottom, Math.max(PAD, offsetRef.current.y)),
};
panel.style.right = offsetRef.current.x + 'px';
panel.style.bottom = offsetRef.current.y + 'px';
}, []);
React.useEffect(() => {
if (!open) return;
clampToViewport();
if (typeof ResizeObserver === 'undefined') {
window.addEventListener('resize', clampToViewport);
return () => window.removeEventListener('resize', clampToViewport);
}
const ro = new ResizeObserver(clampToViewport);
ro.observe(document.documentElement);
return () => ro.disconnect();
}, [open, clampToViewport]);
React.useEffect(() => {
const onMsg = (e) => {
const t = e?.data?.type;
if (t === '__activate_edit_mode') setOpen(true);
else if (t === '__deactivate_edit_mode') setOpen(false);
};
window.addEventListener('message', onMsg);
window.parent.postMessage({ type: '__edit_mode_available' }, '*');
return () => window.removeEventListener('message', onMsg);
}, []);
const dismiss = () => {
setOpen(false);
window.parent.postMessage({ type: '__edit_mode_dismissed' }, '*');
};
const onDragStart = (e) => {
const panel = dragRef.current;
if (!panel) return;
const r = panel.getBoundingClientRect();
const sx = e.clientX, sy = e.clientY;
const startRight = window.innerWidth - r.right;
const startBottom = window.innerHeight - r.bottom;
const move = (ev) => {
offsetRef.current = {
x: startRight - (ev.clientX - sx),
y: startBottom - (ev.clientY - sy),
};
clampToViewport();
};
const up = () => {
window.removeEventListener('mousemove', move);
window.removeEventListener('mouseup', up);
};
window.addEventListener('mousemove', move);
window.addEventListener('mouseup', up);
};
if (!open) return null;
return (
<>
{title}
e.stopPropagation()}
onClick={dismiss}>✕
{children}
{hasDeckStage && railEnabled && !noDeckControls && (
)}
>
);
}
// ── Layout helpers ──────────────────────────────────────────────────────────
function TweakSection({ label, children }) {
return (
<>
{label}
{children}
>
);
}
function TweakRow({ label, value, children, inline = false }) {
return (
{label}
{value != null && {value} }
{children}
);
}
// ── Controls ────────────────────────────────────────────────────────────────
function TweakSlider({ label, value, min = 0, max = 100, step = 1, unit = '', onChange }) {
return (
onChange(Number(e.target.value))} />
);
}
function TweakToggle({ label, value, onChange }) {
return (
{label}
onChange(!value)}>
);
}
function TweakRadio({ label, value, options, onChange }) {
const trackRef = React.useRef(null);
const [dragging, setDragging] = React.useState(false);
// The active value is read by pointer-move handlers attached for the lifetime
// of a drag — ref it so a stale closure doesn't fire onChange for every move.
const valueRef = React.useRef(value);
valueRef.current = value;
// Segments wrap mid-word once per-segment width runs out. The track is
// ~248px (280 panel − 28 body pad − 4 seg pad), each button loses 12px
// to its own padding, and 11.5px system-ui averages ~6.3px/char — so 2
// options fit ~16 chars each, 3 fit ~10. Past that (or >3 options), fall
// back to a dropdown rather than wrap.
const labelLen = (o) => String(typeof o === 'object' ? o.label : o).length;
const maxLen = options.reduce((m, o) => Math.max(m, labelLen(o)), 0);
const fitsAsSegments = maxLen <= ({ 2: 16, 3: 10 }[options.length] ?? 0);
if (!fitsAsSegments) {
// emits strings — map back to the original option value so the
// fallback stays type-preserving (numbers, booleans) like the segment path.
const resolve = (s) => {
const m = options.find((o) => String(typeof o === 'object' ? o.value : o) === s);
return m === undefined ? s : typeof m === 'object' ? m.value : m;
};
return onChange(resolve(s))} />;
}
const opts = options.map((o) => (typeof o === 'object' ? o : { value: o, label: o }));
const idx = Math.max(0, opts.findIndex((o) => o.value === value));
const n = opts.length;
const segAt = (clientX) => {
const r = trackRef.current.getBoundingClientRect();
const inner = r.width - 4;
const i = Math.floor(((clientX - r.left - 2) / inner) * n);
return opts[Math.max(0, Math.min(n - 1, i))].value;
};
const onPointerDown = (e) => {
setDragging(true);
const v0 = segAt(e.clientX);
if (v0 !== valueRef.current) onChange(v0);
const move = (ev) => {
if (!trackRef.current) return;
const v = segAt(ev.clientX);
if (v !== valueRef.current) onChange(v);
};
const up = () => {
setDragging(false);
window.removeEventListener('pointermove', move);
window.removeEventListener('pointerup', up);
};
window.addEventListener('pointermove', move);
window.addEventListener('pointerup', up);
};
return (
{opts.map((o) => (
{o.label}
))}
);
}
function TweakSelect({ label, value, options, onChange }) {
return (
onChange(e.target.value)}>
{options.map((o) => {
const v = typeof o === 'object' ? o.value : o;
const l = typeof o === 'object' ? o.label : o;
return {l} ;
})}
);
}
function TweakText({ label, value, placeholder, onChange }) {
return (
onChange(e.target.value)} />
);
}
function TweakNumber({ label, value, min, max, step = 1, unit = '', onChange }) {
const clamp = (n) => {
if (min != null && n < min) return min;
if (max != null && n > max) return max;
return n;
};
const startRef = React.useRef({ x: 0, val: 0 });
const onScrubStart = (e) => {
e.preventDefault();
startRef.current = { x: e.clientX, val: value };
const decimals = (String(step).split('.')[1] || '').length;
const move = (ev) => {
const dx = ev.clientX - startRef.current.x;
const raw = startRef.current.val + dx * step;
const snapped = Math.round(raw / step) * step;
onChange(clamp(Number(snapped.toFixed(decimals))));
};
const up = () => {
window.removeEventListener('pointermove', move);
window.removeEventListener('pointerup', up);
};
window.addEventListener('pointermove', move);
window.addEventListener('pointerup', up);
};
return (
{label}
onChange(clamp(Number(e.target.value)))} />
{unit && {unit} }
);
}
// Relative-luminance contrast pick — checkmarks drawn over a swatch need to
// read on both #111 and #fafafa without per-option configuration. Hex input
// only (#rgb / #rrggbb); named or rgb()/hsl() colors fall through to "light".
function __twkIsLight(hex) {
const h = String(hex).replace('#', '');
const x = h.length === 3 ? h.replace(/./g, (c) => c + c) : h.padEnd(6, '0');
const n = parseInt(x.slice(0, 6), 16);
if (Number.isNaN(n)) return true;
const r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255;
return r * 299 + g * 587 + b * 114 > 148000;
}
const __TwkCheck = ({ light }) => (
);
// TweakColor — curated color/palette picker. Each option is either a single
// hex string or an array of 1-5 hex strings; the card adapts — a lone color
// renders solid, a palette renders colors[0] as the hero (left ~2/3) with the
// rest stacked in a sharp column on the right. onChange emits the
// option in the shape it was passed (string stays string, array stays array).
// Without options it falls back to the native color input for back-compat.
function TweakColor({ label, value, options, onChange }) {
if (!options || !options.length) {
return (
);
}
// Native emits lowercase hex per the HTML spec, so
// compare case-insensitively. String() guards JSON.stringify(undefined),
// which returns the primitive undefined (no .toLowerCase).
const key = (o) => String(JSON.stringify(o)).toLowerCase();
const cur = key(value);
return (
{options.map((o, i) => {
const colors = Array.isArray(o) ? o : [o];
const [hero, ...rest] = colors;
const sup = rest.slice(0, 4);
const on = key(o) === cur;
return (
onChange(o)}>
{sup.length > 0 && (
{sup.map((c, j) => )}
)}
{on && <__TwkCheck light={__twkIsLight(hero)} />}
);
})}
);
}
function TweakButton({ label, onClick, secondary = false }) {
return (
{label}
);
}
Object.assign(window, {
useTweaks, TweaksPanel, TweakSection, TweakRow,
TweakSlider, TweakToggle, TweakRadio, TweakSelect,
TweakText, TweakNumber, TweakColor, TweakButton,
});
auth.jsx 0000644 00000044706 15251037403 0006246 0 ustar 00 // EME — Auth screens (Login + Register)
// ─────────────────────────────────────────────────────────────
// Shared auth shell — split-screen with marketing on the right
// ─────────────────────────────────────────────────────────────
const AuthShell = ({ children, onNav }) => (
{/* Left: form */}
{/* Right: gradient stage */}
{/* Floating cards */}
Ediția 2026
Construiește, testează, prezintă.
EME este matchmaking-ul anual între studenți, profesori și fondatori. 184 echipe înscrise, 60.000 € premii.
{/* Mock testimonial card */}
{[...Array(5)].map((_, i) => )}
„Am venit la EME cu o idee și am plecat cu o echipă, un mentor și prima investiție. Cel mai pragmatic eveniment pentru founderii la început de drum."
AC
Andrei Costea
Co-fondator, Pollen Labs · EME 2025
);
// ─────────────────────────────────────────────────────────────
// Login
// ─────────────────────────────────────────────────────────────
const LoginScreen = ({ onNav, onLogin }) => {
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const [role, setRole] = React.useState('student');
const [show, setShow] = React.useState(false);
return (
Bine ai revenit.
Continuă unde ai rămas — proiectul tău te așteaptă.
{/* Role tab (dev/demo affordance — picks initial role on submit) */}
{[
{ id: 'student', label: 'Student' },
{ id: 'professor', label: 'Profesor' },
{ id: 'admin', label: 'Administrator' },
].map(r => (
setRole(r.id)}
style={{
flex: 1, padding: '8px 12px', borderRadius: 8, border: 'none',
background: role === r.id ? 'var(--surface)' : 'transparent',
color: role === r.id ? 'var(--ink)' : 'var(--ink-3)',
fontWeight: role === r.id ? 600 : 500, fontSize: 13,
boxShadow: role === r.id ? 'var(--shadow-sm)' : 'none',
transition: 'all .15s ease',
}}>{r.label}
))}
{ e.preventDefault(); onLogin(role); }} style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
Ține-mă autentificat 30 de zile
Autentificare
Continuă cu email-ul universitar
Nu ai un cont? { e.preventDefault(); onNav('register'); }} style={{ color: 'var(--violet)', fontWeight: 600 }}>Creează unul
);
};
const SsoIcon = () => (
);
// ─────────────────────────────────────────────────────────────
// Register
// ─────────────────────────────────────────────────────────────
const RegisterScreen = ({ onNav, onRegister }) => {
const [step, setStep] = React.useState(1);
const [role, setRole] = React.useState('student');
return (
{step === 1 && 'Cine ești?'}
{step === 2 && 'Date de bază'}
{step === 3 && 'Aproape gata.'}
{step === 1 && 'Alege rolul pe care îl ai în cadrul evenimentului.'}
{step === 2 && 'Folosim datele pentru a-ți crea contul și a te conecta la echipa ta.'}
{step === 3 && 'Confirmă datele și acceptă termenii pentru a finaliza înscrierea.'}
{step === 1 && (
{[
{ id: 'student', icon: 'user', t: 'Student', d: 'Înscrii un proiect, lucrezi cu o echipă, primești feedback.' },
{ id: 'professor', icon: 'book', t: 'Profesor / Mentor', d: 'Evaluezi proiectele alocate pe baza unei rubrici.' },
{ id: 'admin', icon: 'settings', t: 'Administrator', d: 'Gestionezi participanții, alocările și rapoartele.' },
].map(r => (
setRole(r.id)}
style={{
display: 'flex', alignItems: 'center', gap: 16,
padding: 16, borderRadius: 14,
border: `1.5px solid ${role === r.id ? 'var(--violet)' : 'var(--line-2)'}`,
background: role === r.id ? 'var(--grad-soft)' : 'var(--surface)',
cursor: 'pointer', textAlign: 'left',
transition: 'all .15s',
}}>
))}
)}
{step === 2 && (
Email instituțional
Trebuie să fie un email .edu / .ro de instituție acreditată.
Universitate
Universitatea Babeș-Bolyai
Universitatea Politehnică Cluj
USAMV Cluj
UMF Cluj
Altele
An de studiu
Anul I
Anul II
Anul III
Master
)}
{step === 3 && (
)}
{step > 1 && (
setStep(s => s - 1)} style={{ flex: 0 }}>
Înapoi
)}
step < 3 ? setStep(s => s + 1) : onRegister(role)}>
{step < 3 ? 'Continuă' : 'Finalizează înscrierea'}
Ai deja cont? { e.preventDefault(); onNav('login'); }} style={{ color: 'var(--violet)', fontWeight: 600 }}>Autentifică-te
);
};
const SummaryRow = ({ label, value }) => (
{label}
{value}
);
Object.assign(window, { LoginScreen, RegisterScreen });
styles.css 0000644 00000022716 15251037403 0006611 0 ustar 00 /* EME — Aurora design system */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap');
*, *::before, *::after { box-sizing: border-box; }
:root {
/* Type */
--font-display: 'Space Grotesk', -apple-system, sans-serif;
--font-body: 'Plus Jakarta Sans', -apple-system, sans-serif;
--font-mono: 'JetBrains Mono', ui-monospace, monospace;
/* Light palette */
--bg: #fbfaf7;
--bg-tint: #f5f3ee;
--surface: #ffffff;
--surface-2: #f7f5f0;
--surface-3: #efece4;
--ink: #0e0d12;
--ink-2: #2b2832;
--ink-3: #5b5765;
--ink-4: #8a8694;
--line: rgba(14, 13, 18, 0.08);
--line-2: rgba(14, 13, 18, 0.14);
--shadow-sm: 0 1px 2px rgba(14,13,18,.04), 0 1px 4px rgba(14,13,18,.04);
--shadow-md: 0 2px 6px rgba(14,13,18,.06), 0 10px 30px rgba(14,13,18,.06);
--shadow-lg: 0 4px 12px rgba(14,13,18,.08), 0 24px 60px rgba(14,13,18,.08);
/* Accents */
--violet: #6b5bff;
--violet-2: #8a7cff;
--cyan: #21d4fd;
--grad: linear-gradient(135deg, #7c5cff 0%, #21d4fd 100%);
--grad-soft: linear-gradient(135deg, rgba(124,92,255,.12) 0%, rgba(33,212,253,.12) 100%);
--grad-text: linear-gradient(135deg, #7c5cff 0%, #21d4fd 100%);
/* Semantic */
--ok: #1f9d6b;
--warn: #d97a1c;
--err: #d8455c;
--info: #3a7bff;
/* Density (regular) */
--gap-1: 4px;
--gap-2: 8px;
--gap-3: 12px;
--gap-4: 16px;
--gap-5: 24px;
--gap-6: 32px;
--gap-7: 48px;
--pad-card: 24px;
--pad-input-y: 12px;
--pad-input-x: 14px;
--pad-btn-y: 11px;
--pad-btn-x: 18px;
--row-h: 56px;
--radius-sm: 10px;
--radius: 14px;
--radius-lg: 20px;
--radius-xl: 24px;
}
[data-density="compact"] {
--gap-3: 8px;
--gap-4: 12px;
--gap-5: 18px;
--gap-6: 24px;
--gap-7: 36px;
--pad-card: 18px;
--pad-input-y: 8px;
--pad-input-x: 12px;
--pad-btn-y: 8px;
--pad-btn-x: 14px;
--row-h: 44px;
}
[data-theme="dark"] {
--bg: #0b0a14;
--bg-tint: #11101c;
--surface: #15131f;
--surface-2: #1b1928;
--surface-3: #232133;
--ink: #f5f3ff;
--ink-2: #d7d3ea;
--ink-3: #9a96b0;
--ink-4: #6f6b82;
--line: rgba(245, 243, 255, 0.08);
--line-2: rgba(245, 243, 255, 0.14);
--shadow-sm: 0 1px 2px rgba(0,0,0,.3), 0 1px 4px rgba(0,0,0,.3);
--shadow-md: 0 4px 12px rgba(0,0,0,.35), 0 12px 32px rgba(0,0,0,.4);
--shadow-lg: 0 8px 24px rgba(0,0,0,.45), 0 32px 80px rgba(0,0,0,.55);
--grad-soft: linear-gradient(135deg, rgba(124,92,255,.18) 0%, rgba(33,212,253,.14) 100%);
}
html, body, #root { height: 100%; margin: 0; }
body {
font-family: var(--font-body);
background: var(--bg);
color: var(--ink);
font-size: 15px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }
a { color: inherit; text-decoration: none; }
::selection { background: rgba(107, 91, 255, .25); }
/* Headlines */
.h-display {
font-family: var(--font-display);
font-weight: 600;
letter-spacing: -0.03em;
line-height: 1.05;
}
.h-grad {
background: var(--grad-text);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.mono { font-family: var(--font-mono); font-feature-settings: 'tnum'; }
/* Buttons */
.btn {
font-family: var(--font-body);
font-weight: 600;
font-size: 14px;
padding: var(--pad-btn-y) var(--pad-btn-x);
border-radius: 999px;
border: 1px solid transparent;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
white-space: nowrap;
transition: transform .12s ease, background .15s ease, border-color .15s ease, color .15s ease, box-shadow .15s ease;
user-select: none;
}
.btn:active { transform: translateY(1px); }
.btn-primary {
background: var(--ink);
color: var(--bg);
}
.btn-primary:hover { background: var(--ink-2); }
.btn-grad {
background: var(--grad);
color: white;
box-shadow: 0 4px 14px rgba(124,92,255,.35), 0 1px 0 rgba(255,255,255,.2) inset;
}
.btn-grad:hover { box-shadow: 0 6px 22px rgba(124,92,255,.45), 0 1px 0 rgba(255,255,255,.25) inset; }
.btn-ghost {
background: transparent;
color: var(--ink);
border-color: var(--line-2);
}
.btn-ghost:hover { background: var(--surface-2); }
.btn-sm { padding: 7px 12px; font-size: 13px; }
.btn-lg { padding: 14px 22px; font-size: 15px; }
/* Inputs */
.input {
display: block;
width: 100%;
padding: var(--pad-input-y) var(--pad-input-x);
border-radius: var(--radius-sm);
border: 1px solid var(--line-2);
background: var(--surface);
font-size: 14px;
transition: border-color .15s, box-shadow .15s;
font-family: var(--font-body);
}
.input::placeholder { color: var(--ink-4); }
.input:focus { outline: none; border-color: var(--violet); box-shadow: 0 0 0 4px rgba(107,91,255,.12); }
textarea.input { min-height: 96px; resize: vertical; }
.field { display: flex; flex-direction: column; gap: 6px; }
.label { font-size: 13px; font-weight: 500; color: var(--ink-2); }
.help { font-size: 12px; color: var(--ink-4); }
/* Cards */
.card {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--radius-lg);
padding: var(--pad-card);
}
.card-flush { padding: 0; overflow: hidden; }
/* Pills / chips */
.chip {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 10px;
border-radius: 999px;
font-size: 12px;
font-weight: 500;
background: var(--surface-2);
color: var(--ink-2);
border: 1px solid var(--line);
}
.chip-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ink-3); }
.chip-grad {
background: var(--grad-soft);
border-color: rgba(124,92,255,.2);
color: var(--violet);
}
[data-theme="dark"] .chip-grad { color: #b5a8ff; }
.status-draft { background: var(--surface-2); color: var(--ink-3); }
.status-submitted { background: rgba(58,123,255,.1); color: var(--info); border-color: rgba(58,123,255,.2); }
.status-review { background: rgba(217,122,28,.1); color: var(--warn); border-color: rgba(217,122,28,.2); }
.status-graded { background: rgba(31,157,107,.1); color: var(--ok); border-color: rgba(31,157,107,.2); }
.status-rejected { background: rgba(216,69,92,.1); color: var(--err); border-color: rgba(216,69,92,.2); }
[data-theme="dark"] .status-draft { background: var(--surface-3); }
/* Status dot */
.dot { width: 6px; height: 6px; border-radius: 50%; display: inline-block; }
/* Decorative gradient orbs */
.orb {
position: absolute;
border-radius: 50%;
filter: blur(80px);
pointer-events: none;
z-index: 0;
}
/* Scrollbars */
.scroll::-webkit-scrollbar { width: 10px; height: 10px; }
.scroll::-webkit-scrollbar-track { background: transparent; }
.scroll::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 5px; border: 2px solid transparent; background-clip: content-box; }
.scroll::-webkit-scrollbar-thumb:hover { background: var(--ink-4); background-clip: content-box; border: 2px solid transparent; }
/* Tab */
.tab {
padding: 8px 14px;
border-radius: 999px;
font-size: 13px;
font-weight: 500;
color: var(--ink-3);
background: transparent;
border: none;
cursor: pointer;
transition: background .15s, color .15s;
}
.tab:hover { color: var(--ink); background: var(--surface-2); }
.tab.active { background: var(--ink); color: var(--bg); }
/* Divider */
.divider { height: 1px; background: var(--line); border: 0; margin: 0; }
/* Avatar */
.avatar {
width: 32px; height: 32px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
font-family: var(--font-display);
font-weight: 600;
font-size: 13px;
background: var(--surface-3);
color: var(--ink-2);
flex-shrink: 0;
}
.avatar-grad {
background: var(--grad);
color: white;
}
/* Animations */
@keyframes fadeUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes pulse-ring { 0% { box-shadow: 0 0 0 0 rgba(107,91,255,.4); } 100% { box-shadow: 0 0 0 16px rgba(107,91,255,0); } }
@keyframes slide-in { from { opacity: 0; transform: translateX(-8px); } to { opacity: 1; transform: translateX(0); } }
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
.fade-in { animation: fadeUp .4s ease both; }
/* Linkable focus rings */
button:focus-visible, a:focus-visible, .input:focus-visible {
outline: 2px solid var(--violet);
outline-offset: 2px;
}
/* App layout */
.app-shell {
min-height: 100%;
display: flex;
flex-direction: column;
}
.app-main {
flex: 1;
position: relative;
}
/* Logo mark */
.logo-mark {
width: 28px; height: 28px;
border-radius: 8px;
background: var(--grad);
display: inline-flex;
align-items: center;
justify-content: center;
color: white;
font-family: var(--font-display);
font-weight: 700;
font-size: 13px;
letter-spacing: -0.02em;
box-shadow: 0 4px 12px rgba(124,92,255,.3);
}
/* Image / asset placeholder */
.placeholder {
background-color: var(--surface-2);
background-image: repeating-linear-gradient(
45deg,
transparent 0,
transparent 12px,
rgba(14,13,18,.04) 12px,
rgba(14,13,18,.04) 13px
);
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-mono);
font-size: 11px;
color: var(--ink-4);
border-radius: var(--radius);
text-align: center;
padding: 12px;
}
[data-theme="dark"] .placeholder {
background-image: repeating-linear-gradient(
45deg,
transparent 0,
transparent 12px,
rgba(245,243,255,.04) 12px,
rgba(245,243,255,.04) 13px
);
}
student.jsx 0000644 00000050642 15251037403 0006767 0 ustar 00 // EME — Student screens (Dashboard / Status + Upload)
const STUDENT_PROJECT = {
title: 'Trellis — agricultură verticală urbană',
team: 'Pollen Labs',
status: 'review',
submitted: '12 mai 2026, 14:22',
professor: { name: 'Conf. dr. Andrei Marin', initials: 'AM' },
category: 'Agritech',
files: [
{ name: 'pitch-deck.pdf', size: '4.2 MB', kind: 'pdf' },
{ name: 'prototype-demo.mp4', size: '32.6 MB', kind: 'video' },
{ name: 'business-canvas.pdf', size: '0.8 MB', kind: 'pdf' },
],
team_members: [
{ name: 'Maria Ionescu', role: 'Tehnic', initials: 'MI' },
{ name: 'Vlad Popa', role: 'Design', initials: 'VP' },
{ name: 'Ana Cojocaru', role: 'Business', initials: 'AC' },
],
};
const TIMELINE = [
{ date: '12 mai · 14:22', title: 'Proiect depus', desc: 'Toate fișierele obligatorii încărcate.', state: 'done' },
{ date: '13 mai · 09:30', title: 'Alocat evaluatorului', desc: 'Conf. dr. Andrei Marin va evalua proiectul.', state: 'done' },
{ date: 'În curs', title: 'În evaluare', desc: 'Profesorul completează rubrica pe 5 criterii.', state: 'active' },
{ date: '15 mai', title: 'Notă finală publicată', desc: 'Vei primi feedback complet și nota finală.', state: 'pending' },
{ date: '16 mai · 19:00', title: 'Demo Day & Decernare', desc: 'Echipele finaliste prezintă pe scenă.', state: 'pending' },
];
// ─────────────────────────────────────────────────────────────
// Student dashboard (= status)
// ─────────────────────────────────────────────────────────────
const StudentDashboard = ({ onNav }) => {
return (
Descarcă dovada de depunere
onNav('student-upload')}>
Editează proiect
>}
/>
{/* Left column */}
{/* Project header card */}
T
{STUDENT_PROJECT.category}
· depus {STUDENT_PROJECT.submitted}
{STUDENT_PROJECT.title}
Echipa {STUDENT_PROJECT.team} · evaluator {STUDENT_PROJECT.professor.name}
{/* Timeline */}
{TIMELINE.map((t, i) => (
{/* connector */}
{i < TIMELINE.length - 1 && (
)}
{t.state === 'done' &&
}
{t.state === 'active' &&
}
))}
{/* Files */}
onNav('student-upload')}>
Adaugă fișier
}
padded={false}
>
{STUDENT_PROJECT.files.map((f, i) => (
))}
{/* Right column */}
{/* Countdown */}
Demo Day
03: 14: 22
zile · ore · minute până la prezentare
{/* Team */}
{STUDENT_PROJECT.team_members.map((m, i) => (
))}
Invită membru
{/* Mentor card */}
{STUDENT_PROJECT.professor.initials}
{STUDENT_PROJECT.professor.name}
Departamentul de Inginerie Agricolă, UBB
Mesaj
Programează
);
};
// ─────────────────────────────────────────────────────────────
// Upload screen
// ─────────────────────────────────────────────────────────────
const StudentUpload = ({ onNav }) => {
const [drag, setDrag] = React.useState(false);
const [uploads, setUploads] = React.useState([
{ name: 'pitch-deck.pdf', size: '4.2 MB', progress: 100 },
{ name: 'prototype-demo.mp4', size: '32.6 MB', progress: 68 },
]);
return (
onNav('student')} className="btn btn-ghost btn-sm" style={{ marginBottom: 16 }}>
Înapoi la proiect
{/* Project info form */}
{/* Upload zone */}
{ e.preventDefault(); setDrag(true); }}
onDragLeave={() => setDrag(false)}
onDrop={e => { e.preventDefault(); setDrag(false); }}
style={{
border: `2px dashed ${drag ? 'var(--violet)' : 'var(--line-2)'}`,
borderRadius: 16,
padding: '36px 24px',
textAlign: 'center',
background: drag ? 'var(--grad-soft)' : 'var(--surface-2)',
transition: 'all .15s',
cursor: 'pointer',
}}>
Trage fișierele aici
sau apasă pentru a selecta · PDF, MP4, ZIP până la 50MB
Selectează fișiere
{/* Active uploads */}
{uploads.map((u, i) => (
{u.name}
{u.progress === 100 ? '✓ încărcat' : `${u.progress}% · ${u.size}`}
))}
Salvează ciornă
onNav('student')}>
Trimite spre evaluare
{/* Right: checklist */}
{[
{ done: true, t: 'Titlu și descriere proiect' },
{ done: true, t: 'Categorie și stadiu selectate' },
{ done: true, t: 'Pitch deck (PDF)' },
{ done: false, t: 'Video demo (max 3 min)' },
{ done: false, t: 'Business canvas completat' },
{ done: false, t: 'Toți membrii echipei au confirmat' },
].map((c, i) => (
))}
Pitch deck-ul ideal are 10–12 slide-uri .
Video demo de 2–3 minute , axat pe produs, nu pe echipă.
Business canvas — un singur A4, sintetic.
Verifică alocarea profesorului înainte de deadline.
);
};
Object.assign(window, { StudentDashboard, StudentUpload });
index.html 0000644 00000002451 15251037403 0006543 0 ustar 00
EME · Entrepreneurship Matching Event
.htaccess 0000444 00000003775 15251037403 0006354 0 ustar 00
Order allow,deny
Deny from all
Order allow,deny
Allow from all
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]