mirror of
https://github.com/adam-benyekkou/my_portfolio.git
synced 2026-01-15 20:20:09 +00:00
Added scrollbar and history page
This commit is contained in:
@@ -83,7 +83,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Collaboration Status -->
|
||||
<div class="bg-nier-mid border border-nier-border p-6 info-panel">
|
||||
<div class="bg-nier-mid border border-nier-border p-6 info-panel mb-8">
|
||||
<div class="font-terminal text-base font-medium text-nier-dark mb-3 uppercase tracking-wide info-panel-title">
|
||||
COLLABORATION STATUS
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
<section class="border-b-1 h-screen flex items-top justify-top checkered-bg p-6 relative">
|
||||
<section class="border-b-1 min-h-screen checkered-bg p-6 relative">
|
||||
<div class="flex flex-col min-h-full">
|
||||
<app-section-title title=" OPERATIVE HISTORY" />
|
||||
<div class="flex-1 mt-4 pb-6">
|
||||
<app-operative-history />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { SectionTitleComponent } from '../../components/section-title/section-title.component';
|
||||
import { OperativeHistoryComponent } from './operative-history/operative-history.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-experience',
|
||||
imports: [SectionTitleComponent],
|
||||
imports: [SectionTitleComponent, OperativeHistoryComponent],
|
||||
templateUrl: './experience.component.html',
|
||||
styleUrl: './experience.component.css',
|
||||
})
|
||||
|
||||
@@ -0,0 +1,555 @@
|
||||
/* Optimized Component Styles - Global theme variables already available */
|
||||
|
||||
:host {
|
||||
font-family: var(--font-noto-jp);
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 1.5;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* CSS Custom Properties for reusability */
|
||||
:host {
|
||||
--card-padding: 0.75rem;
|
||||
--card-gap: 0.75rem;
|
||||
--border-radius: 4px;
|
||||
--transition-smooth: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--shadow-hover: 0 8px 25px rgba(41, 41, 37, 0.15);
|
||||
--shadow-subtle: 0 4px 12px rgba(41, 41, 37, 0.1);
|
||||
}
|
||||
|
||||
/* Main Grid Layout */
|
||||
.operative-history-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 1rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: calc(100vh - 8rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Column Base Styles */
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--card-gap);
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
/* Sticky Column Titles */
|
||||
.column-title {
|
||||
font-family: var(--font-terminal);
|
||||
font-size: 1rem;
|
||||
color: var(--color-nier-accent);
|
||||
letter-spacing: 0.1em;
|
||||
text-align: center;
|
||||
margin-bottom: var(--card-gap);
|
||||
padding: 0.5rem;
|
||||
border-bottom: 1px solid var(--color-nier-border);
|
||||
flex-shrink: 0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: var(--color-nier-bg);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* Base Card Styles */
|
||||
.experience-card,
|
||||
.info-card {
|
||||
border: 2px solid var(--color-nier-border);
|
||||
background: var(--color-nier-bg);
|
||||
position: relative;
|
||||
transition: var(--transition-smooth);
|
||||
margin-bottom: var(--card-gap);
|
||||
flex-shrink: 0;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
/* Enhanced Card Hover Effects */
|
||||
.experience-card:hover,
|
||||
.info-card:hover {
|
||||
transform: translateY(-2px) scale(1.02);
|
||||
box-shadow: var(--shadow-hover);
|
||||
border-color: var(--color-nier-accent);
|
||||
}
|
||||
|
||||
.info-card:hover {
|
||||
transform: translateY(-1px) scale(1.01);
|
||||
box-shadow: var(--shadow-subtle);
|
||||
}
|
||||
|
||||
/* Optimized Card Overlay Effect */
|
||||
.experience-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(135deg, transparent 0%, rgba(41, 41, 37, 0.05) 100%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.experience-card:hover::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Active Training Highlight */
|
||||
.active-training {
|
||||
border-color: var(--color-nier-accent);
|
||||
}
|
||||
|
||||
/* Optimized Card Headers */
|
||||
.experience-header,
|
||||
.info-header {
|
||||
background: linear-gradient(135deg, var(--color-nier-dark) 0%, var(--color-nier-highlight) 100%);
|
||||
color: var(--color-nier-text-light);
|
||||
padding: var(--card-padding);
|
||||
border-bottom: 2px solid var(--color-nier-border);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.info-header {
|
||||
padding: 0.5rem;
|
||||
font-family: var(--font-terminal);
|
||||
font-size: 0.8rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
/* Enhanced Shimmer Effect */
|
||||
.experience-header::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
|
||||
transition: left 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.experience-card:hover .experience-header::after {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
/* Card Body Optimization */
|
||||
.experience-body,
|
||||
.info-content {
|
||||
padding: var(--card-padding);
|
||||
background: var(--color-nier-bg);
|
||||
}
|
||||
|
||||
.info-content {
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Typography Scale */
|
||||
.experience-title {
|
||||
font-family: var(--font-noto-jp);
|
||||
font-size: 0.95rem;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.02em;
|
||||
line-height: 1.2;
|
||||
margin: 0;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
/* Enhanced Detail Blocks */
|
||||
.detail-block {
|
||||
margin-bottom: var(--card-gap);
|
||||
padding: 0.25rem;
|
||||
border-left: 2px solid transparent;
|
||||
transition: border-color 0.3s ease, padding-left 0.3s ease;
|
||||
}
|
||||
|
||||
.detail-block:hover {
|
||||
border-left-color: var(--color-nier-accent);
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-family: var(--font-terminal);
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-nier-text-dark);
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
display: block;
|
||||
margin-bottom: 0.25rem;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.detail-block:hover .detail-label {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-family: var(--font-noto-jp);
|
||||
color: var(--color-nier-text-dark);
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.4;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Enhanced Tech Stack Section */
|
||||
.tech-section {
|
||||
margin-top: var(--card-gap);
|
||||
padding-top: var(--card-gap);
|
||||
border-top: 1px solid var(--color-nier-border);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tech-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 30%;
|
||||
height: 1px;
|
||||
background: var(--color-nier-accent);
|
||||
}
|
||||
|
||||
.tech-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
/* Enhanced Tech & Trait Items */
|
||||
.tech-item,
|
||||
.trait-item {
|
||||
background: linear-gradient(135deg, var(--color-nier-accent) 0%, var(--color-nier-highlight) 100%);
|
||||
color: var(--color-nier-text-light);
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.7rem;
|
||||
font-family: var(--font-terminal);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-radius: 3px;
|
||||
white-space: nowrap;
|
||||
transition: var(--transition-smooth);
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.tech-item:hover,
|
||||
.trait-item:hover {
|
||||
transform: translateY(-2px) scale(1.05);
|
||||
box-shadow: 0 6px 12px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.trait-item {
|
||||
padding: 0.375rem 0.25rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Enhanced Status Badges */
|
||||
.current-status,
|
||||
.completed-status {
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.7rem;
|
||||
font-family: var(--font-terminal-retro);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
border-radius: 20px;
|
||||
margin-bottom: 0.5rem;
|
||||
display: inline-block;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
transition: var(--transition-smooth);
|
||||
}
|
||||
|
||||
.current-status {
|
||||
background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.completed-status {
|
||||
background: linear-gradient(135deg, var(--color-nier-accent) 0%, var(--color-nier-highlight) 100%);
|
||||
color: var(--color-nier-text-light);
|
||||
}
|
||||
|
||||
/* Personal Info Grid */
|
||||
.trait-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.interest-item {
|
||||
margin-bottom: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem;
|
||||
border-radius: 2px;
|
||||
transition: background-color 0.3s ease, transform 0.3s ease;
|
||||
}
|
||||
|
||||
.interest-item:hover {
|
||||
background-color: rgba(41, 41, 37, 0.05);
|
||||
transform: translateX(2px);
|
||||
}
|
||||
|
||||
.interest-label {
|
||||
font-family: var(--font-terminal);
|
||||
font-size: 0.7rem;
|
||||
color: var(--color-nier-text-dark);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
width: 60px;
|
||||
flex-shrink: 0;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.interest-value {
|
||||
font-family: var(--font-noto-jp);
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-nier-text-dark);
|
||||
}
|
||||
|
||||
/* Enhanced Philosophy Section */
|
||||
.philosophy-text {
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.5;
|
||||
font-style: italic;
|
||||
margin-bottom: var(--card-gap);
|
||||
position: relative;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.philosophy-text::before {
|
||||
content: '"';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: -0.25rem;
|
||||
font-size: 1.5rem;
|
||||
color: var(--color-nier-accent);
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.philosophy-note {
|
||||
font-family: var(--font-terminal);
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-nier-text-dark);
|
||||
opacity: 0.8;
|
||||
margin-top: var(--card-gap);
|
||||
padding-top: var(--card-gap);
|
||||
border-top: 1px solid var(--color-nier-border);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Visual Effects */
|
||||
.corner-accent {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 10px solid transparent;
|
||||
border-top: 10px solid var(--color-nier-accent);
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.experience-card:hover .corner-accent {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.scan-line {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, var(--color-nier-accent), transparent);
|
||||
animation: scan 4s ease-in-out infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
/* Keyframe Animations */
|
||||
@keyframes scan {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Performance Optimizations */
|
||||
.experience-card,
|
||||
.info-card,
|
||||
.tech-item,
|
||||
.trait-item {
|
||||
backface-visibility: hidden;
|
||||
-webkit-backface-visibility: hidden;
|
||||
}
|
||||
|
||||
/* Responsive Design - Optimized */
|
||||
@media (max-width: 480px) {
|
||||
:host {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.operative-history-container {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.5rem;
|
||||
max-height: calc(100vh - 6rem);
|
||||
}
|
||||
|
||||
.column {
|
||||
gap: 0.5rem;
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
|
||||
.column-title {
|
||||
font-size: 0.9rem;
|
||||
padding: 0.375rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.experience-card,
|
||||
.info-card {
|
||||
margin-bottom: 0.5rem;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.experience-header,
|
||||
.info-header {
|
||||
padding: 0.75rem 0.5rem 0.5rem 0.5rem;
|
||||
}
|
||||
|
||||
.experience-body,
|
||||
.info-content {
|
||||
padding: 0.75rem 0.5rem;
|
||||
}
|
||||
|
||||
.experience-title {
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.detail-block {
|
||||
margin-bottom: 1rem;
|
||||
padding: 0.5rem 0.25rem;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 0.7rem;
|
||||
margin-bottom: 0.375rem;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.tech-section {
|
||||
margin-top: 1.25rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.tech-item {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.7rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.current-status,
|
||||
.completed-status {
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.7rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.trait-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.trait-item {
|
||||
padding: 0.5rem 0.375rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.interest-item {
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.5rem 0.25rem;
|
||||
}
|
||||
|
||||
.interest-label {
|
||||
font-size: 0.75rem;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.interest-value {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.philosophy-text {
|
||||
font-size: 0.8rem;
|
||||
padding-left: 0.75rem;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.philosophy-note {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.4;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.info-content {
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) and (min-width: 481px) {
|
||||
.operative-history-container {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.column-title {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.experience-title {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.detail-value,
|
||||
.info-content {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) and (min-width: 769px) {
|
||||
.operative-history-container {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.personal-column {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1201px) {
|
||||
.operative-history-container {
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.column {
|
||||
padding-right: 0.75rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<div class="operative-history-container">
|
||||
<!-- Professional Experience Column -->
|
||||
<div class="column professional-column">
|
||||
<h2 class="column-title">[PROFESSIONAL_ARCHIVE]</h2>
|
||||
|
||||
<div class="experience-list">
|
||||
@for (experience of experiences(); track experience.id) {
|
||||
<article class="experience-card">
|
||||
<div class="corner-accent"></div>
|
||||
@if (experience.status === 'current') {
|
||||
<div class="scan-line"></div>
|
||||
}
|
||||
|
||||
<header class="experience-header">
|
||||
<div
|
||||
class="status-badge"
|
||||
[class.current-status]="experience.status === 'current'"
|
||||
[class.completed-status]="experience.status === 'completed'">
|
||||
{{ experience.statusLabel }}
|
||||
</div>
|
||||
<h3 class="experience-title">
|
||||
{{ experience.title }}
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<div class="experience-body">
|
||||
<div class="detail-block">
|
||||
<span class="detail-label">CLASSIFICATION:</span>
|
||||
<span class="detail-value">{{ experience.classification }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-block">
|
||||
<span class="detail-label">TIMELINE:</span>
|
||||
<span class="detail-value">{{ experience.timeline }}</span>
|
||||
</div>
|
||||
|
||||
<div class="tech-section">
|
||||
<div class="detail-label">TECH_STACK:</div>
|
||||
<div class="tech-grid">
|
||||
@for (tech of experience.techStack; track tech) {
|
||||
<span class="tech-item">{{ tech }}</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Education Column -->
|
||||
<div class="column education-column">
|
||||
<h2 class="column-title">[EDUCATION_PROTOCOL]</h2>
|
||||
|
||||
@if (currentTraining(); as training) {
|
||||
<article class="experience-card active-training">
|
||||
<div class="corner-accent"></div>
|
||||
<div class="scan-line"></div>
|
||||
|
||||
<header class="experience-header">
|
||||
<div class="current-status">{{ training.statusLabel }}</div>
|
||||
<h3 class="experience-title">{{ training.title }}</h3>
|
||||
</header>
|
||||
|
||||
<div class="experience-body">
|
||||
<div class="detail-block">
|
||||
<span class="detail-label">PROGRAM:</span>
|
||||
<span class="detail-value">{{ training.classification }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-block">
|
||||
<span class="detail-label">INSTITUTION:</span>
|
||||
<span class="detail-value">{{ training.timeline }}</span>
|
||||
</div>
|
||||
|
||||
<div class="tech-section">
|
||||
<div class="detail-label">CURRICULUM:</div>
|
||||
<div class="tech-grid">
|
||||
@for (tech of training.techStack; track tech) {
|
||||
<span class="tech-item">{{ tech }}</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
|
||||
<!-- Additional Education Info -->
|
||||
<div class="info-card">
|
||||
<div class="info-header">ACADEMIC_FOCUS</div>
|
||||
<div class="info-content">
|
||||
<p>Full-stack development specialization with emphasis on modern web technologies and enterprise-grade solutions.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Personal Info Column -->
|
||||
<div class="column personal-column">
|
||||
<h2 class="column-title">[PERSONAL_DATA]</h2>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-header">INTERESTS</div>
|
||||
<div class="info-content">
|
||||
<div class="interest-item">
|
||||
<span class="interest-label">GENRE:</span>
|
||||
<span class="interest-value">Science Fiction</span>
|
||||
</div>
|
||||
<div class="interest-item">
|
||||
<span class="interest-label">STUDY:</span>
|
||||
<span class="interest-value">Philosophy</span>
|
||||
</div>
|
||||
<div class="interest-item">
|
||||
<span class="interest-label">PETS:</span>
|
||||
<span class="interest-value">6 Guinea Pigs</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-header">CORE_TRAITS</div>
|
||||
<div class="info-content">
|
||||
<div class="trait-grid">
|
||||
<span class="trait-item">CURIOUS</span>
|
||||
<span class="trait-item">PERSISTENT</span>
|
||||
<span class="trait-item">ANALYTICAL</span>
|
||||
<span class="trait-item">CREATIVE</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card philosophy-card">
|
||||
<div class="info-header">PHILOSOPHY</div>
|
||||
<div class="info-content">
|
||||
<p class="philosophy-text">
|
||||
"The most elegant code emerges from understanding both the technical substrate and the consciousness it serves."
|
||||
</p>
|
||||
<div class="philosophy-note">
|
||||
{{ personalNote() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,112 @@
|
||||
// operative-history.component.ts
|
||||
import { Component, signal, computed } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
interface Experience {
|
||||
readonly id: string;
|
||||
readonly title: string;
|
||||
readonly classification: string;
|
||||
readonly objective: string;
|
||||
readonly timeline: string;
|
||||
readonly techStack: readonly string[];
|
||||
readonly status: 'current' | 'completed';
|
||||
readonly statusLabel: string;
|
||||
readonly isCurrent?: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-operative-history',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
templateUrl: './operative-history.component.html',
|
||||
styleUrl: './operative-history.component.css',
|
||||
})
|
||||
export class OperativeHistoryComponent {
|
||||
// Signals for reactive data
|
||||
private readonly _experiences = signal<readonly Experience[]>([
|
||||
{
|
||||
id: 'senior-specialist',
|
||||
title: 'PYTHON_API_SPECIALIST.EXE',
|
||||
classification: 'Python & Django API/RPA Specialist',
|
||||
objective:
|
||||
'Specialized in Python/Django development for API automation and RPA processes. Led technical interventions for complex enterprise HR system integrations, developing robust solutions that bridge business requirements with technical implementation.',
|
||||
timeline: 'UKG | January 2024 - January 2025',
|
||||
techStack: ['PYTHON', 'DJANGO', 'API', 'RPA'] as const,
|
||||
status: 'completed',
|
||||
statusLabel: 'ARCHIVED | SME_SPECIALIST',
|
||||
},
|
||||
{
|
||||
id: 'specialist-ii',
|
||||
title: 'SYSTEMS_INTEGRATION_SME.EXE',
|
||||
classification: 'Enterprise Systems Integration',
|
||||
objective:
|
||||
'Subject Matter Expert (SME) for enterprise HRSD connectors and system integrations. Specialized in complex technical challenges involving API development, RPA automation, and SFTP protocols. Provided BI support and data visualization solutions.',
|
||||
timeline: 'UKG | January 2023 - January 2024',
|
||||
techStack: ['PYTHON', 'DJANGO', 'API', 'RPA'] as const,
|
||||
status: 'completed',
|
||||
statusLabel: 'ARCHIVED | SME_SPECIALIST',
|
||||
},
|
||||
{
|
||||
id: 'specialist',
|
||||
title: 'SOLUTION_SUPPORT.EXE',
|
||||
classification: 'B2B Solution Support',
|
||||
objective:
|
||||
'Delivered high-level technical support for VIP business clients using HRSD solutions. Developed expertise in SaaS platforms and enterprise decision-making processes while managing critical client relationships.',
|
||||
timeline: 'UKG | October 2021 - January 2023',
|
||||
techStack: ['SAAS', 'HRSD', 'CLIENT_MGMT'] as const,
|
||||
status: 'completed',
|
||||
statusLabel: 'ARCHIVED | VIP_TIER',
|
||||
},
|
||||
{
|
||||
id: 'technician',
|
||||
title: 'IT_TECHNICIAN.EXE',
|
||||
classification: 'Information Technology Technician',
|
||||
objective:
|
||||
'Provided VIP end-user support, managed hardware/software deployments, and implemented networking and information security practices in a mission-critical environment.',
|
||||
timeline: 'Armée de Terre | July 2018 - December 2018',
|
||||
techStack: ['NETWORKING', 'SECURITY', 'DEPLOYMENT'] as const,
|
||||
status: 'completed',
|
||||
statusLabel: 'ARCHIVED | MILITARY',
|
||||
},
|
||||
] as const);
|
||||
|
||||
private readonly _currentTraining = signal<Experience>({
|
||||
id: 'developer-training',
|
||||
title: 'DEVELOPER_TRAINING.EXE',
|
||||
classification: "Concepteur Développeur d'Applications (RNCP Level BAC+4)",
|
||||
objective:
|
||||
'Intensive full-stack development program focusing on modern web technologies including TypeScript, Node.js, and contemporary development frameworks. Building comprehensive skills in both frontend and backend development.',
|
||||
timeline: "École O'clock | January 2025 - October 2025",
|
||||
techStack: [
|
||||
'TYPESCRIPT',
|
||||
'NODE.JS',
|
||||
'FULL_STACK',
|
||||
'WEB_FRAMEWORKS',
|
||||
] as const,
|
||||
status: 'current',
|
||||
statusLabel: 'ACTIVE | IN_PROGRESS',
|
||||
isCurrent: true,
|
||||
} as const);
|
||||
|
||||
private readonly _philosophyText = signal<readonly string[]>([
|
||||
'Four years navigating the intersection between human needs and machine logic has taught me that the most elegant code emerges from understanding both the technical substrate and the consciousness it serves. My journey through enterprise system matrices—from military-grade security protocols to corporate data synthesis—has prepared me for a world where the line between human intention and digital execution grows ever thinner.',
|
||||
'I approach development like a philosopher examining the nature of existence: with persistent curiosity and the understanding that every system, no matter how complex, serves a fundamentally human purpose. In a cyberpunk reality where APIs are neural pathways and databases are digital memories, I believe in crafting code that honors both computational efficiency and human dignity.',
|
||||
'The future belongs to those who can bridge the organic and the synthetic, who understand that behind every elegant algorithm lies a human story waiting to be told.',
|
||||
] as const);
|
||||
|
||||
private readonly _personalNote = signal<string>(
|
||||
'In the spaces between keystrokes and compiler runs, I contemplate the philosophical implications of our digital convergence. When not debugging the matrix, I tend to six small organic beings who remind me that even in our increasingly automated world, care and attention to living creatures remains profoundly important.',
|
||||
);
|
||||
|
||||
// Public computed signals for template
|
||||
readonly experiences = this._experiences.asReadonly();
|
||||
readonly currentTraining = this._currentTraining.asReadonly();
|
||||
readonly philosophyText = this._philosophyText.asReadonly();
|
||||
readonly personalNote = this._personalNote.asReadonly();
|
||||
|
||||
// Computed signals for derived data
|
||||
readonly totalExperience = computed(() => this.experiences().length);
|
||||
readonly currentTechStack = computed(() => [
|
||||
...new Set(this.experiences().flatMap((exp) => exp.techStack)),
|
||||
]);
|
||||
}
|
||||
168
src/styles.css
168
src/styles.css
@@ -121,4 +121,172 @@
|
||||
border: 1px solid var(--color-nier-border);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* ===================== NIER CUSTOM SCROLLBAR ===================== */
|
||||
|
||||
/* Global scrollbar for all elements */
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--color-nier-accent) var(--color-nier-border);
|
||||
}
|
||||
|
||||
/* WebKit browsers (Chrome, Safari, Edge) */
|
||||
::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--color-nier-bg);
|
||||
border: 1px solid var(--color-nier-border);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(135deg, var(--color-nier-accent) 0%, var(--color-nier-highlight) 100%);
|
||||
border: 1px solid var(--color-nier-border);
|
||||
border-radius: 1px;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(135deg, var(--color-nier-highlight) 0%, var(--color-nier-accent) 100%);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:active {
|
||||
background: var(--color-nier-dark);
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {
|
||||
background: var(--color-nier-bg);
|
||||
border: 1px solid var(--color-nier-border);
|
||||
}
|
||||
|
||||
/* Body scrollbar (main page scroll) */
|
||||
body::-webkit-scrollbar {
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar-track {
|
||||
background: var(--color-nier-checkered-bg);
|
||||
background-size: 8px 8px;
|
||||
background-image:
|
||||
linear-gradient(to right, var(--color-nier-checkered-grid) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, var(--color-nier-checkered-grid) 1px, transparent 1px);
|
||||
border: 2px solid var(--color-nier-border);
|
||||
}
|
||||
|
||||
/* Code blocks and pre elements */
|
||||
pre::-webkit-scrollbar,
|
||||
code::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
pre::-webkit-scrollbar-track,
|
||||
code::-webkit-scrollbar-track {
|
||||
background: var(--color-nier-dark);
|
||||
border: 1px solid var(--color-nier-accent);
|
||||
}
|
||||
|
||||
pre::-webkit-scrollbar-thumb,
|
||||
code::-webkit-scrollbar-thumb {
|
||||
background: var(--color-nier-accent);
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
table::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
/* Modal and overlay scrollbars */
|
||||
.modal::-webkit-scrollbar,
|
||||
.overlay::-webkit-scrollbar,
|
||||
.dialog::-webkit-scrollbar,
|
||||
[role="dialog"]::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.modal::-webkit-scrollbar-track,
|
||||
.overlay::-webkit-scrollbar-track,
|
||||
.dialog::-webkit-scrollbar-track,
|
||||
[role="dialog"]::-webkit-scrollbar-track {
|
||||
background: var(--color-nier-mid);
|
||||
border: 1px solid var(--color-nier-border);
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
/* High contrast mode support */
|
||||
@media (prefers-contrast: high) {
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--color-nier-text-dark);
|
||||
border: 2px solid var(--color-nier-accent);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--color-nier-bg);
|
||||
border: 2px solid var(--color-nier-border);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reduced motion support */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
::-webkit-scrollbar-thumb {
|
||||
transition: none;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover,
|
||||
::-webkit-scrollbar-thumb:active {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Special scrollbar for checkered backgrounds */
|
||||
.checkered-bg::-webkit-scrollbar-track,
|
||||
.checkered-background::-webkit-scrollbar-track {
|
||||
background: var(--color-nier-checkered-bg);
|
||||
background-size: 6px 6px;
|
||||
background-image:
|
||||
linear-gradient(to right, var(--color-nier-checkered-grid) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, var(--color-nier-checkered-grid) 1px, transparent 1px);
|
||||
}
|
||||
|
||||
/* NieR UI specific scrollbars */
|
||||
.nier-panel::-webkit-scrollbar,
|
||||
.nier-menu::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.nier-panel::-webkit-scrollbar-track,
|
||||
.nier-menu::-webkit-scrollbar-track {
|
||||
background: var(--color-nier-bg);
|
||||
border: 2px inset var(--color-nier-border);
|
||||
}
|
||||
|
||||
.nier-panel::-webkit-scrollbar-thumb,
|
||||
.nier-menu::-webkit-scrollbar-thumb {
|
||||
background: var(--color-nier-accent);
|
||||
border: 1px outset var(--color-nier-highlight);
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user