Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions scripts/copy-resume.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ const destDir = 'public/resume';
// Ensure destination directory exists
fs.mkdirSync(destDir, { recursive: true });

// Copy PDF and HTML files
// Copy PDF files
const files = fs.readdirSync(srcDir);
for (const file of files) {
if (file.endsWith('.pdf') || file.endsWith('.html')) {
if (file.endsWith('.pdf')) {
fs.copyFileSync(path.join(srcDir, file), path.join(destDir, file));
console.log(`Copied ${file}`);
}
Expand Down
22 changes: 14 additions & 8 deletions src/__tests__/components/TerminalEmulator.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import TerminalEmulator from '@/components/terminal/TerminalEmulator';
import { $isAppReady } from '@/stores/app-store';
import {
$terminalHistory,
$terminalHistoryVisibleIdx,
$terminalPromptRef,
} from '@/stores/terminal-store';
import type { CommandEntry } from '@/types/terminal';
import { Command } from '@/types/terminal';

Expand All @@ -21,6 +27,12 @@ vi.mock('@/stores/terminal-store', () => ({
initializeTerminal: vi.fn(),
}));

vi.mock('@/stores/app-store', () => ({
$isAppReady: {
get: vi.fn(() => true),
},
}));

vi.mock('next-intl', () => ({
useTranslations: vi.fn(() => (key: string) => key),
}));
Expand All @@ -43,23 +55,17 @@ vi.mock('@/components/cmd-outputs/UnknownCmdOutput', () => ({
)),
}));

import {
$terminalHistory,
$terminalHistoryVisibleIdx,
$terminalPromptRef,
initializeTerminal,
} from '@/stores/terminal-store';

describe('TerminalEmulator', () => {
const mockHistoryGet = vi.mocked($terminalHistory.get);
const mockHistoryVisibleIdxGet = vi.mocked($terminalHistoryVisibleIdx.get);
const mockPromptRefSet = vi.mocked($terminalPromptRef.set);
const _mockInitializeTerminal = vi.mocked(initializeTerminal);
const mockIsAppReadyGet = vi.mocked($isAppReady.get);

beforeEach(() => {
vi.clearAllMocks();
mockHistoryGet.mockReturnValue([]);
mockHistoryVisibleIdxGet.mockReturnValue(0);
mockIsAppReadyGet.mockReturnValue(true);
});

afterEach(() => {
Expand Down
96 changes: 56 additions & 40 deletions src/components/LoadSequence.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useStore } from '@nanostores/react';
import { useEffect, useMemo, useState } from 'react';
import { $isAppMounted, $isAppReady } from '@/stores/app-store';
import { $isDarkMode } from '@/stores/theme-store';

interface LoadSequenceProps {
Expand All @@ -10,13 +11,22 @@ interface LoadSequenceProps {

export default function LoadSequence({ children }: LoadSequenceProps) {
const [currentStep, setCurrentStep] = useState(0);
const [isLoading, setIsLoading] = useState(true);
const [animationDone, setAnimationDone] = useState(false);
const isDarkMode = useStore($isDarkMode);
const isAppMounted = useStore($isAppMounted);

const isLoading = !animationDone || !isAppMounted;

useEffect(() => {
document.body.style.visibility = 'visible';
}, []);

useEffect(() => {
if (!isLoading) {
$isAppReady.set(true);
}
}, [isLoading]);

const steps = useMemo(
() => [
{ message: '> Detecting theme preference...', delay: 600 },
Expand All @@ -40,55 +50,61 @@ export default function LoadSequence({ children }: LoadSequenceProps) {

return () => clearTimeout(timer);
} else {
setIsLoading(false);
setAnimationDone(true);
}
}, [currentStep, steps]);

const fadeInAnimation =
'opacity-0 animate-[showInstant_0s_ease-in-out_forwards]';
const stepHeight = 'h-[24px] leading-6';

if (!isLoading && children) {
return <>{children}</>;
}

return (
<div className="p-8 text-sm font-medium leading-5">
<style>{`
@keyframes showInstant {
from { opacity: 0; }
to { opacity: 1; }
}
`}</style>
<div className="flex flex-col pt-[24px] relative">
{/* Static HTML steps that display immediately */}
<div
className={`top-0 absolute ${fadeInAnimation}`}
style={{ animationDelay: '200ms' }}
>
<span>{'> Connected to IPFS'}</span>
</div>
<div
className={`top-[24px] ${currentStep ? '' : fadeInAnimation} h-0`}
style={{ animationDelay: '600ms' }}
>
<span>{'> Loading core chunks'}</span>
</div>
<>
<div
aria-hidden={isLoading}
className={isLoading ? 'invisible h-0 overflow-hidden' : undefined}
>
{children}
</div>

<div className="flex flex-col mt-[24px]">
{steps.slice(0, currentStep).map((step) => (
<div className={stepHeight} key={step.message}>
{step.message}
{isLoading && (
<div className="p-8 text-sm font-medium leading-5">
<style>{`
@keyframes showInstant {
from { opacity: 0; }
to { opacity: 1; }
}
`}</style>
<div className="flex flex-col pt-[24px] relative">
<div
className={`top-0 absolute ${fadeInAnimation}`}
style={{ animationDelay: '200ms' }}
>
<span>{'> Connected to IPFS'}</span>
</div>
))}
</div>
<div
className={`${fadeInAnimation}`}
style={{ animationDelay: '600ms' }}
>
<span className="animate-pulse">█</span>
<div
className={`top-[24px] ${currentStep ? '' : fadeInAnimation} h-0`}
style={{ animationDelay: '600ms' }}
>
<span>{'> Loading core chunks'}</span>
</div>

<div className="flex flex-col mt-[24px]">
{steps.slice(0, currentStep).map((step) => (
<div className={stepHeight} key={step.message}>
{step.message}
</div>
))}
</div>
<div
className={`${fadeInAnimation}`}
style={{ animationDelay: '600ms' }}
>
<span className="animate-pulse">█</span>
</div>
</div>
</div>
</div>
</div>
)}
</>
);
}
20 changes: 14 additions & 6 deletions src/components/cmd-outputs/ContactOutput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,6 @@ export default function ContactOutput() {
href: 'https://x.com/nipsysdev',
displayText: '@nipsysdev',
},
{
icon: PaperPlaneTiltIcon,
labelKey: 'telegram',
href: 'https://t.me/nipsysdev',
displayText: '@nipsysdev',
},
{
icon: ButterflyIcon,
labelKey: 'bluesky',
Expand Down Expand Up @@ -83,6 +77,20 @@ export default function ContactOutput() {
displayText: '@nipsys:nips.im',
copyable: true,
},
{
icon: ChatTeardropTextIcon,
labelKey: 'signal',
href: 'https://signal.me/#eu/4FynXZ6lCD-qaR0x_CfvmEGVVtnprCVT4YRzyVrn7GVNB71oVHFAL6aP2soYBAI4',
displayText: 'nipsysdev.12',
copyable: true,
},
{
icon: PaperPlaneTiltIcon,
labelKey: 'telegram',
href: 'https://t.me/nipsysdev',
displayText: '@nipsysdev',
copyable: true,
},
{
icon: EnvelopeIcon,
labelKey: 'email',
Expand Down
Loading
Loading