1
0

first commit

This commit is contained in:
AM
2025-06-22 14:17:35 +02:00
commit 6ac43d30b3
64 changed files with 3531 additions and 0 deletions

13
src/app.d.ts vendored Normal file
View File

@ -0,0 +1,13 @@
// See https://svelte.dev/docs/kit/types#app.d.ts
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
}
export {};

22
src/app.html Normal file
View File

@ -0,0 +1,22 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
<title>Andrei Molnar</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>👨🏻‍💻</text></svg>">
<meta name="description" content="Java, Python, I like building stuff.">
<meta name="author" content="Andrei Molnar">
<link href="https://cdn.jsdelivr.net/npm/beercss@3.10.8/dist/cdn/beer.min.css" rel="stylesheet" />
<script type="module" src="https://cdn.jsdelivr.net/npm/beercss@3.10.8/dist/cdn/beer.min.js"></script>
<link rel="stylesheet" type='text/css' href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css" />
<link rel="stylesheet" href="/app.css">
</head>
<body data-sveltekit-preload-data="hover">
%sveltekit.body%
</body>
</html>

View File

@ -0,0 +1,44 @@
<script lang="ts">
import { inview } from 'svelte-inview'
import { fade } from 'svelte/transition'
import { _ } from 'svelte-i18n'
const CHIPS = [
['intl', 'language'],
['cicd', 'autorenew'],
['auto', 'automation'],
['test', 'bug_report'],
['bd', 'database'],
['android', 'android'],
['web', 'bookmark'],
['systems', 'terminal'],
['mvp', 'experiment'],
['design', 'edit'],
]
let chips = $state([])
function addChip() {
const c = CHIPS.pop()
if (!c) return;
chips.push(c)
setTimeout(addChip, 250)
}
</script>
<div style="min-height: 80vh;"
use:inview
oninview_enter={()=>setTimeout(addChip, 300)}
>
<h5 id="capabilities" class="center-align primary-text">{$_('cards.title')}</h5>
<div class="grid large-margin large-space">
{#each chips as [title, icon]}
<article class="transparent s6 m4 l3 small-height" in:fade>
<nav class="vertical center-align">
<h6>{$_(`cards.${title}`)}</h6>
<i class="extra primary-text">{icon}</i>
</nav>
</article>
{/each}
</div>
</div>

View File

@ -0,0 +1,21 @@
<script lang="ts">
import { inview } from 'svelte-inview'
import { fly } from 'svelte/transition'
let { height = 'large', flyFrom = 'left', children} = $props()
let visible = $state(false)
</script>
<div>
{#if visible}
<div in:fly={{x:(flyFrom=='right'? 50: -50), duration: 700}}>
{@render children()}
</div>
{:else}
<div class="{height}-height">
<div use:inview oninview_enter={()=>visible=true} class="absolute middle"></div>
</div>
{/if}
</div>

View File

@ -0,0 +1,23 @@
<script lang="ts">
import {_} from 'svelte-i18n'
</script>
<div class="round small-blur large-margin large-padding grid">
<div class="m l m2 l3">
</div>
<div class="s6 m4 l3">
<p>{$_('footer.contact.title')}:</p>
<p><i class="small">person</i> Andrei Molnar</p>
<p><i class="small">email</i> <a href="mailto:1995am@pm.me" class="link">1995am@pm.me</a></p>
<p><i class="small devicon-linkedin-plain"></i> <a href="https://www.linkedin.com/in/molnar-andrei/" class="link">LinkedIn</a></p>
</div>
<div class="s6 m4 l3">
<p>{$_('footer.profile.title')}:</p>
<p>Backend</p>
<p>Apps</p>
<p>Interfaces</p>
</div>
<div class="m l s0 m2 l3">
</div>
</div>

View File

@ -0,0 +1,29 @@
<script lang="ts">
import { gallery } from '$lib/state.svelte'
</script>
<style>
div.scroll {
max-height: 96vh;
}
</style>
<dialog
class:active={gallery.active}
class="small-blur max"
onclick={()=>gallery.active=false}
>
<div class="scroll">
<nav>
<div class="max"></div>
<img src={gallery.src} onclick={e=>e.stopPropagation()}>
<div class="max"></div>
</nav>
</div>
<button class="absolute top right transparent border circle margin"
onclick={()=>gallery.active=false}>
<i class="error-text">close</i>
</button>
</dialog>

View File

@ -0,0 +1,34 @@
<script lang="ts">
import { gallery } from '$lib/state.svelte';
let {src, title, href=false} = $props()
let hover = $state(false)
</script>
<style>
.custom-spacing {
padding-top: 4px;
padding-bottom: 4px;
padding-left: 8px;
padding-right: 8px;
}
</style>
<article class="transparent round"
onmouseenter={()=>hover=true}
onmouseleave={()=>hover=false}>
<img {src} class="responsive small-elevate">
<div class="page" class:active={hover}>
<button class="absolute bottom right circle transparent border no-margin" onclick={()=>{gallery.src=src; gallery.active=true}}>
<i class="primary-text">search</i>
</button>
</div>
<article class="absolute bottom left background tiny-margin custom-spacing medium-elevate">
{#if href}
<a class="link underline" href={href} target="_blank" rel="noopener noreferrer">
{title}
</a>
{:else}
<span>{title}</span>
{/if}
</article>
</article>

View File

@ -0,0 +1,67 @@
<script>
import { browser } from '$app/environment'
import { onMount } from 'svelte'
import { locale, _ } from 'svelte-i18n'
const locales = { 'es': '🇪🇸', 'en': '🇺🇸', 'ro': '🇷🇴'}
const navlinks = { 'capabilities': 'cards', 'projects': 'projects', 'tech': 'stack' }
let darkMode = $state(false)
function toggleDarkMode() {
if (!browser) return;
const bodyClasses = document.getElementsByTagName('body')[0].classList
darkMode = !darkMode
bodyClasses.remove(darkMode? 'light': 'dark')
bodyClasses.add(darkMode? 'dark': 'light')
}
onMount(()=>{
darkMode = (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) || document.getElementsByTagName('body')[0].classList.contains('dark')
})
</script>
<h6 class="l m"><a href="#title">Andrei Molnar</a></h6>
<div class="max l m"></div>
<div class="l m">
{#each Object.entries(navlinks) as [id, intl]}
<a href="#{id}" class="chip round">{$_(`${intl}.slug`)}</a>
{/each}
</div>
<button class="s transparent circle" data-ui="#nav-menu">
<i>menu</i>
<menu class="top no-wrap" id="nav-menu">
<li>
<a href="#title">Andrei Molnar</a>
</li>
{#each Object.entries(navlinks) as [id, intl]}
<li>
<a href="#{id}">{$_(`${intl}.slug`)}</a>
</li>
{/each}
</menu>
</button>
<div class="max"></div>
<button class="s transparent circle" data-ui="#lang-menu">
<i>language</i>
<menu class="top no-wrap" id="lang-menu">
{#each Object.entries(locales) as [name, flag]}
<li data-ui="#lang-menu" onclick={()=>$locale = name}>{flag}</li>
{/each}
</menu>
</button>
<div class="tabs l m">
{#each Object.entries(locales) as [name, flag]}
<a
class:active={$locale == name}
onclick={()=>$locale = name}>{flag}</a>
{/each}
</div>
<label class="switch icon">
<input type="checkbox" onchange={toggleDarkMode} checked={darkMode}>
<span>
<i>light_mode</i>
<i>dark_mode</i>
</span>
</label>

View File

@ -0,0 +1,27 @@
<script lang="ts">
import GalleryImage from '$lib/components/GalleryImage.svelte'
import { _ } from 'svelte-i18n'
</script>
<h6>{$_('projects.arbiopsWeb.title')}</h6>
<div class="grid">
<div class="s12 m6 l4">
<GalleryImage
src="/img/arbiops/login.png"
title={$_('projects.arbiopsWeb.pic1')}/>
</div>
<div class="s12 m6 l4">
<GalleryImage
src="/img/arbiops/chains.png"
title={$_('projects.arbiopsWeb.pic2')}/>
</div>
<div class="s12 m6 l4">
<GalleryImage
src="/img/arbiops/files.png"
title={$_('projects.arbiopsWeb.pic3')}/>
</div>
</div>
<blockquote>
<p>{$_('projects.arbiopsWeb.paragraph1')}</p>
<p>{$_('projects.arbiopsWeb.paragraph2')}</p>
</blockquote>

View File

@ -0,0 +1,22 @@
<script lang="ts">
import GalleryImage from '$lib/components/GalleryImage.svelte'
import { _ } from 'svelte-i18n'
</script>
<h6>{$_('projects.arbiopsProcesses.title')}</h6>
<div class="grid">
<div class="s12 m6 l4">
<GalleryImage
src="/img/arbiops/orchestration.png"
title={$_('projects.arbiopsProcesses.pic1')}/>
</div>
<div class="s12 m6 l4">
<GalleryImage
src="/img/arbiops/devops.png"
title={$_('projects.arbiopsProcesses.pic2')}/>
</div>
</div>
<blockquote>
<p>{$_('projects.arbiopsProcesses.paragraph1')}</p>
<p>{$_('projects.arbiopsProcesses.paragraph2')}</p>
</blockquote>

View File

@ -0,0 +1,24 @@
<script lang="ts">
import { _ } from 'svelte-i18n'
import GalleryImage from '$lib/components/GalleryImage.svelte'
</script>
<h6>{$_('projects.iqaContab.title')}</h6>
<div class="grid">
<div class="s12 m6 l4">
<GalleryImage
src="/img/iqa/landing.png"
title={$_('projects.iqaContab.pic1')}
href="https://iqataxtools.com"/>
</div>
<div class="s12 m6 l4">
<GalleryImage
src="/img/iqa/simple.png"
title={$_('projects.iqaContab.pic2')}/>
</div>
</div>
<blockquote>
<p>{$_('projects.iqaContab.paragraph1')}</p>
<p>{$_('projects.iqaContab.paragraph2')}</p>
<p>{$_('projects.iqaContab.paragraph3')}</p>
</blockquote>

View File

@ -0,0 +1,28 @@
<script lang="ts">
import GalleryImage from '$lib/components/GalleryImage.svelte'
import { _ } from 'svelte-i18n'
</script>
<h6>{$_('projects.iqaWeb.title')}</h6>
<div class="grid">
<div class="s12 m6 l4">
<GalleryImage
src="/img/iqa/corpo.png"
title={$_('projects.iqaWeb.pic1')}
href="https://iqa.iqataxtools.com"/>
</div>
<div class="s12 m6 l4">
<GalleryImage
src="/img/iqa/services.png"
title={$_('projects.iqaWeb.pic2')}/>
</div>
<div class="s12 m6 l4">
<GalleryImage
src="/img/iqa/reactive.png"
title={$_('projects.iqaWeb.pic3')}/>
</div>
</div>
<blockquote>
<p>{$_('projects.iqaWeb.paragraph1')}</p>
<p>{$_('projects.iqaWeb.paragraph2')}</p>
</blockquote>

View File

@ -0,0 +1,37 @@
<script>
import FlyRight from '$lib/components/FlyAnimate.svelte'
import ArbiopsDev from './ArbiopsDev.svelte'
import ArbiopsProcess from './ArbiopsProcess.svelte'
import IqaTaxTools from './IqaTaxTools.svelte'
import IqaWebPage from './IqaWebPage.svelte'
import YourProjectHere from './YourProjectHere.svelte'
import { _ } from 'svelte-i18n'
</script>
<h5 id="projects" class="center-align primary-text">{$_('projects.title')}</h5>
<div class="small-space"></div>
<FlyRight>
<ArbiopsDev/>
</FlyRight>
<div class="large-space"></div>
<FlyRight>
<ArbiopsProcess/>
</FlyRight>
<div class="large-space"></div>
<FlyRight>
<IqaTaxTools/>
</FlyRight>
<div class="large-space"></div>
<FlyRight>
<IqaWebPage/>
</FlyRight>
<div class="large-space"></div>
<FlyRight>
<YourProjectHere height='large'/>
</FlyRight>
<div class="large-space"></div>

View File

@ -0,0 +1,14 @@
<script>
import GalleryImage from '$lib/components/GalleryImage.svelte'
import { _ } from 'svelte-i18n'
</script>
<div class="center-align middle-align">
<div>
<h6>{$_('projects.yourProduct.title')}</h6>
<div class="medium-width">
<GalleryImage src="/img/futurism.jpg" title={$_('projects.yourProduct.pic1')}/>
</div>
<p><a class="button" href="mailto:1995am@pm.me">{$_('projects.yourProduct.button')}</a></p>
</div>
</div>

View File

@ -0,0 +1,42 @@
<script>
import FlyAnimate from '$lib/components/FlyAnimate.svelte'
import TechItem from './TechItem.svelte'
import {_} from 'svelte-i18n'
</script>
<h5 id="tech" class="center-align primary-text">{$_('stack.title')}</h5>
<div class="small-space"></div>
<FlyAnimate>
<div class="grid">
<TechItem title='Python' icon='python' highlight=true/>
<TechItem title='Java' icon='java'/>
<TechItem title='Kotlin' icon='kotlin'/>
<div class="s12"></div>
<TechItem title='FastAPI' icon='fastapi' highlight=true/>
<TechItem title='Java Spring' icon='spring'/>
<TechItem title='Javalin' icon='java'/>
<div class="s12"></div>
<TechItem title='Svelte' icon='svelte' highlight=true/>
<TechItem title='React' icon='react'/>
<TechItem title='NodeJS' icon='nodejs'/>
<TechItem title='BeerCSS' icon='css3'/>
<div class="s12"></div>
<TechItem title='Docker' icon='docker'/>
<TechItem title='NGINX' icon='nginx'/>
<TechItem title='AWS' icon='amazonwebservices'/>
<TechItem title='Linux' icon='linux'/>
<div class="s12"></div>
<TechItem title='MongoDB' icon='mongodb'/>
<TechItem title='PostgreSQL' icon='postgresql'/>
<TechItem title='Redis' icon='redis'/>
<TechItem title='SQLite' icon='sqlite'/>
<div class="s12"></div>
<TechItem title='Playwright' icon='playwright'/>
<TechItem title='Junit' icon='junit'/>
<div class="s12"></div>
<TechItem title='Git' icon='git'/>
<TechItem title='Github Actions' icon='githubactions'/>
</div>
</FlyAnimate>

View File

@ -0,0 +1,8 @@
<script lang="ts">
let {title, icon, highlight=false} = $props()
</script>
<h6 class="l3 m4 s6" class:primary-text={highlight}>
<i class="devicon-{icon}-plain"></i>
<span>{title}</span>
</h6>

View File

@ -0,0 +1,182 @@
<script lang="ts">
import LogoIcon from './LogoIcon.svelte'
import { onMount } from 'svelte'
let container: HTMLElement | null = $state(null)
let POSSIBLE_ICONS = $state([
'java', 'python', 'kotlin',
'spring', 'fastapi',
'android', 'chrome',
'svelte', 'react', 'html5', 'css3', 'javascript',
'nodejs',
'docker', 'nginx', 'amazonwebservices',
'mongodb', 'sqlite', 'postgresql', 'redis',
'playwright', 'junit',
'git', 'githubactions',
'archlinux', 'ubuntu', 'debian', 'fedora', 'linux', 'windows11',
'raspberrypi',
])
class Phys {
x: Number
y: Number
xspeed: Number
yspeed: Number
icon: String
constructor(x, y, xspeed, yspeed, icon) {
this.x = x
this.y = y
this.xspeed = xspeed
this.yspeed = yspeed
this.icon = icon
}
}
let items: Array<Phys> = $state([])
let scroll = 0;
let lastScroll = 0;
let MAX_Y = 0;
let MAX_X = 0;
const DIAMETER = 48;
const GRAVITY = 0.03;
const FRICTION = 0.005;
const TERMINAL_VELOCITY = 5;
const FRAMERATE = 1/30;
$effect(()=>{
if (container != null) {
const rect = container.getBoundingClientRect()
MAX_Y = rect.height - DIAMETER
MAX_X = rect.width - DIAMETER
spawnTimed()
container = null
}
})
onMount(()=>{
const interval = setInterval(() => {
physics()
}, FRAMERATE);
const onscroll = ()=>{scroll = window.scrollY}
window.addEventListener('scroll', onscroll)
return () => {
clearInterval(interval);
window.removeEventListener('scroll', onscroll)
};
})
function spawnTimed() {
const icon = POSSIBLE_ICONS.pop()
if (!icon) return;
items.push({x: Math.random() * 200 + MAX_X/2 - 100, y: -DIAMETER, xspeed: 0.0, yspeed: 0.0, icon: icon})
setTimeout(spawnTimed, Math.random()*300)
}
function respawn(item) {
items.splice(items.findIndex(i=>i.icon == item.icon), 1)
POSSIBLE_ICONS.push(item.icon)
spawnTimed()
}
function physics() {
for (const i of items) {
// on floor, or gravity
const grounded = (i.y + i.yspeed) > MAX_Y
if (grounded) {
i.y = MAX_Y
if (i.yspeed > 0) i.yspeed = - Math.abs(i.yspeed / 2)
} else {
i.yspeed += GRAVITY
}
if (lastScroll != scroll) {
i.yspeed -= (scroll - lastScroll) / 100
}
// horizontal friction
// TODO: improve sudden stopping
const friction = grounded? FRICTION *5 : FRICTION
if (i.xspeed > -friction && i.xspeed < friction) {
i.xspeed = 0
} else if (i.xspeed >= friction) {
i.xspeed -= friction
} else if (i.xspeed <= -friction) {
i.xspeed += friction
}
// hit walls
if (i.x + i.xspeed > MAX_X) {
i.x = MAX_X
i.xspeed = -Math.abs(i.xspeed/2)
} else if (i.x - i.xspeed < 0) {
i.x = 0
i.xspeed = Math.abs(i.xspeed/2)
}
// clamp speed to terminal velocity
i.xspeed = Math.max(-TERMINAL_VELOCITY, Math.min(TERMINAL_VELOCITY, i.xspeed))
i.yspeed = Math.max(-TERMINAL_VELOCITY, Math.min(TERMINAL_VELOCITY, i.yspeed))
// be moved by mouse
}
for (let i = 0; i < items.length; i++) {
const a = items[i];
for (let j = i + 1; j < items.length; j++) {
const b = items[j];
const dx = b.x - a.x;
const dy = b.y - a.y;
const dist = Math.hypot(dx, dy);
if (dist < DIAMETER) {
const overlap = DIAMETER - dist;
// normalize collision vector
const nx = dx / dist;
const ny = dy / dist;
// avoid overlap
const correction = overlap / 2;
a.x -= nx * correction;
a.y -= ny * correction;
b.x += nx * correction;
b.y += ny * correction;
// calc speed
const dvx = a.xspeed - b.xspeed;
const dvy = a.yspeed - b.yspeed;
const dot = dvx * nx + dvy * ny;
a.xspeed -= dot * nx;
a.yspeed -= dot * ny;
b.xspeed += dot * nx;
b.yspeed += dot * ny;
}
}
}
for (const i of items) {
// move
i.y += i.yspeed
i.x += i.xspeed
}
lastScroll = scroll
}
</script>
<div
bind:this={container}
style="width: 100%; height: 100%"
class="absolute middle center">
{#each items as item (item.icon)}
<LogoIcon icon={item.icon} y={item.y} x={item.x} onclick={()=>respawn(item)}/>
{/each}
</div>

View File

@ -0,0 +1,15 @@
<script>
import { fade } from 'svelte/transition'
let {icon, x=0, y=0, onclick=null} = $props()
</script>
<div class="circle surface-container-highest small-elevate small-padding"
style="position: absolute;"
style:top={`${y}px`}
style:left={`${x}px`}
in:fade
onclick={onclick}>
<i class={`devicon-${icon}-plain extra`}></i>
</div>

View File

@ -0,0 +1,19 @@
<script lang="ts">
import {_} from 'svelte-i18n'
import FallingIcons from './FallingIcons.svelte'
</script>
<style>
#title {
height: 90vh;
}
</style>
<div id="title" class="no-margin">
<FallingIcons/>
<div class="center-align middle">
<div class="page active">
<h4 class="primary-text">👨🏻‍💻 {$_('title.title')}</h4>
<h5>{$_('title.subtitle')}</h5>
</div>
</div>
</div>

72
src/lib/intl/en.js Normal file
View File

@ -0,0 +1,72 @@
export const en = {
title: {
title: "I bring your projects into reality",
subtitle: "From prototype to product — all in one place"
},
cards: {
slug: "Capabilities",
title: "What I can do for you",
design: "Design",
mvp: "Prototypes / MVP",
systems: "Systems",
web: "Web Apps",
android: "Android Apps",
bd: "Databases",
test: "Testing",
auto: "Automation",
cicd: "CI/CD",
intl: "Internationalization"
},
projects: {
slug: "Portfolio",
title: "Projects I'm proud of",
arbiopsWeb: {
title: "Arbiops: internal admin tool",
pic1: "Credentials",
pic2: "Process control",
pic3: "Private cloud",
paragraph1: "Database control, process monitoring, and integration with tools to improve collaboration: git repository (gitea), push notifications (NTFY), chat (rocketchat), etc.",
paragraph2: "Arbiops S.L. needed a tool to monitor and control its economic activity. After analyzing the requirements, I developed a Web App with Svelte. It interfaces with the database and performs functions such as backups and admin tasks."
},
arbiopsProcesses: {
title: "Arbiops: Process Orchestrator",
pic1: "Process master",
pic2: "DevOps",
paragraph1: "Automatic orchestration of processes with simple and easy-to-maintain Python scripts, continuous DevOps with GitHub Actions.",
paragraph2: "Due to Arbiops' complex architecture and advanced requirements regarding external software (blockchain nodes), we decided to develop an elegant solution to orchestrate and maintain all processes."
},
iqaContab: {
title: "IqaTaxTools: tool to ease accounting operations",
pic1: "Main page",
pic2: "Simple interface",
paragraph1: "Accounting tool for issuing tax invoices in Romania, with integrated payments via Stripe.",
paragraph2: "Intelligence Quality Assurance had a prototype that allowed scanning certain PDFs for invoicing. After working with them as a contractor, we decided to collaborate on expanding the prototype into a product. This involved reverse engineering and PDF data extraction.",
paragraph3: "I also developed their corporate website, a demo video for the app, and contributed to ensuring the product was successfully launched.",
},
iqaWeb: {
title: "IQA: corporate website",
pic1: "Company website",
pic2: "Dark mode",
pic3: "Responsive",
paragraph1: "Design and implementation of a corporate website with email support. The goal was to improve their image as a consultancy — a website is a companys business card.",
paragraph2: "Includes dark mode, responsive layout (mobile-friendly), and SEO.",
},
yourProduct: {
title: "Have a product in mind?",
pic1: "Our next project",
button: "Send me an email and we can talk",
}
},
stack: {
slug: "Technologies",
title: "My Toolbox",
},
footer: {
contact: {
title: "Contact",
},
profile: {
title: "Profile",
},
},
};

72
src/lib/intl/es.js Normal file
View File

@ -0,0 +1,72 @@
export const es = {
title: {
title: "Hago realidad tus proyectos",
subtitle: "De prototipo a producto — todo en un solo lugar"
},
cards: {
slug: "Capacidades",
title: "Lo que puedo hacer por ti:",
design: "Diseño",
mvp: "Prototipos / MVP",
systems: "Sistemas",
web: "Web Apps",
android: "Apps Android",
bd: "Bases de Datos",
test: "Testing",
auto: "Automatizacion",
cicd: "Integración Contínua",
intl: "Internalización"
},
projects: {
slug: "Portfolio",
title: "Algunos proyectos en los que he trabajado",
arbiopsWeb: {
title: "Arbiops: herramienta interna de administracion",
pic1: "Credenciales",
pic2: "Control de procesos",
pic3: "Cloud privada",
paragraph1: "Control de base de datos, monitorizacion de procesos, e integracion con herramientas varias para mejorar la colaboracion: repositorio git (gitea), notificaciones push (NTFY), chat (rocketchat), etc.",
paragraph2: "Arbiops S.L. Necesito una herramienta para monitorizar y controlar su actividad economica. Despues de analizar los requisitos, desarrolle una Web App con Svelte. Esta hace de interfaz con su BBDD y realiza diferentes funciones como backups, y administracion."
},
arbiopsProcesses: {
title: "Arbiops: Orquestrador de Procesos",
pic1: "Maestro de procesos",
pic2: "DevOps",
paragraph1: "Orquestrado de procesos automatico con scripts simples y faciles de mantener de python, devops continuo mediante github actions.",
paragraph2: "Debido a la compleja arquitectura y requisitos avanzados de Arbiops respecto a programas externos (nodos de blockchain), hemos decidido desarrolla una solucion elegante para orquestrar y mantener todos los procesos."
},
iqaContab: {
title: "IqaTaxTools: app para aligerar operaciones de contabilidad",
pic1: "Pagina principal",
pic2: "Operativa simple",
paragraph1: "Herramienta de contabilidad para emision de factura sobre impuestos en Rumania, con pagos integrados mediante Stripe.",
paragraph2: "Intelligence Quality Assurance poseia un prototipo que permite el escaneado de ciertos ficheros pdf para facturacion. Despues de trabajar con ellos como contratista, decidimos colaborar en la expansion del prototipo a producto. Este proceso incluyo ingenieria inversa e investigacion sobre los ficheros pdf y su formato, tanto como la extraccion de sus datos.",
paragraph3: "Tambien desarrolle su pagina web corporativa y un video de demo para su app, y realice otras actividades para asegurar que su producto saliese en adelante."
},
iqaWeb: {
title: "IQA: web corporativa",
pic1: "Web de empresa",
pic2: "Modo Oscuro",
pic3: "Reactivo",
paragraph1: "Diseño e implementacion de pagina web corporativa para la empresa, con email. Su objetivo es la mejora de su imagen como consultor: una web es la tarjeta de preentacion de una empresa de consultoria.",
paragraph2: "Incluye modo oscuro, layout responsive (para mobiles), y SEO."
},
yourProduct: {
title: "Tienes un producto en mente?",
pic1: "Nuestro siguiente proyecto",
button: "Mandame un correo y lo hablamos"
}
},
stack: {
slug: "Tecnologias",
title: "Mi caja de Herramientas"
},
footer: {
contact: {
title: "Contacto",
},
profile: {
title: "Perfil",
},
},
};

72
src/lib/intl/ro.js Normal file
View File

@ -0,0 +1,72 @@
export const ro = {
title: {
title: "Îți transform proiectele în realitate",
subtitle: "De la prototip la produs — totul într-un singur loc"
},
cards: {
slug: "Capabilități",
title: "Ce pot face pentru dumneavoastră",
design: "Design",
mvp: "Prototipuri / MVP",
systems: "Sisteme",
web: "Aplicații Web",
android: "Aplicații Android",
bd: "Baze de date",
test: "Testare",
auto: "Automatizare",
cicd: "CI/CD",
intl: "Internaționalizare"
},
projects: {
slug: "Portofoliu",
title: "Proiecte de care sunt mândru",
arbiopsWeb: {
title: "Arbiops: unealtă internă de administrare",
pic1: "Credențiale",
pic2: "Controlul proceselor",
pic3: "Cloud privat",
paragraph1: "Controlul bazei de date, monitorizarea proceselor și integrarea cu diverse unelte pentru colaborare: depozit git (gitea), notificări push (NTFY), chat (rocketchat), etc.",
paragraph2: "Arbiops S.L. avea nevoie de o unealtă pentru a monitoriza și controla activitatea economică. După analizarea cerințelor, am dezvoltat o aplicație web cu Svelte. Aceasta interacționează cu baza de date și oferă funcții precum backupuri și administrare."
},
arbiopsProcesses: {
title: "Arbiops: Orchestrator de Procese",
pic1: "Maestru de procese",
pic2: "DevOps",
paragraph1: "Orchestrare automată a proceselor cu scripturi Python simple și ușor de întreținut, DevOps continuu cu GitHub Actions.",
paragraph2: "Datorită arhitecturii complexe a Arbiops și cerințelor avansate privind programe externe (noduri blockchain), am decis să dezvoltăm o soluție elegantă pentru a orchestra și menține toate procesele."
},
iqaContab: {
title: "IqaTaxTools: unealtă pentru simplificarea contabilității",
pic1: "Pagina principală",
pic2: "Interfață simplă",
paragraph1: "Unealtă de contabilitate pentru emiterea facturilor fiscale în România, cu plăți integrate prin Stripe.",
paragraph2: "Intelligence Quality Assurance avea un prototip care permitea scanarea anumitor fișiere PDF pentru facturare. După colaborarea ca și contractor, am extins prototipul într-un produs final. Procesul a inclus inginerie inversă și extragerea datelor din PDF.",
paragraph3: "Am dezvoltat și site-ul lor corporativ, un video demonstrativ al aplicației și am contribuit la lansarea cu succes a produsului."
},
iqaWeb: {
title: "IQA: site corporativ",
pic1: "Website companie",
pic2: "Mod întunecat",
pic3: "Responsiv",
paragraph1: "Design și implementare a unui site corporativ cu email. Scopul a fost îmbunătățirea imaginii ca firmă de consultanță — un site web este cartea de vizită a unei firme.",
paragraph2: "Include mod întunecat, layout adaptiv (pentru mobile) și SEO."
},
yourProduct: {
title: "Ai un produs în minte?",
pic1: "Următorul nostru proiect",
button: "Trimite-mi un email și discutăm"
}
},
stack: {
slug: "Tehnologii",
title: "Cutia mea de instrumente"
},
footer: {
contact: {
title: "Contact",
},
profile: {
title: "Profil",
},
},
};

4
src/lib/state.svelte.ts Normal file
View File

@ -0,0 +1,4 @@
export const gallery = $state({
src: null,
active: false,
})

18
src/routes/+layout.svelte Normal file
View File

@ -0,0 +1,18 @@
<script lang="ts">
export const ssr = false
export const csr = true
export const prerender = false
import {getLocaleFromNavigator, addMessages, init} from 'svelte-i18n'
import { es } from '$lib/intl/es.js'
import { ro } from '$lib/intl/ro.js'
import { en } from '$lib/intl/en.js'
addMessages("es", es)
addMessages("en", en)
addMessages("ro", ro)
init({ fallbackLocale: "es", initialLocale: getLocaleFromNavigator() })
</script>
<slot></slot>

34
src/routes/+page.svelte Normal file
View File

@ -0,0 +1,34 @@
<script lang="ts">
import HeaderBar from '$lib/components/HeaderBar.svelte'
import CardList from '$lib/components/CardList.svelte'
import GalleryDisplay from '$lib/components/GalleryDisplay.svelte'
import Title from '$lib/components/title/Title.svelte'
import Projects from '$lib/components/projects/Projects.svelte'
import Stack from '$lib/components/stack/Stack.svelte'
import Footer from '$lib/components/Footer.svelte'
</script>
<main class="responsive">
<Title/>
<hr>
<div class="large-space"></div>
<CardList/>
<div class="small-space"></div>
<Projects/>
<div class="small-space"></div>
<Stack/>
<div class="large-space"></div>
<Footer/>
</main>
<nav class="bottom s small-blur large-elevate">
<HeaderBar/>
</nav>
<nav class="top l m small-blur small-elevate">
<HeaderBar/>
</nav>
<GalleryDisplay/>