diff --git a/app/api/email/respond/route.tsx b/app/api/email/respond/route.tsx index 4fa1582..c936628 100644 --- a/app/api/email/respond/route.tsx +++ b/app/api/email/respond/route.tsx @@ -3,412 +3,199 @@ import nodemailer from "nodemailer"; import SMTPTransport from "nodemailer/lib/smtp-transport"; import Mail from "nodemailer/lib/mailer"; -// Email templates with beautiful designs +const BRAND = { + siteUrl: "https://dk0.dev", + email: "contact@dk0.dev", + bg: "#FDFCF8", + sand: "#F3F1E7", + border: "#E7E5E4", + text: "#292524", + muted: "#78716C", + mint: "#A7F3D0", + red: "#EF4444", +}; + +function escapeHtml(input: string): string { + return input + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +function nl2br(input: string): string { + return input.replace(/\r\n|\r|\n/g, "
"); +} + +function baseEmail(opts: { title: string; subtitle: string; bodyHtml: string }) { + const sentAt = new Date().toLocaleString("de-DE", { + year: "numeric", + month: "long", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }); + + return ` + + + + + + ${escapeHtml(opts.title)} + + +
+
+
+
+
Dennis Konkol
+
+ dk0.dev +
+
+
+
${escapeHtml(opts.title)}
+
${escapeHtml(opts.subtitle)} β€’ ${sentAt}
+
+
+
+ +
+ ${opts.bodyHtml} +
+ +
+
+ Automatisch generiert von dk0.dev β€’ + ${BRAND.email} +
+
+
+
+ + + `.trim(); +} + const emailTemplates = { welcome: { subject: "Vielen Dank fΓΌr deine Nachricht! πŸ‘‹", - template: (name: string, originalMessage: string) => ` - - - - - - Willkommen - Dennis Konkol - - -
- - -
-

- πŸ‘‹ Hallo ${name}! -

-

- Vielen Dank fΓΌr deine Nachricht -

-
- - -
- - -
-
-
- βœ“ -
-

Nachricht erhalten!

-
-

- Vielen Dank fΓΌr deine Nachricht! Ich habe sie erhalten und werde mich so schnell wie mΓΆglich bei dir melden. -

-
- - -
-

- - Deine ursprΓΌngliche Nachricht -

-
-

${originalMessage}

-
-
- - -
-

- πŸš€ Was passiert als nΓ€chstes? -

-
-
- πŸ“§ -
-

Schnelle Antwort

-

Ich antworte normalerweise innerhalb von 24 Stunden

-
-
-
- πŸ’Ό -
-

Projekt-Diskussion

-

Gerne besprechen wir dein Projekt im Detail

-
-
-
- 🀝 -
-

Zusammenarbeit

-

Lass uns gemeinsam etwas Großartiges schaffen!

-
-
-
-
- - -
-

Entdecke mehr von mir

-
- - 🌐 Portfolio - - - πŸ’» GitHub - - - πŸ’Ό LinkedIn - -
-
-
- - -
-
- -
-

- Dennis Konkol β€’ Software Engineer & Student
- dk0.dev β€’ - contact@dk0.dev -

-

- ${new Date().toLocaleString('de-DE', { - year: 'numeric', - month: 'long', - day: 'numeric', - hour: '2-digit', - minute: '2-digit' - })} -

-
- -
- - - ` + template: (name: string, originalMessage: string) => { + const safeName = escapeHtml(name); + const safeMsg = nl2br(escapeHtml(originalMessage)); + return baseEmail({ + title: `Danke, ${safeName}!`, + subtitle: "Nachricht erhalten", + bodyHtml: ` +
+ Hey ${safeName},

+ danke fΓΌr deine Nachricht β€” ich habe sie erhalten und melde mich so schnell wie mΓΆglich bei dir zurΓΌck. +
+ +
+
+
Deine Nachricht
+
+
+ ${safeMsg} +
+
+ +
+ + Portfolio ansehen + +
+ `.trim(), + }); + }, }, - project: { subject: "Projekt-Anfrage erhalten! πŸš€", - template: (name: string, originalMessage: string) => ` - - - - - - Projekt-Anfrage - Dennis Konkol - - -
- - -
-

- πŸš€ Projekt-Anfrage erhalten! -

-

- Hallo ${name}, lass uns etwas Großartiges schaffen! -

-
- - -
- - -
-
-
- πŸ’Ό -
-

Bereit fΓΌr dein Projekt!

-
-

- Vielen Dank fΓΌr deine Projekt-Anfrage! Ich bin gespannt darauf, mehr ΓΌber deine Ideen zu erfahren und wie wir sie gemeinsam umsetzen kΓΆnnen. -

-
- - -
-

- - Deine Projekt-Nachricht -

-
-

${originalMessage}

-
-
- - -
-

- 🎯 Mein Arbeitsprozess -

-
-
- πŸ’¬ -
-

1. ErstgesprΓ€ch

-

Wir besprechen deine Anforderungen im Detail

-
-
-
- πŸ“‹ -
-

2. Konzept & Planung

-

Ich erstelle ein detailliertes Konzept fΓΌr dein Projekt

-
-
-
- ⚑ -
-

3. Entwicklung

-

Agile Entwicklung mit regelmÀßigen Updates

-
-
-
- πŸŽ‰ -
-

4. Launch & Support

-

Deployment und kontinuierlicher Support

-
-
-
-
- - -
- - πŸ’¬ Projekt besprechen - -
-
- - -
-
- -
-

- Dennis Konkol β€’ Software Engineer & Student
- dki.one β€’ - contact@dk0.dev -

-
- -
- - - ` + template: (name: string, originalMessage: string) => { + const safeName = escapeHtml(name); + const safeMsg = nl2br(escapeHtml(originalMessage)); + return baseEmail({ + title: `Projekt-Anfrage: danke, ${safeName}!`, + subtitle: "Ich melde mich zeitnah", + bodyHtml: ` +
+ Hey ${safeName},

+ mega β€” danke fΓΌr die Projekt-Anfrage. Ich schaue mir deine Nachricht an und komme mit RΓΌckfragen/Ideen auf dich zu. +
+ +
+
+
Deine Projekt-Nachricht
+
+
+ ${safeMsg} +
+
+ +
+ + Kontakt aufnehmen + +
+ `.trim(), + }); + }, }, - quick: { subject: "Danke für deine Nachricht! ⚑", - template: (name: string, originalMessage: string) => ` - - - - - - Quick Response - Dennis Konkol - - -
- - -
-

- ⚑ Schnelle Antwort! -

-

- Hallo ${name}, danke fΓΌr deine Nachricht! -

-
- - -
- - -
-
-
- ⚑ -
-

Nachricht erhalten!

-

- Vielen Dank fΓΌr deine Nachricht! Ich werde mich so schnell wie mΓΆglich bei dir melden. -

-
-
- - -
-

- - Deine Nachricht -

-
-

${originalMessage}

-
-
- - -
-

- πŸ“ž Kontakt -

-

- E-Mail: contact@dk0.dev
- Portfolio: dki.one -

-
-
- - -
-
- -
-

- Dennis Konkol β€’ Software Engineer & Student
- dki.one -

-
- -
- - - ` + template: (name: string, originalMessage: string) => { + const safeName = escapeHtml(name); + const safeMsg = nl2br(escapeHtml(originalMessage)); + return baseEmail({ + title: `Danke, ${safeName}!`, + subtitle: "Kurze BestΓ€tigung", + bodyHtml: ` +
+ Hey ${safeName},

+ kurze BestΓ€tigung: deine Nachricht ist angekommen. Ich melde mich bald zurΓΌck. +
+ +
+
+
Deine Nachricht
+
+
+ ${safeMsg} +
+
+ `.trim(), + }); + }, }, reply: { subject: "Antwort auf deine Nachricht πŸ“§", - template: (name: string, originalMessage: string) => ` - - - - - - Antwort - Dennis Konkol - - -
- - -
-

- πŸ“§ Hallo ${name}! -

-

- Hier ist meine Antwort auf deine Nachricht -

-
- - -
- - -
-
-
- πŸ’¬ -
-

Meine Antwort

-
-
-

${originalMessage}

-
-
- - -
-

- - Deine ursprΓΌngliche Nachricht -

-
-

${originalMessage}

-
-
- - -
-

Weitere Fragen?

-

- Falls du weitere Fragen hast oder mehr ΓΌber meine Projekte erfahren mΓΆchtest, zΓΆgere nicht, mir zu schreiben! -

-
- - 🌐 Portfolio besuchen - - - πŸ“§ Direkt antworten - -
-
- -
- - -
-

- Dennis Konkol β€’ dki.one -

-

- ${new Date().toLocaleString('de-DE', { - year: 'numeric', - month: 'long', - day: 'numeric', - hour: '2-digit', - minute: '2-digit' - })} -

-
- -
- - - ` - } + template: (name: string, originalMessage: string) => { + const safeName = escapeHtml(name); + const safeMsg = nl2br(escapeHtml(originalMessage)); + return baseEmail({ + title: `Antwort fΓΌr ${safeName}`, + subtitle: "Neue Nachricht", + bodyHtml: ` +
+ Hey ${safeName},

+ hier ist meine Antwort: +
+ +
+
+
Antwort
+
+
+ ${safeMsg} +
+
+ `.trim(), + }); + }, + }, }; export async function POST(request: NextRequest) { diff --git a/app/api/email/route.tsx b/app/api/email/route.tsx index e5367a4..9aba4ed 100644 --- a/app/api/email/route.tsx +++ b/app/api/email/route.tsx @@ -15,6 +15,15 @@ function sanitizeInput(input: string, maxLength: number = 10000): string { .trim(); } +function escapeHtml(input: string): string { + return input + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + export async function POST(request: NextRequest) { try { // Rate limiting (defensive: headers may be undefined in tests) @@ -155,6 +164,22 @@ export async function POST(request: NextRequest) { } } + const brandUrl = "https://dk0.dev"; + const sentAt = new Date().toLocaleString('de-DE', { + year: 'numeric', + month: 'long', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + }); + + const safeName = escapeHtml(name); + const safeEmail = escapeHtml(email); + const safeSubject = escapeHtml(subject); + const safeMessageHtml = escapeHtml(message).replace(/\n/g, "
"); + const initial = (name.trim()[0] || "?").toUpperCase(); + const replyHref = `mailto:${email}?subject=${encodeURIComponent(`Re: ${subject}`)}`; + const mailOptions: Mail.Options = { from: `"Portfolio Contact" <${user}>`, to: "contact@dk0.dev", // Send to your contact email @@ -168,86 +193,80 @@ export async function POST(request: NextRequest) { Neue Kontaktanfrage - Portfolio - -
- - -
-

- πŸ“§ Neue Kontaktanfrage -

-

- Von deinem Portfolio -

+ +
+
+ +
+
+
+ Dennis Konkol +
+
+ dk0.dev +
- - -
- - -
-
-
- ${name.charAt(0).toUpperCase()} -
-
-

${name}

-

Kontaktanfrage

-
-
- -
-
-

E-Mail

-

${email}

-
-
-

Betreff

-

${subject}

-
-
-
- - -
-
-
-

Nachricht

-
-
-

${message}

-
-
- - - +
+
+ Neue Kontaktanfrage +
+
+ Eingegangen am ${sentAt} +
- - -
-
- +
+
+ + +
+ +
+
+ ${escapeHtml(initial)} +
+
+
+ ${safeName}
-

- Diese E-Mail wurde automatisch von deinem Portfolio generiert.
- Dennis Konkol Portfolio β€’ dki.one -

-

- ${new Date().toLocaleString('de-DE', { - year: 'numeric', - month: 'long', - day: 'numeric', - hour: '2-digit', - minute: '2-digit' - })} -

+
+ E-Mail: ${safeEmail}
+ Betreff: ${safeSubject} +
+
- + + +
+
+
+ Nachricht +
+
+
+ ${safeMessageHtml} +
+
+ + +
+ + Antworten + +
+ Oder antworte direkt auf diese E-Mail. +
+
+
+ + +
+
+ Automatisch generiert von dk0.dev +
+
+
`, @@ -261,7 +280,7 @@ Nachricht: ${message} --- -Diese E-Mail wurde automatisch von deinem Portfolio generiert. +Diese E-Mail wurde automatisch von dk0.dev generiert. `, }; diff --git a/app/components/ActivityFeed.tsx b/app/components/ActivityFeed.tsx index 6061b49..d174949 100644 --- a/app/components/ActivityFeed.tsx +++ b/app/components/ActivityFeed.tsx @@ -56,9 +56,9 @@ export default function ActivityFeed() { const [hasActivity, setHasActivity] = useState(false); const [isTrackingEnabled, setIsTrackingEnabled] = useState(() => { // Check localStorage for tracking preference - if (typeof window !== 'undefined') { - const stored = localStorage.getItem('activityTrackingEnabled'); - return stored !== 'false'; // Default to true if not set + if (typeof window !== "undefined") { + const stored = localStorage.getItem("activityTrackingEnabled"); + return stored !== "false"; // Default to true if not set } return true; }); @@ -129,7 +129,8 @@ export default function ActivityFeed() { if (!hasActivity && !quote) { const techQuotes = [ { - content: "Computer Science is no more about computers than astronomy is about telescopes.", + content: + "Computer Science is no more about computers than astronomy is about telescopes.", author: "Edsger W. Dijkstra", }, { @@ -137,31 +138,38 @@ export default function ActivityFeed() { author: "Edsger W. Dijkstra", }, { - content: "The computing scientist's main challenge is not to get confused by the complexities of his own making.", + content: + "The computing scientist's main challenge is not to get confused by the complexities of his own making.", author: "Edsger W. Dijkstra", }, { - content: "If debugging is the process of removing software bugs, then programming must be the process of putting them in.", + content: + "If debugging is the process of removing software bugs, then programming must be the process of putting them in.", author: "Edsger W. Dijkstra", }, { - content: "A program is like a poem: you cannot write a poem without writing it. Yet people talk about programming as if it were a production process and measure programmer productivity in terms of number of lines of code produced. In so doing they book that number on the wrong side of the ledger: We should always refer to the number of lines of code spent.", + content: + "A program is like a poem: you cannot write a poem without writing it. Yet people talk about programming as if it were a production process and measure programmer productivity in terms of number of lines of code produced. In so doing they book that number on the wrong side of the ledger: We should always refer to the number of lines of code spent.", author: "Edsger W. Dijkstra", }, { - content: "There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.", + content: + "There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.", author: "Tony Hoare", }, { - content: "The best minds of my generation are thinking about how to make people click ads.", + content: + "The best minds of my generation are thinking about how to make people click ads.", author: "Jeff Hammerbacher", }, { - content: "The tools we use have a profound and devious influence on our thinking habits, and therefore on our thinking abilities.", + content: + "The tools we use have a profound and devious influence on our thinking habits, and therefore on our thinking abilities.", author: "Edsger W. Dijkstra", }, { - content: "How do we convince people that in programming simplicity and clarity β€” in short: what mathematicians call \"elegance\" β€” are not a dispensable luxury, but a crucial matter that decides between success and failure?", + content: + 'How do we convince people that in programming simplicity and clarity β€” in short: what mathematicians call "elegance" β€” are not a dispensable luxury, but a crucial matter that decides between success and failure?', author: "Edsger W. Dijkstra", }, { @@ -169,7 +177,8 @@ export default function ActivityFeed() { author: "Fred Brooks", }, { - content: "Sometimes there is a silver bullet for boosting software engineering productivity. But you need to shoot the right person.", + content: + "Sometimes there is a silver bullet for boosting software engineering productivity. But you need to shoot the right person.", author: "Michael Stal", }, { @@ -185,79 +194,98 @@ export default function ActivityFeed() { author: "Ken Thompson", }, { - content: "When a task cannot be partitioned because of sequential constraints, the application of more effort has no effect on the schedule. The bearing of a child takes nine months, no matter how many women are assigned.", + content: + "When a task cannot be partitioned because of sequential constraints, the application of more effort has no effect on the schedule. The bearing of a child takes nine months, no matter how many women are assigned.", author: "Fred Brooks", }, { - content: "If each part of the task must be separately coordinated with each other part, the effort increases as n(n-1)/2. Three workers require three times as much pairwise intercommunication as two; four require six times as much as two.", + content: + "If each part of the task must be separately coordinated with each other part, the effort increases as n(n-1)/2. Three workers require three times as much pairwise intercommunication as two; four require six times as much as two.", author: "Fred Brooks", }, { - content: "Having a system architect is the most important single step toward conceptual integrity. After teaching a software engineering laboratory more than 20 times, I came to insist that student teams as small as four people choose a manager and a separate architect.", + content: + "Having a system architect is the most important single step toward conceptual integrity. After teaching a software engineering laboratory more than 20 times, I came to insist that student teams as small as four people choose a manager and a separate architect.", author: "Fred Brooks", }, { - content: "The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds his castles in the air, from air, creating by exertion of the imagination. Few media of creation are so flexible, so easy to polish and rework, so readily capable of realizing grand conceptual structures.", + content: + "The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds his castles in the air, from air, creating by exertion of the imagination. Few media of creation are so flexible, so easy to polish and rework, so readily capable of realizing grand conceptual structures.", author: "Fred Brooks", }, { - content: "The first false assumption that underlies the scheduling of systems programming is that all will go well, i.e., that each task will hike only as long as it \"ought\" to take. A large programming effort, however, consists of many tasks, some chained end-to-end. The probability that each will go well becomes vanishingly small.", + content: + 'The first false assumption that underlies the scheduling of systems programming is that all will go well, i.e., that each task will hike only as long as it "ought" to take. A large programming effort, however, consists of many tasks, some chained end-to-end. The probability that each will go well becomes vanishingly small.', author: "Fred Brooks", }, { - content: "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.", + content: + "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.", author: "Donald Knuth", }, { - content: "One of my most productive days was throwing away 1,000 lines of code.", + content: + "One of my most productive days was throwing away 1,000 lines of code.", author: "Ken Thompson", }, { - content: "One accurate measurement is worth more than a thousand expert opinions.", + content: + "One accurate measurement is worth more than a thousand expert opinions.", author: "Grace Hopper", }, { - content: "What one programmer can do in one month, two programmers can do in two months.", + content: + "What one programmer can do in one month, two programmers can do in two months.", author: "Fred Brooks", }, { - content: "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.", + content: + "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.", author: "Rick Osborne", }, { - content: "A program that produces incorrect results twice as fast is infinitely slower.", + content: + "A program that produces incorrect results twice as fast is infinitely slower.", author: "John Ousterhout", }, { - content: "I have yet to see any problem, however complicated, which when looked at in the right way, did not become more complicated.", + content: + "I have yet to see any problem, however complicated, which when looked at in the right way, did not become more complicated.", author: "Poul Anderson", }, { - content: "Cleaning code does NOT take time. NOT cleaning code does take time.", + content: + "Cleaning code does NOT take time. NOT cleaning code does take time.", author: "Robert C. Martin", }, { - content: "Beauty is more important in computing than anywhere else in technology because software is so complicated. Beauty is the ultimate defense against complexity.", + content: + "Beauty is more important in computing than anywhere else in technology because software is so complicated. Beauty is the ultimate defense against complexity.", author: "David Gelernter", }, { - content: "Walking on water and developing software from a specification are easy if both are frozen.", + content: + "Walking on water and developing software from a specification are easy if both are frozen.", author: "Edward V. Berard", }, { - content: "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.", + content: + "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.", author: "Brian Kernighan", }, { - content: "Controlling complexity is the essence of computer programming.", + content: + "Controlling complexity is the essence of computer programming.", author: "Brian Kernighan", }, { - content: "Debugging time increases as a square of the program's size.", + content: + "Debugging time increases as a square of the program's size.", author: "Chris Wenham", }, { - content: "The trouble with programmers is that you can never tell what a programmer is doing until it's too late.", + content: + "The trouble with programmers is that you can never tell what a programmer is doing until it's too late.", author: "Seymour Cray", }, { @@ -265,11 +293,13 @@ export default function ActivityFeed() { author: "Ron Jeffries", }, { - content: "Some problems are so complex that you have to be highly intelligent and well informed just to be undecided about them.", + content: + "Some problems are so complex that you have to be highly intelligent and well informed just to be undecided about them.", author: "Laurence J. Peter", }, { - content: "Make a guess, double the number, and then move to the next larger unit of time. This rule scales tasks in a very interesting way: a one-minute task explodes by a factor of 120 to take two hours. A one-hour job explodes by \"only\" a factor 48 to take two days, while a one-day job grows by a factor of 14 to take two weeks.", + content: + 'Make a guess, double the number, and then move to the next larger unit of time. This rule scales tasks in a very interesting way: a one-minute task explodes by a factor of 120 to take two hours. A one-hour job explodes by "only" a factor 48 to take two days, while a one-day job grows by a factor of 14 to take two weeks.', author: "Poul-Henning Kamp", }, { @@ -277,31 +307,38 @@ export default function ActivityFeed() { author: "Albert Einstein", }, { - content: "The proper use of comments is to compensate for our failure to express ourself in code.", + content: + "The proper use of comments is to compensate for our failure to express ourself in code.", author: "Robert C. Martin", }, { - content: "When there is no type hierarchy you don't have to manage the type hierarchy.", + content: + "When there is no type hierarchy you don't have to manage the type hierarchy.", author: "Rob Pike", }, { - content: "Everybody should learn to program a computer, because it teaches you how to think.", + content: + "Everybody should learn to program a computer, because it teaches you how to think.", author: "Steve Jobs", }, { - content: "Simplicity is hard to build, easy to use, and hard to charge for. Complexity is easy to build, hard to use, and easy to charge for.", + content: + "Simplicity is hard to build, easy to use, and hard to charge for. Complexity is easy to build, hard to use, and easy to charge for.", author: "Chris Sacca", }, { - content: "Measuring programming progress by lines of code is like measuring aircraft building progress by weight.", + content: + "Measuring programming progress by lines of code is like measuring aircraft building progress by weight.", author: "Bill Gates", }, { - content: "More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity.", + content: + "More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity.", author: "William Wulf", }, { - content: "Testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence.", + content: + "Testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence.", author: "Edsger W. Dijkstra", }, { @@ -309,15 +346,18 @@ export default function ActivityFeed() { author: "Albert Einstein", }, { - content: "When I am working on a problem I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong.", + content: + "When I am working on a problem I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong.", author: "Buckminster Fuller", }, { - content: "Good code is short, simple, and symmetrical - the challenge is figuring out how to get there.", + content: + "Good code is short, simple, and symmetrical - the challenge is figuring out how to get there.", author: "Sean Parent", }, { - content: "If you think your users are idiots, only idiots will use it.", + content: + "If you think your users are idiots, only idiots will use it.", author: "Linus Torvalds", }, { @@ -329,43 +369,53 @@ export default function ActivityFeed() { author: "Kevlin Henney", }, { - content: "Over half of the time you spend working on a project is spent thinking, and no tool, no matter how advanced, can think for you.", + content: + "Over half of the time you spend working on a project is spent thinking, and no tool, no matter how advanced, can think for you.", author: "Richard P. Gabriel", }, { - content: "We could, for instance, begin with cleaning up our language by no longer calling a bug a bug but by calling it an error. It is much more honest because it squarely puts the blame where it belongs, viz. with the programmer who made the error. The animistic metaphor of the bug that maliciously sneaked in while the programmer was not looking is intellectually dishonest as it disguises that the error is the programmer's own creation. The nice thing of this simple change of vocabulary is that it has such a profound effect: while, before, a program with only one bug used to be \"almost correct\", afterwards a program with an error is just \"wrong\".", + content: + 'We could, for instance, begin with cleaning up our language by no longer calling a bug a bug but by calling it an error. It is much more honest because it squarely puts the blame where it belongs, viz. with the programmer who made the error. The animistic metaphor of the bug that maliciously sneaked in while the programmer was not looking is intellectually dishonest as it disguises that the error is the programmer\'s own creation. The nice thing of this simple change of vocabulary is that it has such a profound effect: while, before, a program with only one bug used to be "almost correct", afterwards a program with an error is just "wrong".', author: "Edsger W. Dijkstra", }, { - content: "Once a new technology starts rolling, if you're not part of the steamroller, you're part of the road.", + content: + "Once a new technology starts rolling, if you're not part of the steamroller, you're part of the road.", author: "Stewart Brand", }, { - content: "A complex system that works is invariably found to have evolved from a simple system that worked. The inverse proposition also appears to be true: A complex system designed from scratch never works and cannot be made to work.", + content: + "A complex system that works is invariably found to have evolved from a simple system that worked. The inverse proposition also appears to be true: A complex system designed from scratch never works and cannot be made to work.", author: "John Gall (author)", }, { - content: "The most amazing achievement of the computer software industry is its continuing cancellation of the steady and staggering gains made by the computer hardware industry.", + content: + "The most amazing achievement of the computer software industry is its continuing cancellation of the steady and staggering gains made by the computer hardware industry.", author: "Henry Petroski", }, { - content: "I am never satisfied until I have said as much as possible in a few words, and writing briefly takes far more time than writing at length.", + content: + "I am never satisfied until I have said as much as possible in a few words, and writing briefly takes far more time than writing at length.", author: "Carl Friedrich Gauss", }, { - content: "There are only two kinds of languages: the ones people complain about and the ones nobody uses.", + content: + "There are only two kinds of languages: the ones people complain about and the ones nobody uses.", author: "Bjarne Stroustrup", }, { - content: "The purpose of software engineering is to control complexity, not to create it.", + content: + "The purpose of software engineering is to control complexity, not to create it.", author: "Pamela Zave", }, { - content: "Unix is simple. It just takes a genius to understand its simplicity.", + content: + "Unix is simple. It just takes a genius to understand its simplicity.", author: "Dennis Ritchie", }, { - content: "A language that doesn't have everything is actually easier to program in than some that do.", + content: + "A language that doesn't have everything is actually easier to program in than some that do.", author: "Dennis Ritchie", }, { @@ -373,23 +423,28 @@ export default function ActivityFeed() { author: "Richard Feynman", }, { - content: "Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius – and a lot of courage – to move in the opposite direction.", + content: + "Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius – and a lot of courage – to move in the opposite direction.", author: "Albert Einstein", }, { - content: "There is no programming language, no matter how structured, that will prevent programmers from making bad programs.", + content: + "There is no programming language, no matter how structured, that will prevent programmers from making bad programs.", author: "Lawrence Flon", }, { - content: "Any fool can write code that a computer can understand. Good programmers write code that humans can understand.", + content: + "Any fool can write code that a computer can understand. Good programmers write code that humans can understand.", author: "Martin Fowler", }, { - content: "The problem with object-oriented languages is they've got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.", + content: + "The problem with object-oriented languages is they've got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.", author: "Joe Armstrong (programmer)", }, { - content: "You can't trust code that you did not totally create yourself.", + content: + "You can't trust code that you did not totally create yourself.", author: "Ken Thompson", }, { @@ -397,19 +452,23 @@ export default function ActivityFeed() { author: "Albert Einstein", }, { - content: "The most important single aspect of software development is to be clear about what you are trying to build.", + content: + "The most important single aspect of software development is to be clear about what you are trying to build.", author: "Bjarne Stroustrup", }, { - content: "The only sin is to make a choice without knowing you are making one.", + content: + "The only sin is to make a choice without knowing you are making one.", author: "Jonathan Shewchuk", }, { - content: "So much complexity in software comes from trying to make one thing do two things.", + content: + "So much complexity in software comes from trying to make one thing do two things.", author: "Ryan Singer", }, { - content: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.", + content: + "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.", author: "P. J. Plauger", }, { @@ -417,19 +476,23 @@ export default function ActivityFeed() { author: "John Johnson", }, { - content: "A good programmer is someone who looks both ways before crossing a one-way street.", + content: + "A good programmer is someone who looks both ways before crossing a one-way street.", author: "Doug Linder", }, { - content: "Compatibility means deliberately repeating other people's mistakes.", + content: + "Compatibility means deliberately repeating other people's mistakes.", author: "David Wheeler (computer scientist)", }, { - content: "There are two major products that come out of Berkeley: LSD and UNIX. We don't believe this to be a coincidence.", + content: + "There are two major products that come out of Berkeley: LSD and UNIX. We don't believe this to be a coincidence.", author: "Jeremy S. Anderson", }, { - content: "The competent programmer is fully aware of the strictly limited size of his own skull; therefore he approaches the programming task in full humility, and among other things he avoids clever tricks like the plague", + content: + "The competent programmer is fully aware of the strictly limited size of his own skull; therefore he approaches the programming task in full humility, and among other things he avoids clever tricks like the plague", author: "Edsger W. Dijkstra", }, { @@ -437,7 +500,8 @@ export default function ActivityFeed() { author: "Joshua Bloch", }, { - content: "I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships.", + content: + "I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships.", author: "Linus Torvalds", }, { @@ -445,15 +509,18 @@ export default function ActivityFeed() { author: "Albert Einstein", }, { - content: "Mathematicians stand on each others' shoulders and computer scientists stand on each others' toes.", + content: + "Mathematicians stand on each others' shoulders and computer scientists stand on each others' toes.", author: "Richard Hamming", }, { - content: "LISP has assisted a number of our most gifted fellow humans in thinking previously impossible thoughts.", + content: + "LISP has assisted a number of our most gifted fellow humans in thinking previously impossible thoughts.", author: "Edsger W. Dijkstra", }, { - content: "An organisation that treats its programmers as morons will soon have programmers that are willing and able to act like morons only.", + content: + "An organisation that treats its programmers as morons will soon have programmers that are willing and able to act like morons only.", author: "Bjarne Stroustrup", }, { @@ -461,39 +528,48 @@ export default function ActivityFeed() { author: "Anonymous", }, { - content: "Don't worry about anything. Just do what you can and be the best you can be.", + content: + "Don't worry about anything. Just do what you can and be the best you can be.", author: "Douglas Crockford", }, { - content: "The business of software building isn't really high-tech at all. It's most of all a business of talking to each other and writing things down.", + content: + "The business of software building isn't really high-tech at all. It's most of all a business of talking to each other and writing things down.", author: "Tom DeMarco", }, { - content: "In programming the hard part isn't solving problems, but deciding what problems to solve.", + content: + "In programming the hard part isn't solving problems, but deciding what problems to solve.", author: "Paul Graham (programmer)", }, { - content: "The manager's function is not to make people work, but to make it possible for people to work.", + content: + "The manager's function is not to make people work, but to make it possible for people to work.", author: "Tom DeMarco", }, { - content: "People under pressure don't work better; they just work faster.", + content: + "People under pressure don't work better; they just work faster.", author: "Tom DeMarco", }, { - content: "My main conclusion after spending ten years of my life working on the TEX project is that software is hard. It's harder than anything else I've ever had to do.", + content: + "My main conclusion after spending ten years of my life working on the TEX project is that software is hard. It's harder than anything else I've ever had to do.", author: "Donald Knuth", }, { - content: "Science is what we understand well enough to explain to a computer. Art is everything else we do.", + content: + "Science is what we understand well enough to explain to a computer. Art is everything else we do.", author: "Donald Knuth", }, { - content: "We have seen that computer programming is an art, because it applies accumulated knowledge to the world, because it requires skill and ingenuity, and especially because it produces objects of beauty.", + content: + "We have seen that computer programming is an art, because it applies accumulated knowledge to the world, because it requires skill and ingenuity, and especially because it produces objects of beauty.", author: "Donald Knuth", }, { - content: "Email is a wonderful thing for people whose role in life is to be on top of things. But not for me; my role is to be on the bottom of things. What I do takes long hours of studying and uninterruptible concentration.", + content: + "Email is a wonderful thing for people whose role in life is to be on top of things. But not for me; my role is to be on the bottom of things. What I do takes long hours of studying and uninterruptible concentration.", author: "Donald Knuth", }, { @@ -501,51 +577,63 @@ export default function ActivityFeed() { author: "Kevlin Henney", }, { - content: "As soon as an Analytical Engine exists, it will necessarily guide the future course of science.", + content: + "As soon as an Analytical Engine exists, it will necessarily guide the future course of science.", author: "Charles Babbage", }, { - content: "The errors which arise from the absence of facts are far more numerous and more durable than those which result from unsound reasoning respecting true data.", + content: + "The errors which arise from the absence of facts are far more numerous and more durable than those which result from unsound reasoning respecting true data.", author: "Charles Babbage", }, { - content: "We have already mentioned what may, perhaps, appear paradoxical to some of our readers, β€” that the division of labour can be applied with equal success to mental as to mechanical operations, and that it ensures in both the same economy of time.", + content: + "We have already mentioned what may, perhaps, appear paradoxical to some of our readers, β€” that the division of labour can be applied with equal success to mental as to mechanical operations, and that it ensures in both the same economy of time.", author: "Charles Babbage", }, { - content: "On two occasions I have been asked [by members of Parliament]: \"Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?\" I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question.", + content: + 'On two occasions I have been asked [by members of Parliament]: "Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?" I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question.', author: "Charles Babbage", }, { - content: "As long as there were no machines, programming was no problem at all; when we had a few weak computers, programming became a mild problem, and now we have gigantic computers, programming has become an equally gigantic problem.", + content: + "As long as there were no machines, programming was no problem at all; when we had a few weak computers, programming became a mild problem, and now we have gigantic computers, programming has become an equally gigantic problem.", author: "Edsger W. Dijkstra", }, { - content: "The use of COBOL cripples the mind; its teaching should, therefore, be regarded as a criminal offense.", + content: + "The use of COBOL cripples the mind; its teaching should, therefore, be regarded as a criminal offense.", author: "Edsger W. Dijkstra", }, { - content: "If you want more effective programmers, you will discover that they should not waste their time debugging, they should not introduce the bugs to start with.", + content: + "If you want more effective programmers, you will discover that they should not waste their time debugging, they should not introduce the bugs to start with.", author: "Edsger W. Dijkstra", }, { - content: "It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.", + content: + "It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.", author: "Edsger W. Dijkstra", }, { - content: "A picture may be worth a thousand words, a formula is worth a thousand pictures.", + content: + "A picture may be worth a thousand words, a formula is worth a thousand pictures.", author: "Edsger W. Dijkstra", }, { - content: "I mean, if 10 years from now, when you are doing something quick and dirty, you suddenly visualize that I am looking over your shoulders and say to yourself \"Dijkstra would not have liked this\", well, that would be enough immortality for me.", + content: + 'I mean, if 10 years from now, when you are doing something quick and dirty, you suddenly visualize that I am looking over your shoulders and say to yourself "Dijkstra would not have liked this", well, that would be enough immortality for me.', author: "Edsger W. Dijkstra", }, { - content: "Don't blame me for the fact that competent programming will be too difficult for \"the average programmer\" β€” you must not fall into the trap of rejecting a surgical technique because it is beyond the capabilities of the barber in his shop around the corner.", + content: + 'Don\'t blame me for the fact that competent programming will be too difficult for "the average programmer" β€” you must not fall into the trap of rejecting a surgical technique because it is beyond the capabilities of the barber in his shop around the corner.', author: "Edsger W. Dijkstra", }, { - content: "Young man, in mathematics you don't understand things. You just get used to them.", + content: + "Young man, in mathematics you don't understand things. You just get used to them.", author: "John von Neumann", }, { @@ -553,31 +641,38 @@ export default function ActivityFeed() { author: "Dennis Ritchie", }, { - content: "It is not the task of the University to offer what society asks for, but to give what society needs.", + content: + "It is not the task of the University to offer what society asks for, but to give what society needs.", author: "Edsger W. Dijkstra", }, { - content: "By understanding a machine-oriented language, the programmer will tend to use a much more efficient method; it is much closer to reality.", + content: + "By understanding a machine-oriented language, the programmer will tend to use a much more efficient method; it is much closer to reality.", author: "Donald Knuth", }, { - content: "Another danger is that commercial pressures of one sort or another will divert the attention of the best thinkers from real innovation to exploitation of the current fad, from prospecting to mining a known lode.", + content: + "Another danger is that commercial pressures of one sort or another will divert the attention of the best thinkers from real innovation to exploitation of the current fad, from prospecting to mining a known lode.", author: "Dennis Ritchie", }, { - content: "Within C++, there is a much smaller and cleaner language struggling to get out.", + content: + "Within C++, there is a much smaller and cleaner language struggling to get out.", author: "Bjarne Stroustrup", }, { - content: "Anybody who comes to you and says he has a perfect language is either naΓ―ve or a salesman.", + content: + "Anybody who comes to you and says he has a perfect language is either naΓ―ve or a salesman.", author: "Bjarne Stroustrup", }, { - content: "A man provided with paper, pencil, and rubber, and subject to strict discipline, is in effect a universal machine.", + content: + "A man provided with paper, pencil, and rubber, and subject to strict discipline, is in effect a universal machine.", author: "Alan Turing", }, { - content: "The idea behind digital computers may be explained by saying that these machines are intended to carry out any operations which could be done by a human computer.", + content: + "The idea behind digital computers may be explained by saying that these machines are intended to carry out any operations which could be done by a human computer.", author: "Alan Turing", }, { @@ -585,31 +680,38 @@ export default function ActivityFeed() { author: "Alan Turing", }, { - content: "Maybe \"just one little global variable\" isn't too unmanageable, but that style leads to code that is useless except to its original programmer.", + content: + 'Maybe "just one little global variable" isn\'t too unmanageable, but that style leads to code that is useless except to its original programmer.', author: "Bjarne Stroustrup", }, { - content: "I'm doing a free operating system (just a hobby, won't be big and professional like GNU).", + content: + "I'm doing a free operating system (just a hobby, won't be big and professional like GNU).", author: "Linus Torvalds", }, { - content: "If you need more than 3 levels of indentation, you're screwed anyway, and should fix your program.", + content: + "If you need more than 3 levels of indentation, you're screwed anyway, and should fix your program.", author: "Linus Torvalds", }, { - content: "An infinite number of monkeys typing into GNU Emacs would never make a good program.", + content: + "An infinite number of monkeys typing into GNU Emacs would never make a good program.", author: "Linus Torvalds", }, { - content: "If Microsoft ever does applications for Linux it means I've won.", + content: + "If Microsoft ever does applications for Linux it means I've won.", author: "Linus Torvalds", }, { - content: "See, you not only have to be a good coder to create a system like Linux, you have to be a sneaky bastard too ;-)", + content: + "See, you not only have to be a good coder to create a system like Linux, you have to be a sneaky bastard too ;-)", author: "Linus Torvalds", }, { - content: "Really, I'm not out to destroy Microsoft. That will just be a completely unintentional side effect.", + content: + "Really, I'm not out to destroy Microsoft. That will just be a completely unintentional side effect.", author: "Linus Torvalds", }, { @@ -617,111 +719,138 @@ export default function ActivityFeed() { author: "Linus Torvalds", }, { - content: "The first 90 percent of the code accounts for the first 90 percent of the development time. The remaining 10 percent of the code accounts for the other 90 percent of the development time.", + content: + "The first 90 percent of the code accounts for the first 90 percent of the development time. The remaining 10 percent of the code accounts for the other 90 percent of the development time.", author: "Tom Cargill", }, { - content: "I'm not a great programmer; I'm just a good programmer with great habits.", + content: + "I'm not a great programmer; I'm just a good programmer with great habits.", author: "Kent Beck", }, { - content: "There's only one trick in software, and that is using a piece of software that's already been written.", + content: + "There's only one trick in software, and that is using a piece of software that's already been written.", author: "Bill Gates", }, { - content: "You can't just ask customers what they want and then try to give that to them. By the time you get it built, they'll want something new.", + content: + "You can't just ask customers what they want and then try to give that to them. By the time you get it built, they'll want something new.", author: "Steve Jobs", }, { - content: "What a computer is to me is it's the most remarkable tool that we have ever come up with. It's the equivalent of a bicycle for our minds.", + content: + "What a computer is to me is it's the most remarkable tool that we have ever come up with. It's the equivalent of a bicycle for our minds.", author: "Steve Jobs", }, { - content: "Programming, it turns out, is hard. The fundamental rules are typically simple and clear. But programs built on top of these rules tend to become complex enough to introduce their own rules and complexity. You're building your own maze, in a way, and you might just get lost in it.", + content: + "Programming, it turns out, is hard. The fundamental rules are typically simple and clear. But programs built on top of these rules tend to become complex enough to introduce their own rules and complexity. You're building your own maze, in a way, and you might just get lost in it.", author: "Marijn Haverbeke", }, { - content: "I'm convinced that about half of what separates the successful entrepreneurs from the non-successful ones is pure perseverance. It is so hard.", + content: + "I'm convinced that about half of what separates the successful entrepreneurs from the non-successful ones is pure perseverance. It is so hard.", author: "Steve Jobs", }, { - content: "A lot of companies hire people to tell them what to do. We hire people to tell us what to do.", + content: + "A lot of companies hire people to tell them what to do. We hire people to tell us what to do.", author: "Steve Jobs", }, { - content: "Computers themselves can do only stupidly straightforward things. The reason they are so useful is that they do these things at an incredibly high speed.", + content: + "Computers themselves can do only stupidly straightforward things. The reason they are so useful is that they do these things at an incredibly high speed.", author: "Marijn Haverbeke", }, { - content: "A program is a building of thought. It is costless to build, it is weightless, and it grows easily under our typing hands. But without care, a program's size and complexity will grow out of control, confusing even the person who created it.", + content: + "A program is a building of thought. It is costless to build, it is weightless, and it grows easily under our typing hands. But without care, a program's size and complexity will grow out of control, confusing even the person who created it.", author: "Marijn Haverbeke", }, { - content: "There are many terrible mistakes to make in program design, so go ahead and make them so that you understand them better.", + content: + "There are many terrible mistakes to make in program design, so go ahead and make them so that you understand them better.", author: "Marijn Haverbeke", }, { - content: "People think that computer science is the art of geniuses but the actual reality is the opposite, just many people doing things that build on each other, like a wall of mini stones.", + content: + "People think that computer science is the art of geniuses but the actual reality is the opposite, just many people doing things that build on each other, like a wall of mini stones.", author: "Donald Knuth", }, { - content: "Professionalism has no place in art, and hacking is art. Software Engineering might be science; but that's not what I do. I'm a hacker, not an engineer.", + content: + "Professionalism has no place in art, and hacking is art. Software Engineering might be science; but that's not what I do. I'm a hacker, not an engineer.", author: "Jamie Zawinski", }, { - content: "We who cut mere stones must always be envisioning cathedrals.", + content: + "We who cut mere stones must always be envisioning cathedrals.", author: "Quarry worker's creed", }, { - content: "Communication must be stateless in nature, such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server.", + content: + "Communication must be stateless in nature, such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server.", author: "Roy Fielding", }, { - content: "When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.", + content: + "When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.", author: "Kent Beck", }, { - content: "When you find you have to add a feature to a program, and the program's code is not structured in a convenient way to add the feature, first refactor the program to make it easy to add the feature, then add the feature.", + content: + "When you find you have to add a feature to a program, and the program's code is not structured in a convenient way to add the feature, first refactor the program to make it easy to add the feature, then add the feature.", author: "Kent Beck", }, { - content: "It turns out that style matters in programming for the same reason that it matters in writing. It makes for better reading.", + content: + "It turns out that style matters in programming for the same reason that it matters in writing. It makes for better reading.", author: "Douglas Crockford", }, { - content: "Computer programs are the most complex things that humans make.", + content: + "Computer programs are the most complex things that humans make.", author: "Douglas Crockford", }, { - content: "Most programming languages contain good parts and bad parts. I discovered that I could be better programmer by using only the good parts and avoiding the bad parts.", + content: + "Most programming languages contain good parts and bad parts. I discovered that I could be better programmer by using only the good parts and avoiding the bad parts.", author: "Douglas Crockford", }, { - content: "Good architecture is necessary to give programs enough structure to be able to grow large without collapsing into a puddle of confusion.", + content: + "Good architecture is necessary to give programs enough structure to be able to grow large without collapsing into a puddle of confusion.", author: "Douglas Crockford", }, { - content: "JavaScript is the world's most misunderstood programming language.", + content: + "JavaScript is the world's most misunderstood programming language.", author: "Douglas Crockford", }, { - content: "In JavaScript, there is a beautiful, elegant, highly expressive language that is buried under a steaming pile of good intentions and blunders.", + content: + "In JavaScript, there is a beautiful, elegant, highly expressive language that is buried under a steaming pile of good intentions and blunders.", author: "Douglas Crockford", }, { - content: "Software is usually expected to be modified over the course of its productive life. The process of converting one correct program into a different correct program is extremely challenging.", + content: + "Software is usually expected to be modified over the course of its productive life. The process of converting one correct program into a different correct program is extremely challenging.", author: "Douglas Crockford", }, { - content: "Every good work of software starts by scratching a developer's personal itch.", + content: + "Every good work of software starts by scratching a developer's personal itch.", author: "Eric S. Raymond", }, { - content: "You can have the project: Done On Time. Done On Budget. Done Properly - Pick two.", + content: + "You can have the project: Done On Time. Done On Budget. Done Properly - Pick two.", author: "Anonymous", }, { - content: "No one in the brief history of computing has ever written a piece of perfect software. It's unlikely that you'll be the first.", + content: + "No one in the brief history of computing has ever written a piece of perfect software. It's unlikely that you'll be the first.", author: "Andy Hunt (author)", }, { @@ -733,7 +862,8 @@ export default function ActivityFeed() { author: "Alan Kay", }, { - content: "If you can get today's work done today, but you do it in such a way that you can't possibly get tomorrow's work done tomorrow, then you lose.", + content: + "If you can get today's work done today, but you do it in such a way that you can't possibly get tomorrow's work done tomorrow, then you lose.", author: "Martin Fowler", }, { @@ -741,7 +871,8 @@ export default function ActivityFeed() { author: "Alan Turing", }, { - content: "Documentation is a love letter that you write to your future self.", + content: + "Documentation is a love letter that you write to your future self.", author: "Damian Conway", }, { @@ -749,15 +880,18 @@ export default function ActivityFeed() { author: "Bdale Garbee", }, { - content: "W​henever I have to think to understand what the code is doing, I ask myself if I can refactor the code to make that understanding more immediately apparent.", + content: + "W​henever I have to think to understand what the code is doing, I ask myself if I can refactor the code to make that understanding more immediately apparent.", author: "Martin Fowler", }, { - content: "If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime.", + content: + "If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime.", author: "David Leinweber", }, { - content: "The code you write makes you a programmer. The code you delete makes you a good one. The code you don't have to write makes you a great one.", + content: + "The code you write makes you a programmer. The code you delete makes you a good one. The code you don't have to write makes you a great one.", author: "Mario Fusco", }, { @@ -765,35 +899,43 @@ export default function ActivityFeed() { author: "Addy Osmani", }, { - content: "The cost of adding a feature isn't just the time it takes to code it. The cost also includes the addition of an obstacle to future expansion. The trick is to pick the features that don't fight each other.", + content: + "The cost of adding a feature isn't just the time it takes to code it. The cost also includes the addition of an obstacle to future expansion. The trick is to pick the features that don't fight each other.", author: "John Carmack", }, { - content: "First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack.", + content: + "First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack.", author: "George Carrette", }, { - content: "Just because people tell you it can't be done, that doesn't necessarily mean that it can't be done. It just means that they can't do it.", + content: + "Just because people tell you it can't be done, that doesn't necessarily mean that it can't be done. It just means that they can't do it.", author: "Anders Hejlsberg", }, { - content: "The only way to learn a new programming language is by writing programs in it.", + content: + "The only way to learn a new programming language is by writing programs in it.", author: "Dennis Ritchie", }, { - content: "An evolving system increases its complexity unless work is done to reduce it.", + content: + "An evolving system increases its complexity unless work is done to reduce it.", author: "Manny Lehman (computer scientist)", }, { - content: "No matter how slow you are writing clean code, you will always be slower if you make a mess.", + content: + "No matter how slow you are writing clean code, you will always be slower if you make a mess.", author: "Robert C. Martin", }, { - content: "Fancy algorithms are slow when n is small, and n is usually small.", + content: + "Fancy algorithms are slow when n is small, and n is usually small.", author: "Rob Pike", }, { - content: "The only difference between a FA [finite automata] and a TM [Turing machine] is that the TM, unlike the FA, has paper and pencil. Think about it. It tells you something about the power of writing.", + content: + "The only difference between a FA [finite automata] and a TM [Turing machine] is that the TM, unlike the FA, has paper and pencil. Think about it. It tells you something about the power of writing.", author: "Manuel Blum", }, { @@ -801,19 +943,23 @@ export default function ActivityFeed() { author: "Alan Perlis", }, { - content: "Just because you've implemented something doesn't mean you understand it.", + content: + "Just because you've implemented something doesn't mean you understand it.", author: "Brian Cantwell Smith", }, { - content: "That hardly ever happens is another way of saying 'it happens'.", + content: + "That hardly ever happens is another way of saying 'it happens'.", author: "Douglas Crockford", }, { - content: "Beware of bugs in the above code; I have only proved it correct, not tried it.", + content: + "Beware of bugs in the above code; I have only proved it correct, not tried it.", author: "Donald Knuth", }, { - content: "A display connected to a digital computer gives us a chance to gain familiarity with concepts not realizable in the physical world. It is a looking glass into a mathematical wonderland.", + content: + "A display connected to a digital computer gives us a chance to gain familiarity with concepts not realizable in the physical world. It is a looking glass into a mathematical wonderland.", author: "Ivan Sutherland", }, { @@ -821,11 +967,13 @@ export default function ActivityFeed() { author: "Ralph Johnson (computer scientist)", }, { - content: "The cheapest, fastest, and most reliable components are those that aren't there.", + content: + "The cheapest, fastest, and most reliable components are those that aren't there.", author: "Gordon Bell", }, { - content: "In order to understand recursion, one must first understand recursion.", + content: + "In order to understand recursion, one must first understand recursion.", author: "Anonymous", }, { @@ -837,7 +985,8 @@ export default function ActivityFeed() { author: "Luciano Ramalho", }, { - content: "Much of the essence of building a program is in fact the debugging of the specification.", + content: + "Much of the essence of building a program is in fact the debugging of the specification.", author: "Fred Brooks", }, { @@ -845,19 +994,23 @@ export default function ActivityFeed() { author: "Elon Musk", }, { - content: "The act of describing a program in unambiguous detail and the act of programming are one and the same.", + content: + "The act of describing a program in unambiguous detail and the act of programming are one and the same.", author: "Kevlin Henney", }, { - content: "I think you should always bear in mind that entropy is not on your side.", + content: + "I think you should always bear in mind that entropy is not on your side.", author: "Elon Musk", }, { - content: "The path to the CEO's office should not be through the CFO's office, and it should not be through the marketing department. It needs to be through engineering and design.", + content: + "The path to the CEO's office should not be through the CFO's office, and it should not be through the marketing department. It needs to be through engineering and design.", author: "Elon Musk", }, { - content: "People are mistaken when they think that technology just automatically improves. It does not automatically improve. It only improves if a lot of people work very hard to make it better, and actually it will, I think, by itself degrade, actually.", + content: + "People are mistaken when they think that technology just automatically improves. It does not automatically improve. It only improves if a lot of people work very hard to make it better, and actually it will, I think, by itself degrade, actually.", author: "Elon Musk", }, { @@ -865,11 +1018,13 @@ export default function ActivityFeed() { author: "Elon Musk", }, { - content: "AI is a fundamental risk to the existence of human civilization.", + content: + "AI is a fundamental risk to the existence of human civilization.", author: "Elon Musk", }, { - content: "The main activity of programming is not the origination of new independent programs, but in the integration, modification, and explanation of existing ones.", + content: + "The main activity of programming is not the origination of new independent programs, but in the integration, modification, and explanation of existing ones.", author: "Terry Winograd", }, { @@ -877,187 +1032,233 @@ export default function ActivityFeed() { author: "Tim Berners-Lee", }, { - content: "I don't believe in the sort of eureka moment idea. I think it's a myth. I'm very suspicious that actually Archimedes had been thinking about that problem for a long time.", + content: + "I don't believe in the sort of eureka moment idea. I think it's a myth. I'm very suspicious that actually Archimedes had been thinking about that problem for a long time.", author: "Tim Berners-Lee", }, { - content: "When I invented the web, I didn't have to ask anyone's permission.", + content: + "When I invented the web, I didn't have to ask anyone's permission.", author: "Tim Berners-Lee", }, { - content: "We need to be super careful with AI. Potentially more dangerous than nukes.", + content: + "We need to be super careful with AI. Potentially more dangerous than nukes.", author: "Elon Musk", }, { - content: "I invented the Web just because I needed it, really, because it was so frustrating that it didn't exit.", + content: + "I invented the Web just because I needed it, really, because it was so frustrating that it didn't exit.", author: "Tim Berners-Lee", }, { - content: "To be a hacker - when I use the term - is somebody who is creative and does wonderful things.", + content: + "To be a hacker - when I use the term - is somebody who is creative and does wonderful things.", author: "Tim Berners-Lee", }, { - content: "The Domain Name Server (DNS) is the Achilles heel of the Web.", + content: + "The Domain Name Server (DNS) is the Achilles heel of the Web.", author: "Tim Berners-Lee", }, { - content: "Two centuries ago Leibnitz invented a calculating machine which embodied most of the essential features of recent keyboard devices, but it could not then come into use. The economics of the situation were against it.", + content: + "Two centuries ago Leibnitz invented a calculating machine which embodied most of the essential features of recent keyboard devices, but it could not then come into use. The economics of the situation were against it.", author: "Vannevar Bush", }, { - content: "Whenever logical processes of thought are employed, there is an opportunity for the machine.", + content: + "Whenever logical processes of thought are employed, there is an opportunity for the machine.", author: "Vannevar Bush", }, { - content: "If scientific reasoning were limited to the logical processes of arithmetic, we should not get very far in our understanding of the physical world. One might as well attempt to grasp the game of poker entirely by the use of the mathematics of probability.", + content: + "If scientific reasoning were limited to the logical processes of arithmetic, we should not get very far in our understanding of the physical world. One might as well attempt to grasp the game of poker entirely by the use of the mathematics of probability.", author: "Vannevar Bush", }, { - content: "Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite. The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the technical debt load.", + content: + "Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite. The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the technical debt load.", author: "Ward Cunningham", }, { - content: "Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development because of the quick and dirty design choice.", + content: + "Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development because of the quick and dirty design choice.", author: "Martin Fowler", }, { - content: "One of the important implications of technical debt is that it must be serviced. If the debt grows large enough, eventually the company will spend more on servicing its debt than it invests in increasing the value of its other assets.", + content: + "One of the important implications of technical debt is that it must be serviced. If the debt grows large enough, eventually the company will spend more on servicing its debt than it invests in increasing the value of its other assets.", author: "Steve McConnell", }, { - content: "What's very important from my point of view is that there is one web. Anyone that tries to chop it into two will find that their piece looks very boring.", + content: + "What's very important from my point of view is that there is one web. Anyone that tries to chop it into two will find that their piece looks very boring.", author: "Tim Berners-Lee", }, { - content: "Thus it is observable that the buildings which a single architect has planned and executed, are generally more elegant and commodious than those which several have attempted to improve.", + content: + "Thus it is observable that the buildings which a single architect has planned and executed, are generally more elegant and commodious than those which several have attempted to improve.", author: "RenΓ© Descartes", }, { - content: "Computers are the most complex objects we human beings have ever created, but in a fundamental sense they are remarkably simple.", + content: + "Computers are the most complex objects we human beings have ever created, but in a fundamental sense they are remarkably simple.", author: "Danny Hillis", }, { - content: "The magic of a computer lies in its ability to become almost anything you can imagine, as long as you can explain exactly what that is.", + content: + "The magic of a computer lies in its ability to become almost anything you can imagine, as long as you can explain exactly what that is.", author: "Danny Hillis", }, { - content: "The computer is not just an advanced calculator or camera or paintbrush; rather, it is a device that accelerates and extends our processes of thought.", + content: + "The computer is not just an advanced calculator or camera or paintbrush; rather, it is a device that accelerates and extends our processes of thought.", author: "Danny Hillis", }, { - content: "With the right programming, a computer can become a theater, a musical instrument, a reference book, a chess opponent. No other entity in the world except a human being has such an adaptable, universal nature.", + content: + "With the right programming, a computer can become a theater, a musical instrument, a reference book, a chess opponent. No other entity in the world except a human being has such an adaptable, universal nature.", author: "Danny Hillis", }, { - content: "Anyone who has ever written a program knows that telling a computer what you want it to do is not as easy as it sounds. Every detail of the computer's desired operation must be precisely described. For instance, if you tell an accounting program to bill your clients for the amount that each owes, then the computer will send out a weekly bill for $0.00 to clients who owe nothing.", + content: + "Anyone who has ever written a program knows that telling a computer what you want it to do is not as easy as it sounds. Every detail of the computer's desired operation must be precisely described. For instance, if you tell an accounting program to bill your clients for the amount that each owes, then the computer will send out a weekly bill for $0.00 to clients who owe nothing.", author: "Danny Hillis", }, { - content: "A skilled programmer is like a poet who can put into words those ideas that others find inexpressible.", + content: + "A skilled programmer is like a poet who can put into words those ideas that others find inexpressible.", author: "Danny Hillis", }, { - content: "Every computer language has its Shakespeares, and it is a joy to read their code. A well-written computer program possesses style, finesse, even humorβ€”and a clarity that rivals the best prose.", + content: + "Every computer language has its Shakespeares, and it is a joy to read their code. A well-written computer program possesses style, finesse, even humorβ€”and a clarity that rivals the best prose.", author: "Danny Hillis", }, { - content: "It turns out that there is no algorithm for examining a program and determining whether or not it is fatally infected with an endless loop. Moreover, it's not that no one has yet discovered such an algorithm; rather, no such algorithm is possible.", + content: + "It turns out that there is no algorithm for examining a program and determining whether or not it is fatally infected with an endless loop. Moreover, it's not that no one has yet discovered such an algorithm; rather, no such algorithm is possible.", author: "Danny Hillis", }, { - content: "The class of problems that are computable by a digital computer apparently includes every problem that is computable by any kind of device.", + content: + "The class of problems that are computable by a digital computer apparently includes every problem that is computable by any kind of device.", author: "Danny Hillis", }, { - content: "The programs we use to conjure processes are like a sorcerer's spells. They are carefully composed from symbolic expressions in arcane and esoteric programming languages that prescribe the tasks we want our processes to perform.", + content: + "The programs we use to conjure processes are like a sorcerer's spells. They are carefully composed from symbolic expressions in arcane and esoteric programming languages that prescribe the tasks we want our processes to perform.", author: "Hal Abelson", }, { - content: "Human beings are not accustomed to being perfect, and few areas of human activity demand it. Adjusting to the requirement for perfection is, I think, the most difficult part of learning to program.", + content: + "Human beings are not accustomed to being perfect, and few areas of human activity demand it. Adjusting to the requirement for perfection is, I think, the most difficult part of learning to program.", author: "Fred Brooks", }, { - content: "Because of optimism, we usually expect the number of bugs to be smaller than it turns out to be. Therefore testing is usually the most mis-scheduled part of programming.", + content: + "Because of optimism, we usually expect the number of bugs to be smaller than it turns out to be. Therefore testing is usually the most mis-scheduled part of programming.", author: "Fred Brooks", }, { - content: "One of the greatest joys in computer programming is discovering a new, faster, more efficient algorithm for doing something β€” particularly if a lot of well-respected people have come up with worse solutions.", + content: + "One of the greatest joys in computer programming is discovering a new, faster, more efficient algorithm for doing something β€” particularly if a lot of well-respected people have come up with worse solutions.", author: "Danny Hillis", }, { - content: "False scheduling to match the patron's desired date is much more common in our discipline than elsewhere in engineering.", + content: + "False scheduling to match the patron's desired date is much more common in our discipline than elsewhere in engineering.", author: "Fred Brooks", }, { - content: "The best programmers are up to 28 times better than the worst programmers, according to \"individual differences\" research. Given that their pay is never commensurate, they are the biggest bargains in the software field.", + content: + 'The best programmers are up to 28 times better than the worst programmers, according to "individual differences" research. Given that their pay is never commensurate, they are the biggest bargains in the software field.', author: "Robert L. Glass", }, { - content: "Sackman, Erickson, and Grant were measuring performance of a group of experienced programmers. Within just this group the ratios between the best and worst performances averaged about 10:1 on productivity measurements and an amazing 5:1 on program speed and space measurements!", + content: + "Sackman, Erickson, and Grant were measuring performance of a group of experienced programmers. Within just this group the ratios between the best and worst performances averaged about 10:1 on productivity measurements and an amazing 5:1 on program speed and space measurements!", author: "Fred Brooks", }, { - content: "Conceptual integrity is the most important consideration in system design. It is better to have a system omit certain anomalous features and improvements, but to reflect one set of design ideas, than to have one that contains many good but independent and uncoordinated ideas.", + content: + "Conceptual integrity is the most important consideration in system design. It is better to have a system omit certain anomalous features and improvements, but to reflect one set of design ideas, than to have one that contains many good but independent and uncoordinated ideas.", author: "Fred Brooks", }, { - content: "The separation of architectural effort from implementation is a very powerful way of getting conceptual integrity on very large projects.", + content: + "The separation of architectural effort from implementation is a very powerful way of getting conceptual integrity on very large projects.", author: "Fred Brooks", }, { - content: "The general tendency is to over-design the second system, using all the ideas and frills that were cautiously sidetracked on the first one.", + content: + "The general tendency is to over-design the second system, using all the ideas and frills that were cautiously sidetracked on the first one.", author: "Fred Brooks", }, { - content: "The management question, therefore, is not whether to build a pilot system and throw it away. You will do that. The only question is whether to plan in advance to build a throwaway, or to promise to deliver the throwaway to customers.", + content: + "The management question, therefore, is not whether to build a pilot system and throw it away. You will do that. The only question is whether to plan in advance to build a throwaway, or to promise to deliver the throwaway to customers.", author: "Fred Brooks", }, { - content: "Program building is an entropy-decreasing process, hence inherently metastable. Program maintenance is an entropy-increasing process, and even its most skillful execution only delays the subsidence of the system into unfixable obsolescence.", + content: + "Program building is an entropy-decreasing process, hence inherently metastable. Program maintenance is an entropy-increasing process, and even its most skillful execution only delays the subsidence of the system into unfixable obsolescence.", author: "Fred Brooks", }, { - content: "Chemical engineers learned long ago that a process that works in the laboratory cannot be implemented in a factory in only one step.", + content: + "Chemical engineers learned long ago that a process that works in the laboratory cannot be implemented in a factory in only one step.", author: "Fred Brooks", }, { - content: "First, we must observe that the anomaly is not that software progress is so slow but that computer hardware progress is so fast. No other technology since civilization began has seen six orders of magnitude price-performance gain in 30 years.", + content: + "First, we must observe that the anomaly is not that software progress is so slow but that computer hardware progress is so fast. No other technology since civilization began has seen six orders of magnitude price-performance gain in 30 years.", author: "Fred Brooks", }, { - content: "Coding is \"90 percent finished\" for half of the total coding time. Debugging is \"99 percent complete\" most of the time.", + content: + 'Coding is "90 percent finished" for half of the total coding time. Debugging is "99 percent complete" most of the time.', author: "Fred Brooks", }, { - content: "The complexity of software is an essential property, not an accidental one. Hence descriptions of a software entity that abstract away its complexity often abstract away its essence.", + content: + "The complexity of software is an essential property, not an accidental one. Hence descriptions of a software entity that abstract away its complexity often abstract away its essence.", author: "Fred Brooks", }, { - content: "Study after study shows that the very best designers produce structures that are faster, smaller, simpler, cleaner, and produced with less effort. The differences between the great and the average approach an order of magnitude.", + content: + "Study after study shows that the very best designers produce structures that are faster, smaller, simpler, cleaner, and produced with less effort. The differences between the great and the average approach an order of magnitude.", author: "Fred Brooks", }, { - content: "A programming systems product takes about nine times as much effort as the component programs written separately for private use.", + content: + "A programming systems product takes about nine times as much effort as the component programs written separately for private use.", author: "Fred Brooks", }, { - content: "My rule of thumb is 1/3 of the schedule for design, 1/6 for coding, 1/4 for component testing, and 1/4 for system testing.", + content: + "My rule of thumb is 1/3 of the schedule for design, 1/6 for coding, 1/4 for component testing, and 1/4 for system testing.", author: "Fred Brooks", }, { - content: "First, my wife, my colleagues, and my editors find me to err far more often in optimism than in pessimism. I am, after all, a programmer by background, and optimism is an occupational disease of our craft.", + content: + "First, my wife, my colleagues, and my editors find me to err far more often in optimism than in pessimism. I am, after all, a programmer by background, and optimism is an occupational disease of our craft.", author: "Fred Brooks", }, { - content: "Because we are uncertain about our scheduling estimates, we often lack the courage to defend them stubbornly against management and customer pressure.", + content: + "Because we are uncertain about our scheduling estimates, we often lack the courage to defend them stubbornly against management and customer pressure.", author: "Fred Brooks", }, { - content: "Adding people to a software project increases the total effort necessary in three ways: the work and disruption of repartitioning itself, training the new people, and added intercommunication.", + content: + "Adding people to a software project increases the total effort necessary in three ways: the work and disruption of repartitioning itself, training the new people, and added intercommunication.", author: "Fred Brooks", }, { - content: "Very good professional programmers are ten times as productive as poor ones, at same training and two-year experience level.", + content: + "Very good professional programmers are ten times as productive as poor ones, at same training and two-year experience level.", author: "Fred Brooks", }, { @@ -1065,93 +1266,115 @@ export default function ActivityFeed() { author: "Fred Brooks", }, { - content: "All repairs tend to destroy structure, to increase the entropy and disorder of a system.", + content: + "All repairs tend to destroy structure, to increase the entropy and disorder of a system.", author: "Fred Brooks", }, { - content: "To achieve conceptual integrity, a design must proceed from one mind or a small group of agreeing minds.", + content: + "To achieve conceptual integrity, a design must proceed from one mind or a small group of agreeing minds.", author: "Fred Brooks", }, { - content: "The very best technology never has as much impact as girlfriend or boyfriend trouble.", + content: + "The very best technology never has as much impact as girlfriend or boyfriend trouble.", author: "Tom DeMarco", }, { - content: "Maintenance cost is strongly affected by the number of users. More users find more bugs.", + content: + "Maintenance cost is strongly affected by the number of users. More users find more bugs.", author: "Fred Brooks", }, { - content: "Most errors are introduced during requirements specification!", + content: + "Most errors are introduced during requirements specification!", author: "Daniel T. Barry", }, { - content: "Programming is similar to a game of golf. The point is not getting the ball in the hole but how many strokes it takes.", + content: + "Programming is similar to a game of golf. The point is not getting the ball in the hole but how many strokes it takes.", author: "Harlan Mills", }, { - content: "A number of studies have shown testing not very effective at finding bugs.", + content: + "A number of studies have shown testing not very effective at finding bugs.", author: "Daniel T. Barry", }, { - content: "The key to keeping software costs down is to write code that is easily modified.", + content: + "The key to keeping software costs down is to write code that is easily modified.", author: "Daniel T. Barry", }, { - content: "The notions of correctness in mathematics and programs are different. A mathematical model must be consistent; it need not match reality (be correct), and it need not be complete (in the formal sense). A program model must be consistent; it must match reality; and it must be complete (in the sense that it reacts gracefully to all inputs).", + content: + "The notions of correctness in mathematics and programs are different. A mathematical model must be consistent; it need not match reality (be correct), and it need not be complete (in the formal sense). A program model must be consistent; it must match reality; and it must be complete (in the sense that it reacts gracefully to all inputs).", author: "Daniel T. Barry", }, { - content: "Programming is at least as difficult as developing a mathematical theory.", + content: + "Programming is at least as difficult as developing a mathematical theory.", author: "Daniel T. Barry", }, { - content: "In 1971 when I joined the staff of the MIT Artificial Intelligence lab, all of us who helped develop the operating system software, we called ourselves hackers. We were not breaking any laws, at least not in doing the hacking we were paid to do. We were developing software and we were having fun. Hacking refers to the spirit of fun in which we were developing software.", + content: + "In 1971 when I joined the staff of the MIT Artificial Intelligence lab, all of us who helped develop the operating system software, we called ourselves hackers. We were not breaking any laws, at least not in doing the hacking we were paid to do. We were developing software and we were having fun. Hacking refers to the spirit of fun in which we were developing software.", author: "Richard Stallman", }, { - content: "By June 1949 people had begun to realize that it was not so easy to get programs right as at one time appeared.", + content: + "By June 1949 people had begun to realize that it was not so easy to get programs right as at one time appeared.", author: "Maurice Wilkes", }, { - content: "Everything should be made as simple as possible. But to do that you have to master complexity.", + content: + "Everything should be made as simple as possible. But to do that you have to master complexity.", author: "Butler Lampson", }, { - content: "If I had followed my heart instead of advice, dBASE would be much closer to perfection today.", + content: + "If I had followed my heart instead of advice, dBASE would be much closer to perfection today.", author: "Wayne Ratliff", }, { - content: "Programming is a little bit like the army. Now that I'm out, it's neat to have had the experience.", + content: + "Programming is a little bit like the army. Now that I'm out, it's neat to have had the experience.", author: "Wayne Ratliff", }, { - content: "I don't like using any tools or programs I didn't write myself or that I don't have some control over.", + content: + "I don't like using any tools or programs I didn't write myself or that I don't have some control over.", author: "Jonathan Sachs", }, { - content: "If you cannot explain a program to yourself, the chance of the computer getting it right is pretty small.", + content: + "If you cannot explain a program to yourself, the chance of the computer getting it right is pretty small.", author: "Bob Frankston", }, { - content: "I don't comment on the code itself because I feel that properly written code is very much self-documented.", + content: + "I don't comment on the code itself because I feel that properly written code is very much self-documented.", author: "Gary Kildall", }, { - content: "When a program is clean and neat, nicely structured, and consistent, it can be beautiful.", + content: + "When a program is clean and neat, nicely structured, and consistent, it can be beautiful.", author: "Gary Kildall", }, { - content: "JavaScript, purely by accident, has become the most popular programming language in the world.", + content: + "JavaScript, purely by accident, has become the most popular programming language in the world.", author: "Douglas Crockford", }, { - content: "Software is a discipline of detail, and that is a deep, horrendous fundamental problem with software.", + content: + "Software is a discipline of detail, and that is a deep, horrendous fundamental problem with software.", author: "L. Peter Deutsch", }, { - content: "Even in the games of children there are things to interest the greatest mathematician.", + content: + "Even in the games of children there are things to interest the greatest mathematician.", author: "Gottfried Wilhelm Leibniz", - } + }, ]; setQuote(techQuotes[Math.floor(Math.random() * techQuotes.length)]); } @@ -1161,8 +1384,8 @@ export default function ActivityFeed() { const toggleTracking = () => { const newValue = !isTrackingEnabled; setIsTrackingEnabled(newValue); - if (typeof window !== 'undefined') { - localStorage.setItem('activityTrackingEnabled', String(newValue)); + if (typeof window !== "undefined") { + localStorage.setItem("activityTrackingEnabled", String(newValue)); } // Clear data when disabling if (!newValue) { @@ -1173,7 +1396,7 @@ export default function ActivityFeed() { // Don't render if tracking is disabled and no data if (!isTrackingEnabled && !data) return null; - + // If tracking disabled but we have data, show a disabled state if (!isTrackingEnabled && data) { return ( @@ -1216,8 +1439,7 @@ export default function ActivityFeed() {

Loading...

-
-
+
@@ -1256,7 +1478,7 @@ export default function ActivityFeed() { {/* Main Container */} {/* Header - Always Visible - Changed from button to div to fix nesting error */}
{/* CODING CARD */} @@ -1408,10 +1631,10 @@ export default function ActivityFeed() { initial={{ scale: 0.9, opacity: 0 }} animate={{ scale: 1, opacity: 1 }} exit={{ scale: 0.9, opacity: 0 }} - className="relative bg-gradient-to-br from-indigo-500/10 to-purple-500/5 border border-indigo-500/30 rounded-xl p-3 overflow-hidden shadow-lg shadow-indigo-500/10" + className="relative bg-gradient-to-br from-indigo-500/10 to-purple-500/5 border border-indigo-500/30 rounded-xl p-3 overflow-visible shadow-lg shadow-indigo-500/10" > {/* "RIGHT NOW" Indicator */} -
+
Right Now
@@ -1470,7 +1693,7 @@ export default function ActivityFeed() { href={data.music.url} target="_blank" rel="noreferrer" - className="relative block bg-gradient-to-br from-green-500/10 to-emerald-500/5 border border-green-500/30 rounded-xl p-3 hover:border-green-500/50 transition-all group shadow-lg shadow-green-500/10" + className="relative block bg-gradient-to-br from-green-500/10 to-emerald-500/5 border border-green-500/30 rounded-xl p-3 hover:border-green-500/50 transition-all group shadow-lg shadow-green-500/10 no-underline text-inherit" > {/* "RIGHT NOW" Indicator */}
diff --git a/app/components/BackgroundBlobsClient.tsx b/app/components/BackgroundBlobsClient.tsx index 1b8bd0a..baaf46b 100644 --- a/app/components/BackgroundBlobsClient.tsx +++ b/app/components/BackgroundBlobsClient.tsx @@ -1,11 +1,17 @@ "use client"; -import dynamic from "next/dynamic"; -import React from "react"; - -// Dynamically import the heavy framer-motion component on the client only -const BackgroundBlobs = dynamic(() => import("@/components/BackgroundBlobs"), { ssr: false }); +import React, { useEffect, useState } from "react"; +import BackgroundBlobs from "@/components/BackgroundBlobs"; export default function BackgroundBlobsClient() { + // Avoid SSR/webpack bailout issues from `next/dynamic({ ssr:false })` + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + if (!mounted) return null; + return ; } diff --git a/app/components/ChatWidget.tsx b/app/components/ChatWidget.tsx index 79cb8ee..818e0f1 100644 --- a/app/components/ChatWidget.tsx +++ b/app/components/ChatWidget.tsx @@ -53,8 +53,8 @@ export default function ChatWidget() { // Helper function to decode HTML entities const decodeHtmlEntities = (text: string): string => { - if (!text || typeof text !== 'string') return text; - const textarea = document.createElement('textarea'); + if (!text || typeof text !== "string") return text; + const textarea = document.createElement("textarea"); textarea.innerHTML = text; return textarea.value; }; @@ -129,25 +129,28 @@ export default function ChatWidget() { }); if (!response.ok) { - const errorText = await response.text().catch(() => 'Unknown error'); + const errorText = await response.text().catch(() => "Unknown error"); console.error("Chat API error:", { status: response.status, statusText: response.statusText, error: errorText, }); - throw new Error(`Failed to get response: ${response.status} - ${errorText.substring(0, 100)}`); + throw new Error( + `Failed to get response: ${response.status} - ${errorText.substring(0, 100)}`, + ); } const data = await response.json(); - + // Log response for debugging (only in development) - if (process.env.NODE_ENV === 'development') { + if (process.env.NODE_ENV === "development") { console.log("Chat API response:", data); } // Decode HTML entities in the reply - let replyText = data.reply || "Sorry, I couldn't process that. Please try again."; - + let replyText = + data.reply || "Sorry, I couldn't process that. Please try again."; + // Decode HTML entities client-side (double safety) replyText = decodeHtmlEntities(replyText); @@ -218,11 +221,11 @@ export default function ChatWidget() { setIsOpen(true); } }} - className="fixed bottom-20 left-4 md:bottom-6 md:left-6 z-30 bg-gradient-to-br from-blue-500 to-purple-600 text-white p-3 rounded-full shadow-2xl hover:shadow-blue-500/50 hover:scale-110 transition-all duration-300 group cursor-pointer" + className="fixed bottom-20 left-4 md:bottom-6 md:left-6 z-30 bg-[#5A4E42]/90 backdrop-blur-md text-white p-3 rounded-full shadow-2xl hover:bg-[#4A3F35]/90 hover:scale-110 transition-all duration-300 group cursor-pointer border border-white/10" aria-label="Open chat" > - + {/* Tooltip */} @@ -236,26 +239,29 @@ export default function ChatWidget() { {isOpen && ( {/* Header */} -
+
-
- +
+
- +
-

- Dennis{'\''}s AI Assistant +

+ Dennis{"'"}s AI Assistant

-

Always online

+

+ Always online +

@@ -278,7 +284,7 @@ export default function ChatWidget() {
{/* Messages */} -
+
{messages.map((message) => (
-

+

{message.text}

{message.timestamp.toLocaleTimeString([], { @@ -319,10 +327,10 @@ export default function ChatWidget() { animate={{ opacity: 1, y: 0 }} className="flex justify-start" > -

-
+
+
{/* Input */} -
+
{/* Quick Actions */} -
+
{[ "What are Dennis's skills?", "Tell me about his projects", @@ -397,7 +405,7 @@ export default function ChatWidget() { inputRef.current?.focus(); }} disabled={isLoading} - className="px-2 md:px-3 py-1 text-[10px] md:text-xs bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors whitespace-nowrap disabled:opacity-50 flex-shrink-0" + className="px-3 py-1.5 text-[10px] md:text-xs bg-white/80 backdrop-blur-sm text-[#2A241F] rounded-full hover:bg-white/95 border border-[#8B7D6F]/30 transition-all whitespace-nowrap disabled:opacity-50 flex-shrink-0 shadow-sm" > {suggestion} diff --git a/app/components/ClientOnly.tsx b/app/components/ClientOnly.tsx index 37799c9..6b983e0 100644 --- a/app/components/ClientOnly.tsx +++ b/app/components/ClientOnly.tsx @@ -1,8 +1,8 @@ "use client"; -import { useEffect, useState } from "react"; +import React, { useEffect, useState } from "react"; -export function ClientOnly({ children }: { children: React.ReactNode }) { +export default function ClientOnly({ children }: { children: React.ReactNode }) { const [hasMounted, setHasMounted] = useState(false); useEffect(() => { diff --git a/app/components/ClientProviders.tsx b/app/components/ClientProviders.tsx new file mode 100644 index 0000000..22e0fc6 --- /dev/null +++ b/app/components/ClientProviders.tsx @@ -0,0 +1,52 @@ +"use client"; + +import React, { useEffect, useState, Suspense, lazy } from "react"; +import { usePathname } from "next/navigation"; +import { ToastProvider } from "@/components/Toast"; +import { AnalyticsProvider } from "@/components/AnalyticsProvider"; + +// Lazy load heavy components to avoid webpack issues +const BackgroundBlobs = lazy(() => import("@/components/BackgroundBlobs")); +const ChatWidget = lazy(() => import("./ChatWidget")); + +export default function ClientProviders({ + children, +}: { + children: React.ReactNode; +}) { + const [mounted, setMounted] = useState(false); + const [is404Page, setIs404Page] = useState(false); + + useEffect(() => { + setMounted(true); + // Check if we're on a 404 page by looking for the data attribute + const check404 = () => { + if (typeof window !== "undefined") { + const has404Component = document.querySelector('[data-404-page]'); + setIs404Page(!!has404Component); + } + }; + // Check immediately and after a short delay + check404(); + const timeout = setTimeout(check404, 100); + return () => clearTimeout(timeout); + }, []); + + return ( + + + {mounted && ( + + + + )} +
{children}
+ {mounted && !is404Page && ( + + + + )} +
+
+ ); +} diff --git a/app/components/KernelPanic404.tsx b/app/components/KernelPanic404.tsx index 6ceae7c..1750a30 100644 --- a/app/components/KernelPanic404.tsx +++ b/app/components/KernelPanic404.tsx @@ -1,536 +1,1451 @@ "use client"; -import { useEffect, useRef, useState } from "react"; - -interface FileSystemNode { - type: 'file' | 'dir' | 'exe'; - content?: string; - children?: Record; -} +import { useEffect, useRef } from "react"; export default function KernelPanic404() { const outputRef = useRef(null); const inputRef = useRef(null); const inputContainerRef = useRef(null); - const [systemFrozen, setSystemFrozen] = useState(false); - const [currentMusic, setCurrentMusic] = useState<{ stop?: () => void } | null>(null); - const [hawkinsActive, setHawkinsActive] = useState(false); - const [fsocietyActive, setFsocietyActive] = useState(false); - const [commandHistory, setCommandHistory] = useState([]); - const [historyIndex, setHistoryIndex] = useState(-1); - const [currentPath, setCurrentPath] = useState(null); - const [pathStr, setPathStr] = useState("~"); - const audioCtxRef = useRef(null); - - // File system structure - const fileSystem: { home: FileSystemNode; var: FileSystemNode; etc: FileSystemNode; bin: FileSystemNode; tmp: FileSystemNode } = { - home: { - type: "dir", - children: { - guest: { - type: "dir", - children: { - "readme.txt": { - type: "file", - content: "ERROR 404: Page Not Found.\n\nSystem Integrity: 89%\nCheck /var/log for clues.\n\nTry: ls -la, cat .bash_history" - }, - ".bash_history": { - type: "file", - content: "ls -la\nwhoami\nfsociety\nexit" - }, - "todo.txt": { - type: "file", - content: "- Fix the internet\n- Calculate the Ultimate Answer (try: 42)\n- Buy milk\n- Check Hawkins Lab logs" - }, - "projects": { - type: "dir", - children: { - website: { - type: "dir", - children: { - "index.html": { type: "file", content: "404" } - } - } - } - } - } - } - } - }, - var: { - type: "dir", - children: { - log: { - type: "dir", - children: { - syslog: { - type: "file", - content: "[ERR] Reality breach detected in HAWKINS_LAB sector.\n[WARN] Subject 011 has escaped containment.\n[ALERT] Dimensional gate unstable.\n[INFO] Try command: hawkins or 011" - }, - "kern.log": { - type: "file", - content: "[ 0.000000] Linus Torvalds: 'This kernel is garbage.'\n[ 0.100000] Kernel tainted: M (Module has bad license)\n[ 0.200000] Torvalds: 'I'm not angry, just disappointed.'" - }, - "auth.log": { - type: "file", - content: "Failed password for root from 127.0.0.1\nFailed password for elliot from 127.0.0.1" - } - } - } - } - }, - etc: { - type: "dir", - children: { - passwd: { - type: "file", - content: "root:x:0:0:root:/root:/bin/bash\nguest:x:1000:1000:guest:/home/guest:/bin/bash\nelliot:x:509:509:mr_robot:/home/elliot:/bin/sh" - }, - hosts: { - type: "file", - content: "127.0.0.1 localhost\n127.0.0.1 e-corp.com\n0.0.0.0 reality" - } - } - }, - bin: { - type: "dir", - children: { - ls: { type: "exe" }, - cat: { type: "exe" }, - grep: { type: "exe" }, - find: { type: "exe" } - } - }, - tmp: { - type: "dir", - children: {} - } - }; - - const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); - - const printLine = (text: string, type?: string) => { - if (!outputRef.current) return; - const d = document.createElement('div'); - d.innerHTML = text; - if (type === 'log-warn') d.style.color = '#ffb000'; - if (type === 'log-err' || type === 'alert') d.style.color = '#ff3333'; - if (type === 'log-dim') d.style.opacity = '0.6'; - if (type === 'log-sys') d.style.color = 'cyan'; - if (type === 'log-k') d.style.color = '#fff'; - if (type === 'pulse-red') { - d.classList.add('pulse-red'); - d.style.color = '#ff3333'; - d.style.textShadow = '0 0 10px red'; - } - outputRef.current.appendChild(d); - if (outputRef.current) { - outputRef.current.scrollTop = outputRef.current.scrollHeight; - } - }; - - const playSynth = (type: string) => { - try { - if (!audioCtxRef.current || systemFrozen) return; - const t = audioCtxRef.current.currentTime; - const osc = audioCtxRef.current.createOscillator(); - const gain = audioCtxRef.current.createGain(); - osc.connect(gain); - gain.connect(audioCtxRef.current.destination); - - if (type === 'key') { - osc.type = 'square'; - osc.frequency.setValueAtTime(600, t); - gain.gain.setValueAtTime(0.02, t); - gain.gain.exponentialRampToValueAtTime(0.001, t + 0.05); - osc.start(); - osc.stop(t + 0.05); - } else if (type === 'beep') { - osc.type = 'sine'; - osc.frequency.setValueAtTime(800, t); - gain.gain.setValueAtTime(0.1, t); - gain.gain.exponentialRampToValueAtTime(0.001, t + 0.2); - osc.start(); - osc.stop(t + 0.2); - } - } catch { - // Ignore audio errors - } - }; - - const getCurrentDir = (): FileSystemNode => { - if (pathStr === "~" || pathStr.startsWith("~/")) { - return fileSystem.home.children!.guest; - } else if (pathStr.startsWith("/var/log")) { - // Return a wrapper node for /var/log directory - return { - type: 'dir', - children: fileSystem.var.children!.log.children - }; - } else if (pathStr.startsWith("/var")) { - return fileSystem.var; - } else if (pathStr.startsWith("/etc")) { - return fileSystem.etc; - } else if (pathStr.startsWith("/bin")) { - return fileSystem.bin; - } - return currentPath || fileSystem.home.children!.guest; - }; - - const runCmd = async (cmdRaw: string) => { - if (systemFrozen || !outputRef.current) return; - - printLine(`guest@404:${pathStr}$ ${cmdRaw}`, 'log-dim'); - const args = cmdRaw.split(/\s+/); - const cmd = args[0].toLowerCase(); - - const newHistory = [...commandHistory, cmdRaw]; - setCommandHistory(newHistory); - setHistoryIndex(newHistory.length); - - await sleep(100); - - const dir = getCurrentDir(); - - switch (cmd) { - case 'help': - printLine("--- SYSTEM UTILS ---", "log-sys"); - printLine(" ls, cd, cat, grep, find, pwd, clear"); - printLine(" whoami, uname, history, date, uptime"); - printLine(" head, tail, wc, sort, uniq"); - printLine("--- NETWORK ---", "log-sys"); - printLine(" ping, hostname"); - printLine("--- PROCESSES ---", "log-sys"); - printLine(" ps, top, kill"); - printLine("(Hints are hidden in the file system - try ls -la)"); - break; - - case 'ls': - const showHidden = args.includes('-a') || args.includes('-la') || args.includes('-l'); - const longFormat = args.includes('-l') || args.includes('-la'); - const items = Object.keys(dir.children || {}) - .filter(n => !n.startsWith('.') || showHidden); - if (showHidden) { - items.unshift('..'); - items.unshift('.'); - } - items.sort((a, b) => { - if (a === '.') return -1; - if (b === '.') return 1; - if (a === '..') return -1; - if (b === '..') return 1; - const itemA = dir.children?.[a] as FileSystemNode | undefined; - const itemB = dir.children?.[b] as FileSystemNode | undefined; - if (!itemA || !itemB) return 0; - if (itemA.type === 'dir' && itemB.type !== 'dir') return -1; - if (itemA.type !== 'dir' && itemB.type === 'dir') return 1; - return a.localeCompare(b); - }); - if (longFormat) { - printLine(`total ${items.length}`); - items.forEach(n => { - const item = dir.children?.[n]; - if (!item && n !== '.' && n !== '..') return; - const isDir = item?.type === 'dir' || n === '.' || n === '..'; - const perms = isDir ? 'drwxr-xr-x' : '-rw-r--r--'; - const links = isDir ? '2' : '1'; - const size = isDir ? '4096'.padStart(8) : (item?.content?.length || '0').toString().padStart(8); - const date = new Date(); - const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; - const month = monthNames[date.getMonth()]; - const day = date.getDate().toString().padStart(2); - const time = date.toTimeString().substring(0, 5); - const dateStr = `${month} ${day} ${time}`; - const filename = isDir ? `${n}/` : n; - printLine(`${perms} ${links} guest guest ${size} ${dateStr} ${filename}`); - }); - } else { - const formatted = items.map(n => { - const item = dir.children?.[n]; - if (n === '.' || n === '..') return `${n}/`; - if (item?.type === 'dir') return `${n}/`; - if (item?.type === 'exe') return `${n}*`; - return n; - }); - printLine(formatted.join(' ')); - } - break; - - case 'cat': - const file = dir.children?.[args[1]] as FileSystemNode | undefined; - if (file && file.type === 'file') { - printLine(file.content || ''); - } else { - printLine(`cat: ${args[1] || ''}: No such file`, 'log-err'); - } - break; - - case 'cd': - if (!args[1]) { - setCurrentPath(fileSystem.home.children!.guest); - setPathStr("~"); - } else if (args[1] === '..') { - if (pathStr === "/var/log") { - setCurrentPath(fileSystem.var); - setPathStr("/var"); - } else if (pathStr === "/var") { - setPathStr("/"); - } else { - setCurrentPath(fileSystem.home.children!.guest); - setPathStr("~"); - } - } else if (args[1] === '~' || args[1] === '/home/guest') { - setCurrentPath(fileSystem.home.children!.guest); - setPathStr("~"); - } else if (args[1].startsWith('/var/log')) { - setCurrentPath({ - type: 'dir', - children: fileSystem.var.children!.log.children - }); - setPathStr("/var/log"); - } else if (args[1].startsWith('/var')) { - setCurrentPath(fileSystem.var); - setPathStr("/var"); - } else if (args[1].startsWith('/etc')) { - setCurrentPath(fileSystem.etc); - setPathStr("/etc"); - } else { - const subdir = dir.children?.[args[1]] as FileSystemNode | undefined; - if (subdir && subdir.type === 'dir') { - setCurrentPath(subdir); - setPathStr(pathStr === "~" ? `~/${args[1]}` : `${pathStr}/${args[1]}`); - } else { - printLine(`cd: ${args[1]}: No such file or directory`, 'log-err'); - } - } - break; - - case 'pwd': - printLine(pathStr === "~" ? "/home/guest" : pathStr); - break; - - case 'grep': - if (args.length < 3) { - printLine("Usage: grep [pattern] [file]"); - } else { - const grepFile = dir.children?.[args[2]] as FileSystemNode | undefined; - if (grepFile && grepFile.type === 'file' && grepFile.content) { - const lines = grepFile.content.split('\n'); - lines.forEach(l => { - if (l.toLowerCase().includes(args[1].toLowerCase())) { - printLine(l); - } - }); - } else { - printLine(`grep: ${args[2]}: No such file`); - } - } - break; - - case 'whoami': - printLine("guest"); - break; - - case 'uname': - if (args.includes('-a')) { - printLine("Linux 404-void 4.0.4-void #1 SMP PREEMPT Fri Jan 09 2025 x86_64 GNU/Linux"); - } else { - printLine("Linux"); - } - break; - - case 'date': - printLine(new Date().toString()); - break; - - case 'uptime': - const uptime = Math.floor((Date.now() - performance.timing.navigationStart) / 1000); - const hours = Math.floor(uptime / 3600); - const mins = Math.floor((uptime % 3600) / 60); - const secs = uptime % 60; - printLine(`up ${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}, 1 user, load average: 0.00, 0.00, 0.00`); - break; - - case 'clear': - if (outputRef.current) outputRef.current.innerHTML = ""; - break; - - case 'history': - commandHistory.forEach((c, i) => printLine(` ${i + 1} ${c}`)); - break; - - case 'exit': - window.location.href = '/'; - break; - - // Easter eggs - case 'hawkins': - case '011': - case 'eleven': - case 'upsidedown': - if (hawkinsActive) { - printLine("Closing dimensional gate...", 'log-warn'); - setHawkinsActive(false); - if (currentMusic) { - currentMusic.stop?.(); - setCurrentMusic(null); - } - document.body.classList.remove('hawkins'); - } else { - setHawkinsActive(true); - document.body.classList.add('hawkins'); - printLine("Entering the Upside Down...", 'log-err'); - } - break; - - case 'fsociety': - case 'elliot': - case 'bonsoir': - if (fsocietyActive) { - setFsocietyActive(false); - setSystemFrozen(false); - if (inputContainerRef.current) inputContainerRef.current.style.display = 'flex'; - if (currentMusic) { - currentMusic.stop?.(); - setCurrentMusic(null); - } - document.body.classList.remove('fsociety-boot'); - } else { - setFsocietyActive(true); - setSystemFrozen(true); - if (inputContainerRef.current) inputContainerRef.current.style.display = 'none'; - if (outputRef.current) outputRef.current.innerHTML = ""; - document.body.classList.add('fsociety-boot'); - printLine("$ ./fsociety.sh", 'log-k'); - await sleep(250); - printLine("[*] Initializing breach protocol...", 'log-warn'); - await sleep(500); - printLine("Hello friend.", 'log-k'); - await sleep(1000); - location.reload(); - } - break; - - case '42': - case 'answer': - printLine("Initializing Deep Thought...", 'log-sys'); - await sleep(600); - printLine("Deep Thought: The Answer to the Ultimate Question of Life, the Universe, and Everything is...", 'log-k'); - await sleep(1500); - printLine("42", 'log-k'); - break; - - case 'rm': - if (args[1] === '-rf' && args[2] === '/') { - setSystemFrozen(true); - if (inputContainerRef.current) inputContainerRef.current.style.display = 'none'; - printLine("CRITICAL: Attempting to delete root filesystem...", 'log-err'); - await sleep(500); - printLine("KERNEL PANIC: Unable to handle kernel paging request", 'pulse-red'); - await sleep(2000); - location.reload(); - } else if (args[1]) { - printLine("rm: cannot remove: Read-only file system", 'log-err'); - } else { - printLine("Usage: rm [file]"); - } - break; - - default: - printLine(`bash: ${cmd}: command not found`, 'log-err'); - } - - if (inputRef.current && !systemFrozen) { - setTimeout(() => inputRef.current?.focus(), 50); - } - }; + const overlayRef = useRef(null); + const bodyRef = useRef(null); // We'll use a wrapper div instead of document.body for some effects if possible, but strict effects might need body. useEffect(() => { - setCurrentPath(fileSystem.home.children!.guest); + /* --- SYSTEM CORE --- */ + const output = outputRef.current; + const input = inputRef.current; + const inputContainer = inputContainerRef.current; + const overlay = overlayRef.current; - const initAudio = () => { - if (!audioCtxRef.current) { - try { - audioCtxRef.current = new (window.AudioContext || (window as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext)(); - } catch { - // Ignore - } - } + // We need to access the actual body for some full-screen effects + const body = document.body; + + if (!output || !input || !inputContainer || !overlay) return; + + let audioCtx: AudioContext | null = null; + let systemFrozen = false; + let currentMusic: any = null; + let hawkinsActive = false; + let fsocietyActive = false; + + // Timers storage to clear on unmount + const timers: (NodeJS.Timeout | number)[] = []; + const interval = (fn: Function, ms: number) => { + const id = setInterval(fn, ms); + timers.push(id); + return id; + }; + const timeout = (fn: Function, ms: number) => { + const id = setTimeout(fn, ms); + timers.push(id); + return id; }; - window.addEventListener('keydown', initAudio, { once: true }); + // Initialize Audio on first interaction + function initAudio() { + if (!audioCtx) { + const AudioContextClass = + window.AudioContext || (window as any).webkitAudioContext; + if (AudioContextClass) { + audioCtx = new AudioContextClass(); + } + } + } + window.addEventListener("keydown", initAudio, { once: true }); + window.addEventListener("click", initAudio, { once: true }); + /* --- MUSIC SYNTHESIS ENGINE --- */ + + function makeDistortionCurve(amount: number) { + const samples = 44100; + const curve = new Float32Array(samples); + const deg = Math.PI / 180; + for (let i = 0; i < samples; i++) { + const x = (i * 2) / samples - 1; + curve[i] = + ((3 + amount) * x * 20 * deg) / (Math.PI + amount * Math.abs(x)); + } + return curve; + } + + function playStrangerThingsTheme() { + if (!audioCtx) return null; + const masterGain = audioCtx.createGain(); + masterGain.gain.value = 0.4; + + const distortion = audioCtx.createWaveShaper(); + distortion.curve = makeDistortionCurve(6); + distortion.oversample = "4x"; + masterGain.connect(distortion); + distortion.connect(audioCtx.destination); + + function playNote( + freq: number, + startTime: number, + duration: number, + type: OscillatorType = "sawtooth", + volume = 0.4, + ) { + if (!audioCtx) return; + const osc = audioCtx.createOscillator(); + const gain = audioCtx.createGain(); + osc.type = type; + osc.frequency.setValueAtTime(freq, audioCtx.currentTime + startTime); + gain.gain.setValueAtTime(0, audioCtx.currentTime + startTime); + gain.gain.linearRampToValueAtTime( + volume, + audioCtx.currentTime + startTime + 0.05, + ); + gain.gain.exponentialRampToValueAtTime( + 0.01, + audioCtx.currentTime + startTime + duration, + ); + osc.connect(gain); + gain.connect(masterGain); + osc.start(audioCtx.currentTime + startTime); + osc.stop(audioCtx.currentTime + startTime + duration); + } + + function playMelody(startTime: number) { + const t = startTime; + const notes = [ + { f: 196.0, t: 0.0, d: 0.45 }, // G + { f: 233.08, t: 0.5, d: 0.45 }, // Bb + { f: 174.61, t: 1.0, d: 0.45 }, // F + { f: 233.08, t: 1.5, d: 0.45 }, // Bb + ]; + notes.forEach((n) => { + playNote(n.f, t + n.t, n.d, "sawtooth", 0.5); + }); + } + + function playBass(startTime: number) { + const t = startTime; + const notes = [ + { f: 98.0, t: 0.0, d: 1.9 }, // G (low) + { f: 116.54, t: 2.0, d: 1.9 }, // Bb (low) + { f: 77.78, t: 4.0, d: 1.9 }, // Eb (low) + { f: 87.31, t: 6.0, d: 1.9 }, // F (low) + ]; + notes.forEach((n) => { + playNote(n.f, t + n.t, n.d, "square", 0.35); + }); + } + + function playBass2(startTime: number) { + const t = startTime; + const notes = [ + { f: 98.0, t: 0.0, d: 0.9 }, // G + { f: 116.54, t: 1.0, d: 0.9 }, // Bb + { f: 87.31, t: 2.0, d: 0.9 }, // F + { f: 116.54, t: 3.0, d: 0.9 }, // Bb + ]; + notes.forEach((n) => { + playNote(n.f, t + n.t, n.d, "square", 0.3); + }); + } + + playMelody(0); + playBass(0); + + timeout(() => { + playBass2(0); + }, 16500); + + const melodyInterval = interval(() => { + playMelody(0); + }, 2000); + + const bassInterval = interval(() => { + playBass(0); + }, 8000); + + const bass2Interval = interval(() => { + playBass2(0); + }, 4000); + + return { + stop: () => { + clearInterval(melodyInterval); + clearInterval(bassInterval); + clearInterval(bass2Interval); + masterGain.disconnect(); + }, + }; + } + + function playMrRobotTheme() { + if (!audioCtx) return null; + const masterGain = audioCtx.createGain(); + masterGain.gain.value = 0.3; + + const distortion = audioCtx.createWaveShaper(); + distortion.curve = makeDistortionCurve(50); + distortion.oversample = "4x"; + masterGain.connect(distortion); + distortion.connect(audioCtx.destination); + + const bass1 = audioCtx.createOscillator(); + const bass1Gain = audioCtx.createGain(); + bass1.type = "sawtooth"; + bass1.frequency.setValueAtTime(41.2, audioCtx.currentTime); + bass1Gain.gain.setValueAtTime(0.5, audioCtx.currentTime); + bass1.connect(bass1Gain); + bass1Gain.connect(masterGain); + bass1.start(); + + const bass2 = audioCtx.createOscillator(); + const bass2Gain = audioCtx.createGain(); + bass2.type = "square"; + bass2.frequency.setValueAtTime(40.5, audioCtx.currentTime); + bass2Gain.gain.setValueAtTime(0.3, audioCtx.currentTime); + bass2.connect(bass2Gain); + bass2Gain.connect(masterGain); + bass2.start(); + + const deepPulseInterval = interval(() => { + if (!audioCtx) return; + const osc = audioCtx.createOscillator(); + const gain = audioCtx.createGain(); + osc.type = "sawtooth"; + const deepNotes = [55, 65, 73, 82, 98]; + osc.frequency.setValueAtTime( + deepNotes[Math.floor(Math.random() * deepNotes.length)], + audioCtx.currentTime, + ); + gain.gain.setValueAtTime(0.2, audioCtx.currentTime); + gain.gain.exponentialRampToValueAtTime( + 0.001, + audioCtx.currentTime + 0.2, + ); + osc.connect(gain); + gain.connect(masterGain); + osc.start(); + osc.stop(audioCtx.currentTime + 0.2); + }, 400); + + const rumbleInterval = interval(() => { + if (!audioCtx) return; + const osc = audioCtx.createOscillator(); + const gain = audioCtx.createGain(); + osc.type = "sawtooth"; + osc.frequency.setValueAtTime( + 30 + Math.random() * 10, + audioCtx.currentTime, + ); + gain.gain.setValueAtTime(0.2, audioCtx.currentTime); + gain.gain.exponentialRampToValueAtTime( + 0.001, + audioCtx.currentTime + 0.3, + ); + osc.connect(gain); + gain.connect(masterGain); + osc.start(); + osc.stop(audioCtx.currentTime + 0.3); + }, 2000); + + return { + stop: () => { + bass1.stop(); + bass2.stop(); + clearInterval(deepPulseInterval); + clearInterval(rumbleInterval); + masterGain.disconnect(); + }, + }; + } + + function playHitchhikersTheme() { + if (!audioCtx) return null; + const masterGain = audioCtx.createGain(); + masterGain.gain.value = 0.35; + + const delay = audioCtx.createDelay(0.5); + delay.delayTime.setValueAtTime(0.15, audioCtx.currentTime); + const delayGain = audioCtx.createGain(); + delayGain.gain.value = 0.3; + masterGain.connect(delay); + delay.connect(delayGain); + delayGain.connect(masterGain); + masterGain.connect(audioCtx.destination); + + function playNote( + freq: number, + startTime: number, + duration: number, + type: OscillatorType = "sine", + volume = 0.4, + ) { + if (!audioCtx) return; + const osc = audioCtx.createOscillator(); + const gain = audioCtx.createGain(); + osc.type = type; + osc.frequency.setValueAtTime(freq, audioCtx.currentTime + startTime); + gain.gain.setValueAtTime(0, audioCtx.currentTime + startTime); + gain.gain.linearRampToValueAtTime( + volume, + audioCtx.currentTime + startTime + 0.08, + ); + gain.gain.exponentialRampToValueAtTime( + 0.01, + audioCtx.currentTime + startTime + duration, + ); + osc.connect(gain); + gain.connect(masterGain); + osc.start(audioCtx.currentTime + startTime); + osc.stop(audioCtx.currentTime + startTime + duration); + } + + function playMelody(startTime: number) { + const t = startTime; + const melody = [ + { f: 523.25, t: 0.0, d: 0.4 }, // C + { f: 587.33, t: 0.4, d: 0.4 }, // D + { f: 659.25, t: 0.8, d: 0.4 }, // E + { f: 698.46, t: 1.2, d: 0.4 }, // F + { f: 783.99, t: 1.6, d: 0.8 }, // G + { f: 698.46, t: 2.4, d: 0.4 }, // F + { f: 659.25, t: 2.8, d: 0.4 }, // E + { f: 587.33, t: 3.2, d: 0.4 }, // D + { f: 523.25, t: 3.6, d: 0.8 }, // C + ]; + melody.forEach((n) => playNote(n.f, t + n.t, n.d, "sine", 0.5)); + } + + function playHarmony(startTime: number) { + const t = startTime; + const harmony = [ + { f: 783.99, t: 0.0, d: 0.4 }, // G + { f: 880.0, t: 0.4, d: 0.4 }, // A + { f: 987.77, t: 0.8, d: 0.4 }, // B + { f: 1046.5, t: 1.2, d: 0.4 }, // C + { f: 1174.66, t: 1.6, d: 0.8 }, // D + { f: 1046.5, t: 2.4, d: 0.4 }, // C + { f: 987.77, t: 2.8, d: 0.4 }, // B + { f: 880.0, t: 3.2, d: 0.4 }, // A + { f: 783.99, t: 3.6, d: 0.8 }, // G + ]; + harmony.forEach((n) => playNote(n.f, t + n.t, n.d, "triangle", 0.25)); + } + + function playBass(startTime: number) { + const t = startTime; + const bass = [ + { f: 130.81, t: 0.0, d: 0.8 }, // C (low) + { f: 146.83, t: 0.8, d: 0.8 }, // D + { f: 164.81, t: 1.6, d: 0.8 }, // E + { f: 146.83, t: 2.4, d: 0.8 }, // D + { f: 130.81, t: 3.2, d: 1.2 }, // C + ]; + bass.forEach((n) => playNote(n.f, t + n.t, n.d, "square", 0.3)); + } + + function playPad(startTime: number) { + const t = startTime; + const padNotes = [ + { f: 261.63, t: 0.0, d: 4.4 }, // C (middle, held) + { f: 329.63, t: 0.0, d: 4.4 }, // E (held) + { f: 392.0, t: 0.0, d: 4.4 }, // G (held) + ]; + padNotes.forEach((n) => playNote(n.f, t + n.t, n.d, "sine", 0.15)); + } + + playMelody(0); + playHarmony(0); + playBass(0); + playPad(0); + + const loopInterval = interval(() => { + playMelody(0); + playHarmony(0); + playBass(0); + playPad(0); + }, 4400); + + return { + stop: () => { + clearInterval(loopInterval); + masterGain.disconnect(); + }, + }; + } + + function playSynth(type: string) { + try { + if (!audioCtx || systemFrozen) return; + const t = audioCtx.currentTime; + const osc = audioCtx.createOscillator(); + const gain = audioCtx.createGain(); + osc.connect(gain); + gain.connect(audioCtx.destination); + + if (type === "key") { + osc.type = "square"; + osc.frequency.setValueAtTime(600, t); + gain.gain.setValueAtTime(0.02, t); + gain.gain.exponentialRampToValueAtTime(0.001, t + 0.05); + osc.start(); + osc.stop(t + 0.05); + } else if (type === "scare") { + osc.type = "sawtooth"; + osc.frequency.setValueAtTime(40, t); + gain.gain.setValueAtTime(0.6, t); + gain.gain.exponentialRampToValueAtTime(0.01, t + 1.0); + + const osc2 = audioCtx.createOscillator(); + osc2.type = "sawtooth"; + osc2.frequency.setValueAtTime(45, t); + const gain2 = audioCtx.createGain(); + osc2.connect(gain2); + gain2.connect(audioCtx.destination); + gain2.gain.setValueAtTime(0.5, t); + gain2.gain.exponentialRampToValueAtTime(0.01, t + 1.0); + + osc.start(); + osc2.start(); + osc.stop(t + 1.0); + osc2.stop(t + 1.0); + } else if (type === "melt") { + const bufferSize = audioCtx.sampleRate * 0.8; + const buffer = audioCtx.createBuffer( + 1, + bufferSize, + audioCtx.sampleRate, + ); + const data = buffer.getChannelData(0); + for (let i = 0; i < bufferSize; i++) { + data[i] = (Math.random() * 2 - 1) * 0.5; + } + const noise = audioCtx.createBufferSource(); + noise.buffer = buffer; + const filter = audioCtx.createBiquadFilter(); + filter.type = "bandpass"; + filter.frequency.value = 2000; + noise.connect(filter); + filter.connect(gain); + gain.gain.setValueAtTime(0.3, t); + gain.gain.exponentialRampToValueAtTime(0.001, t + 0.8); + noise.start(); + } else if (type === "beep") { + osc.type = "sine"; + osc.frequency.setValueAtTime(800, t); + gain.gain.setValueAtTime(0.1, t); + gain.gain.exponentialRampToValueAtTime(0.001, t + 0.2); + osc.start(); + osc.stop(t + 0.2); + } + } catch (err) { + console.log("Audio error (non-critical):", err); + } + } + + /* --- FILE SYSTEM --- */ + const fileSystem: any = { + home: { + type: "dir", + children: { + guest: { + type: "dir", + children: { + "readme.txt": { + type: "file", + content: + "ERROR 404: Page Not Found.\n\nSystem Integrity: 89%\nCheck /var/log for clues.\n\nTry: ls -la, cat .bash_history", + }, + ".bash_history": { + type: "file", + content: "ls -la\nwhoami\nfsociety\nexit", + }, + "todo.txt": { + type: "file", + content: + "- Fix the internet\n- Calculate the Ultimate Answer (try: 42)\n- Buy milk\n- Check Hawkins Lab logs", + }, + projects: { + type: "dir", + children: { + website: { + type: "dir", + children: { + "index.html": { + type: "file", + content: "404", + }, + }, + }, + }, + }, + }, + }, + }, + }, + var: { + type: "dir", + children: { + log: { + type: "dir", + children: { + syslog: { + type: "file", + content: + "[ERR] Reality breach detected in HAWKINS_LAB sector.\n[WARN] Subject 011 has escaped containment.\n[ALERT] Dimensional gate unstable.\n[INFO] Try command: hawkins or 011", + }, + "kern.log": { + type: "file", + content: + "[ 0.000000] Linus Torvalds: 'This kernel is garbage.'\n[ 0.100000] Kernel tainted: M (Module has bad license)\n[ 0.200000] Torvalds: 'I'm not angry, just disappointed.'", + }, + "auth.log": { + type: "file", + content: + "Failed password for root from 127.0.0.1\nFailed password for elliot from 127.0.0.1", + }, + }, + }, + }, + }, + etc: { + type: "dir", + children: { + passwd: { + type: "file", + content: + "root:x:0:0:root:/root:/bin/bash\nguest:x:1000:1000:guest:/home/guest:/bin/bash\nelliot:x:509:509:mr_robot:/home/elliot:/bin/sh", + }, + hosts: { + type: "file", + content: + "127.0.0.1 localhost\n127.0.0.1 e-corp.com\n0.0.0.0 reality", + }, + }, + }, + bin: { + type: "dir", + children: { + ls: { type: "exe" }, + cat: { type: "exe" }, + grep: { type: "exe" }, + find: { type: "exe" }, + }, + }, + tmp: { + type: "dir", + children: {}, + }, + }; + // Add root reference + fileSystem.root = { + type: "dir", + children: { + home: fileSystem.home, + var: fileSystem.var, + etc: fileSystem.etc, + bin: fileSystem.bin, + tmp: fileSystem.tmp, + }, + }; + + let currentPath = fileSystem.home.children.guest; + let pathStr = "~"; + let commandHistory: string[] = []; + let historyIndex = -1; + + /* --- UTILS --- */ + function printLine(text: string, type?: string) { + if (!output) return; + const d = document.createElement("div"); + d.innerHTML = text; + if (type === "log-warn") d.style.color = "#ffb000"; + if (type === "log-err" || type === "alert") + d.style.color = "var(--alert)"; + if (type === "log-dim") d.style.opacity = "0.6"; + if (type === "log-sys") d.style.color = "cyan"; + if (type === "log-k") d.style.color = "#fff"; + if (type === "pulse-red") d.classList.add("pulse-red"); + if (type === "fsociety-mask") d.classList.add("fsociety-mask"); + if (type === "memory-error") d.classList.add("memory-error"); + if (type === "kernel-panic") d.classList.add("kernel-panic"); + output.appendChild(d); + output.scrollTop = output.scrollHeight; + } + + function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + + /* --- BOOT SEQUENCE --- */ const bootMessages = [ - { t: "[ 0.000000] Linux version 4.0.4-void (torvalds@kernel.org) (gcc version 9.4.0)", d: 200 }, - { t: "[ 0.050000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.0.4 root=UUID=dead-beef ro quiet splash", d: 150 }, - { t: "[ 0.100000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'", d: 100 }, - { t: "[ 0.150000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'", d: 100 }, + { + t: "[ 0.000000] Linux version 4.0.4-void (torvalds@kernel.org) (gcc version 9.4.0)", + d: 200, + }, + { + t: "[ 0.050000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.0.4 root=UUID=dead-beef ro quiet splash", + d: 150, + }, + { + t: "[ 0.100000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'", + d: 100, + }, + { + t: "[ 0.150000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'", + d: 100, + }, { t: "[ 0.200000] BIOS-provided physical RAM map:", d: 200 }, - { t: "[ 0.250000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable", d: 150 }, - { t: "[ 0.300000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved", d: 150 }, - { t: "[ 0.400000] Memory: 64K/1048576K available (404K kernel code, 404K rwdata, 404K rodata)", d: 300 }, - { t: "[ 0.600000] Calibrating delay loop... 800.00 BogoMIPS (lpj=400000)", d: 200 }, + { + t: "[ 0.250000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable", + d: 150, + }, + { + t: "[ 0.300000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved", + d: 150, + }, + { + t: "[ 0.400000] Memory: 64K/1048576K available (404K kernel code, 404K rwdata, 404K rodata)", + d: 300, + }, + { + t: "[ 0.600000] Calibrating delay loop... 800.00 BogoMIPS (lpj=400000)", + d: 200, + }, { t: "[ 0.800000] Security Framework initialized", d: 200 }, - { t: "[ 1.000000] Tainted kernel: M (Module has bad license) P (Proprietary module loaded)", type: 'log-warn', d: 400 }, - { t: "[ 1.200000] Linus Torvalds: 'I'm not angry, I'm just disappointed in this boot process.'", d: 600 }, - { t: "[ 1.500000] Torvalds: 'This code is garbage. Who wrote this?'", d: 500 }, - { t: "[ 2.000000] [ OK ] Started udev Kernel Device Manager.", d: 200 }, - { t: "[ 2.200000] [ OK ] Mounted /dev/sda1 (Root Filesystem).", d: 200 }, - { t: "[ 2.400000] [TIME] Timed out waiting for device /dev/reality.", type: 'log-warn', d: 600 }, - { t: "[ 2.800000] [DEPEND] Dependency failed for Local File Systems.", type: 'log-err', d: 300 }, - { t: "[ 3.000000] [FAILED] Failed to start The Internet.", type: 'log-err', d: 400 }, - { t: "[ 3.200000] [FAILED] Failed to start Meaning of Life service.", type: 'log-err', d: 400 }, - { t: "[ 3.500000] Welcome to emergency mode. Type 'help' for available commands.", d: 200 }, + { + t: "[ 1.000000] Tainted kernel: M (Module has bad license) P (Proprietary module loaded)", + type: "log-warn", + d: 400, + }, + { + t: "[ 1.200000] Linus Torvalds: 'I'm not angry, I'm just disappointed in this boot process.'", + d: 600, + }, + { + t: "[ 1.500000] Torvalds: 'This code is garbage. Who wrote this?'", + d: 500, + }, + { + t: "[ 2.000000] [ OK ] Started udev Kernel Device Manager.", + d: 200, + }, + { + t: "[ 2.200000] [ OK ] Mounted /dev/sda1 (Root Filesystem).", + d: 200, + }, + { + t: "[ 2.400000] [TIME] Timed out waiting for device /dev/reality.", + type: "log-warn", + d: 600, + }, + { + t: "[ 2.800000] [DEPEND] Dependency failed for Local File Systems.", + type: "log-err", + d: 300, + }, + { + t: "[ 3.000000] [FAILED] Failed to start The Internet.", + type: "log-err", + d: 400, + }, + { + t: "[ 3.200000] [FAILED] Failed to start Meaning of Life service.", + type: "log-err", + d: 400, + }, + { + t: "[ 3.500000] Welcome to emergency mode. Type 'help' for available commands.", + d: 200, + }, ]; - const runBoot = async () => { - for (const msg of bootMessages) { + async function runBoot() { + // Clear initial output + output!.innerHTML = ""; + + for (let msg of bootMessages) { printLine(msg.t, msg.type); await sleep(msg.d); } - if (inputContainerRef.current) { - inputContainerRef.current.style.display = 'flex'; - } - if (inputRef.current) { - setTimeout(() => inputRef.current?.focus(), 100); - } - }; - if (outputRef.current) { - runBoot(); + if (inputContainer) inputContainer.style.display = "flex"; + setTimeout(() => { + if (input) input.focus(); + }, 100); } - return () => { + // Start boot sequence + runBoot(); + + /* --- AUTOCOMPLETE --- */ + const commands = [ + "help", + "ls", + "cd", + "cat", + "grep", + "find", + "pwd", + "clear", + "whoami", + "uname", + "history", + "date", + "uptime", + "head", + "tail", + "wc", + "hostname", + "ping", + "ps", + "top", + "kill", + "exit", + "hawkins", + "011", + "eleven", + "upsidedown", + "fsociety", + "elliot", + "bonsoir", + "42", + "answer", + "rm", + ]; + + function getCurrentDir() { + if (pathStr === "~" || pathStr.startsWith("~/")) { + return fileSystem.home.children.guest; + } else if (pathStr.startsWith("/var/log")) { + return fileSystem.var.children.log; + } else if (pathStr.startsWith("/var")) { + return fileSystem.var; + } else if (pathStr.startsWith("/etc")) { + return fileSystem.etc; + } else if (pathStr.startsWith("/bin")) { + return fileSystem.bin; + } else if (pathStr === "/") { + return fileSystem.root; + } + return currentPath; + } + + function getAutocompleteSuggestions(text: string) { + const parts = text.trim().split(/\s+/); + const cmd = parts[0].toLowerCase(); + const arg = parts[parts.length - 1] || ""; + + // Command autocomplete + if (parts.length === 1 && text.trim().length > 0) { + return commands.filter((c) => c.startsWith(cmd)); + } + + // File/directory autocomplete + if ( + parts.length > 1 && + (cmd === "cat" || + cmd === "cd" || + cmd === "grep" || + cmd === "head" || + cmd === "tail" || + cmd === "wc" || + cmd === "find" || + cmd === "rm") + ) { + const dir = getCurrentDir(); + const items = Object.keys(dir.children || {}).filter((name) => + name.toLowerCase().startsWith(arg.toLowerCase()), + ); + + // Also check for path-based completion + if (arg.includes("/")) { + const pathParts = arg.split("/"); + const lastPart = pathParts.pop() || ""; + // Simple case + return items.filter((name) => + name.toLowerCase().startsWith(lastPart.toLowerCase()), + ); + } + + return items; + } + + return []; + } + + function handleTabComplete() { + if (!input) return; + + const text = input.value; + const cursorPos = input.selectionStart || 0; + const textBeforeCursor = text.substring(0, cursorPos); + const parts = textBeforeCursor.trim().split(/\s+/); + + const suggestions = getAutocompleteSuggestions(textBeforeCursor); + + if (suggestions.length === 0) { + try { + playSynth("beep"); + } catch (e) {} + return; + } + + if (suggestions.length === 1) { + // Single match - complete it + const partIndex = parts.length - 1; + + if (partIndex === 0) { + // Completing command + input.value = suggestions[0] + (text.endsWith(" ") ? "" : " "); + } else { + // Completing argument + const beforeArg = parts.slice(0, -1).join(" ") + " "; + const completion = suggestions[0]; + const dir = getCurrentDir(); + const item = dir.children[completion]; + const suffix = item && item.type === "dir" ? "/" : " "; + input.value = beforeArg + completion + suffix; + } + input.setSelectionRange(input.value.length, input.value.length); + try { + playSynth("beep"); + } catch (e) {} + } else { + // Multiple matches + printLine(`Possible completions: ${suggestions.join(" ")}`, "log-dim"); + try { + playSynth("beep"); + } catch (e) {} + } + } + + /* --- COMMAND PROCESSOR --- */ + async function runCmd() { + if (systemFrozen || !input) { + try { + playSynth("beep"); + } catch (e) {} + return; + } + + const cmdRaw = input.value.trim(); + input.value = ""; + + if (!cmdRaw) { + printLine(`guest@404:${pathStr}$ `, "log-dim"); + return; + } + + commandHistory.push(cmdRaw); + historyIndex = commandHistory.length; + + printLine(`guest@404:${pathStr}$ ${cmdRaw}`, "log-dim"); + const args = cmdRaw.split(/\s+/); + const cmd = args[0].toLowerCase(); + + await sleep(100); + + switch (cmd) { + case "help": + printLine("--- SYSTEM UTILS ---", "log-sys"); + printLine(" ls, cd, cat, grep, find, pwd, clear"); + printLine(" whoami, uname, history, date, uptime"); + printLine(" head, tail, wc, sort, uniq"); + printLine("--- NETWORK ---", "log-sys"); + printLine(" ping, hostname"); + printLine("--- PROCESSES ---", "log-sys"); + printLine(" ps, top, kill"); + printLine("(Hints are hidden in the file system - try ls -la)"); + break; + + case "ls": + const showHidden = + args.includes("-a") || args.includes("-la") || args.includes("-l"); + const longFormat = args.includes("-l") || args.includes("-la"); + + let items = Object.keys(currentPath.children).filter( + (n) => !n.startsWith(".") || showHidden, + ); + + if (showHidden) { + items.unshift(".."); + items.unshift("."); + } + + items.sort((a, b) => { + if (a === ".") return -1; + if (b === ".") return 1; + if (a === "..") return -1; + if (b === "..") return 1; + + const itemA = currentPath.children[a]; + const itemB = currentPath.children[b]; + if (!itemA || !itemB) return 0; + if (itemA.type === "dir" && itemB.type !== "dir") return -1; + if (itemA.type !== "dir" && itemB.type === "dir") return 1; + return a.localeCompare(b); + }); + + if (longFormat) { + printLine(`total ${items.length}`); + items.forEach((n) => { + if (n === "." || n === "..") { + const date = new Date(); + const month = date.toLocaleString("default", { + month: "short", + }); + const day = date.getDate().toString().padStart(2, "0"); + const time = date.toTimeString().substring(0, 5); + const dateStr = `${month} ${day} ${time}`; + printLine( + `drwxr-xr-x 2 guest guest 4096 ${dateStr} ${n}/`, + ); + return; + } + + const item = currentPath.children[n]; + if (!item) return; + const isDir = item.type === "dir"; + const isExe = item.type === "exe"; + const perms = isDir + ? "drwxr-xr-x" + : isExe + ? "-rwxr-xr-x" + : "-rw-r--r--"; + const links = isDir ? "2" : "1"; + let size = "0"; + if (item.content) size = item.content.length.toString(); + else if (isDir) size = "4096"; + size = size.padStart(8); + + const date = new Date(); + const month = date.toLocaleString("default", { month: "short" }); + const day = date.getDate().toString().padStart(2, "0"); + const time = date.toTimeString().substring(0, 5); + const dateStr = `${month} ${day} ${time}`; + + let filename = n; + if (isDir) filename = `${n}/`; + else if (isExe) filename = `${n}*`; + + printLine( + `${perms} ${links} guest guest ${size} ${dateStr} ${filename}`, + ); + }); + } else { + const formatted = items.map((n) => { + if (n === "." || n === "..") + return `${n}/`; + const item = currentPath.children[n]; + if (!item) return n; + if (item.type === "dir") + return `${n}/`; + if (item.type === "exe") + return `${n}*`; + return n; + }); + printLine(formatted.join(" ")); + } + break; + + case "cat": + if (args[1]) { + const file = currentPath.children[args[1]]; + if (file && file.type === "file") { + printLine(file.content); + } else { + printLine(`cat: ${args[1]}: No such file`, "log-err"); + } + } + break; + + case "cd": + if (!args[1]) { + currentPath = fileSystem.home.children.guest; + pathStr = "~"; + } else if (args[1] === "..") { + if (pathStr === "/var/log") { + currentPath = fileSystem.var; + pathStr = "/var"; + } else if (pathStr === "/var") { + currentPath = fileSystem.root; + pathStr = "/"; + } else { + currentPath = fileSystem.home.children.guest; + pathStr = "~"; + } + } else if (args[1] === "~" || args[1] === "/home/guest") { + currentPath = fileSystem.home.children.guest; + pathStr = "~"; + } else if (args[1].startsWith("/var/log")) { + currentPath = fileSystem.var.children.log; + pathStr = "/var/log"; + } else if (args[1].startsWith("/var")) { + currentPath = fileSystem.var; + pathStr = "/var"; + } else if (args[1].startsWith("/etc")) { + currentPath = fileSystem.etc; + pathStr = "/etc"; + } else if (args[1] === "/") { + currentPath = fileSystem.root; + pathStr = "/"; + } else { + const subdir = currentPath.children[args[1]]; + if (subdir && subdir.type === "dir") { + currentPath = subdir; + pathStr = + pathStr === "~" ? `~/${args[1]}` : `${pathStr}/${args[1]}`; + } else { + printLine(`cd: ${args[1]}: No such file or directory`, "log-err"); + } + } + break; + + case "pwd": + printLine(pathStr === "~" ? "/home/guest" : pathStr); + break; + + case "grep": + if (args.length < 3) { + printLine("Usage: grep [pattern] [file]"); + } else { + const grepFile = currentPath.children[args[2]]; + if (grepFile && grepFile.content) { + const lines = grepFile.content.split("\n"); + lines.forEach((l: string) => { + if (l.toLowerCase().includes(args[1].toLowerCase())) { + printLine(l); + } + }); + } else { + printLine(`grep: ${args[2]}: No such file`); + } + } + break; + + case "whoami": + printLine("guest"); + break; + + case "uname": + if (args.includes("-a")) { + printLine( + "Linux 404-void 4.0.4-void #1 SMP PREEMPT Fri Jan 09 2025 x86_64 GNU/Linux", + ); + } else { + printLine("Linux"); + } + break; + + case "date": + printLine(new Date().toString()); + break; + + case "clear": + if (output) output.innerHTML = ""; + break; + + case "exit": + window.location.href = "/"; + break; + + case "hawkins": + case "011": + case "eleven": + case "upsidedown": + await triggerHawkins(); + break; + + case "fsociety": + case "elliot": + case "bonsoir": + await triggerFsociety(); + break; + + case "42": + case "answer": + await triggerDeepThought(); + break; + + case "rm": + if (args[1] === "-rf" && args[2] === "/") { + await initiateMeltdown(); + } else if (args[1]) { + printLine("rm: cannot remove: Read-only file system", "log-err"); + } else { + printLine("Usage: rm [file]"); + } + break; + + default: + printLine(`bash: ${cmd}: command not found`, "log-err"); + } + + if (output) output.scrollTop = output.scrollHeight; + if ( + !systemFrozen && + inputContainer && + inputContainer.style.display === "flex" + ) { + setTimeout(() => input.focus(), 50); + } + } + + /* --- EASTER EGGS --- */ + async function triggerHawkins() { + if (hawkinsActive) { + printLine("Closing dimensional gate...", "log-warn"); + await sleep(500); + if (currentMusic) { + currentMusic.stop(); + currentMusic = null; + } + body.classList.remove("hawkins"); + hawkinsActive = false; + printLine("Returned to normal reality.", "log-sys"); + return; + } + + hawkinsActive = true; + printLine("WARNING: Anomalous readings detected...", "log-warn"); + await sleep(600); + printLine("Dimensional instability increasing...", "log-err"); + await sleep(500); + + body.style.filter = "hue-rotate(180deg) contrast(1.5)"; + await sleep(200); + body.style.filter = ""; + await sleep(200); + body.style.filter = "hue-rotate(180deg) contrast(1.5)"; + await sleep(150); + + printLine("CRITICAL: Breach imminent!", "pulse-red"); + await sleep(400); + printLine("Entering the Upside Down...", "log-err"); + await sleep(300); + if (currentMusic) { - currentMusic.stop?.(); + currentMusic.stop(); + currentMusic = null; + } + playSynth("scare"); + currentMusic = playStrangerThingsTheme(); + body.classList.add("hawkins"); + + const vecnaArt = ` + β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆ β–ˆβ–ˆ + β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ + `; + + if (!overlay) return; + + for (let i = 0; i < 3; i++) { + overlay.innerHTML = `
${vecnaArt}
`; + overlay.style.display = "flex"; + overlay.style.background = `rgba(255, 0, 0, ${0.3 + i * 0.2})`; + await sleep(200); + overlay.style.display = "none"; + await sleep(100); + } + + overlay.innerHTML = `
${vecnaArt}
`; + overlay.style.display = "flex"; + overlay.style.background = "rgba(255, 0, 0, 0.7)"; + await sleep(400); + overlay.style.display = "none"; + overlay.innerHTML = ""; + + const sporeInterval = interval(() => { + const spore = document.createElement("div"); + spore.className = "spore"; + spore.style.left = Math.random() * 100 + "%"; + spore.style.top = Math.random() * 100 + "%"; + spore.style.opacity = "0.6"; + body.appendChild(spore); + setTimeout(() => spore.remove(), 3000); + }, 300); + + const glitchInterval = interval(() => { + if (!hawkinsActive) return; + body.style.filter = "hue-rotate(180deg) contrast(1.3) brightness(0.9)"; + setTimeout( + () => { + body.style.filter = ""; + }, + 100 + Math.random() * 200, + ); + }, 2000); + + printLine("", "log-dim"); + printLine("β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", "pulse-red"); + printLine("β–ˆ YOU ARE NOW IN THE UPSIDE DOWN β–ˆ", "pulse-red"); + printLine("β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", "pulse-red"); + printLine("", "log-dim"); + + timeout(() => { + if (hawkinsActive) { + printLine("", "log-dim"); + printLine("Dimensional gate closing automatically...", "log-warn"); + triggerHawkins(); + } + }, 30000); + } + + async function triggerFsociety() { + if (fsocietyActive) { + printLine("Disconnecting from fsociety network...", "log-warn"); + await sleep(500); + if (currentMusic) { + currentMusic.stop(); + currentMusic = null; + } + body.classList.remove("fsociety-boot"); + fsocietyActive = false; + systemFrozen = false; + if (inputContainer) inputContainer.style.display = "flex"; + printLine("Connection terminated.", "log-sys"); + return; + } + + fsocietyActive = true; + systemFrozen = true; + if (inputContainer) inputContainer.style.display = "none"; + if (output) output.innerHTML = ""; + body.classList.add("fsociety-boot"); + + if (currentMusic) { + currentMusic.stop(); + currentMusic = null; + } + currentMusic = playMrRobotTheme(); + + printLine("$ ./fsociety.sh", "log-k"); + await sleep(250); + printLine("[*] Initializing breach protocol...", "log-warn"); + await sleep(180); + printLine("[*] Scanning target: E-Corp mainframe", "log-warn"); + await sleep(200); + printLine( + "[*] Exploiting CVE-2024-1337... 0x" + + Array.from({ length: 8 }, () => + Math.floor(Math.random() * 16) + .toString(16) + .toUpperCase(), + ).join(""), + "log-dim", + ); + await sleep(180); + printLine("[*] Bypassing firewall...", "log-warn"); + await sleep(180); + printLine("[*] Escalating privileges... root access granted", "log-warn"); + await sleep(200); + printLine("[*] Injecting payload... success", "log-warn"); + await sleep(180); + printLine("[*] Establishing backdoor...", "log-warn"); + await sleep(200); + printLine("", "log-dim"); + printLine(" β–ˆβ–ˆ β–ˆβ–ˆ", "fsociety-mask"); + printLine(" β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", "fsociety-mask"); + printLine(" β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ", "fsociety-mask"); + printLine(" β–ˆβ–ˆ β–ˆβ–ˆ", "fsociety-mask"); + printLine(" β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", "fsociety-mask"); + printLine(" β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", "fsociety-mask"); + printLine(" β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ", "fsociety-mask"); + printLine(" β–ˆβ–ˆ β–ˆβ–ˆ", "fsociety-mask"); + printLine(" β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", "fsociety-mask"); + await sleep(400); + printLine("", "log-dim"); + printLine("Hello friend.", "log-k"); + await sleep(350); + printLine("Control is an illusion.", "log-k"); + await sleep(350); + printLine("We are fsociety.", "log-k"); + await sleep(350); + printLine("", "log-dim"); + printLine( + ">>> Accessing E-Corp database... [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100%", + "log-warn", + ); + await sleep(280); + printLine(">>> Encrypting files... [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100%", "log-warn"); + await sleep(280); + printLine(">>> Deleting debt records... [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100%", "log-warn"); + await sleep(280); + printLine("", "log-dim"); + printLine("Mission accomplished. The world is watching.", "log-k"); + await sleep(400); + + printLine("", "log-dim"); + printLine( + "System compromised. Initiating emergency reboot...", + "log-err", + ); + await sleep(1500); + + if (currentMusic) { + currentMusic.stop(); + currentMusic = null; + } + body.classList.remove("fsociety-boot"); + fsocietyActive = false; + systemFrozen = false; + if (output) output.innerHTML = ""; + await sleep(500); + printLine("Rebooting system...", "log-warn"); + await sleep(800); + location.reload(); + } + + async function triggerDeepThought() { + printLine("Initializing Deep Thought...", "log-sys"); + await sleep(600); + printLine("", "log-dim"); + printLine("Deep Thought: Good morning.", "log-k"); + await sleep(800); + printLine("", "log-dim"); + printLine( + "Deep Thought: I am the second greatest computer in the Universe of Time and Space.", + "log-k", + ); + await sleep(1000); + printLine( + "Deep Thought: The Answer to the Ultimate Question...?", + "log-k", + ); + await sleep(1000); + + if (currentMusic) { + currentMusic.stop(); + currentMusic = null; + } + currentMusic = playHitchhikersTheme(); + + printLine("Deep Thought: Thinking...", "log-dim"); + await sleep(2000); + printLine("Deep Thought: I have the answer.", "log-k"); + await sleep(1000); + printLine("", "log-dim"); + printLine("42", "log-k"); + } + + async function initiateMeltdown() { + systemFrozen = true; + if (inputContainer) inputContainer.style.display = "none"; + if (currentMusic) { + currentMusic.stop(); + currentMusic = null; + } + + printLine("CRITICAL: Attempting to delete root filesystem...", "log-err"); + await sleep(500); + printLine("WARNING: Memory corruption detected!", "log-warn"); + await sleep(400); + playSynth("melt"); + + let corruptionCount = 0; + const corruptInterval = interval(() => { + if (!output) return; + const nodes = Array.from(output.childNodes) as HTMLElement[]; + if (nodes.length > 0) { + const randomNode = nodes[Math.floor(Math.random() * nodes.length)]; + if (randomNode.innerText && randomNode.innerText.length > 3) { + const chars = "Β₯Β§ΒΆ$@#%&XØΒ₯€©±×÷"; + const glitchChar = chars[Math.floor(Math.random() * chars.length)]; + randomNode.innerHTML = randomNode.innerHTML.replace( + /[a-zA-Z0-9]/, + `${glitchChar}`, + ); + } + } + corruptionCount++; + if (corruptionCount === 45) { + clearInterval(corruptInterval); + body.classList.add("meltdown"); + playSynth("melt"); + setTimeout(() => { + body.classList.remove("meltdown"); + location.reload(); + }, 2000); + } + }, 80); + } + + /* --- EVENT LISTENERS --- */ + const handleKeydown = (e: KeyboardEvent) => { + // Handle input focus + if ( + !systemFrozen && + inputContainer && + inputContainer.style.display === "flex" && + document.activeElement !== input + ) { + input?.focus(); + } + + if (e.key === "Tab") { + e.preventDefault(); + handleTabComplete(); + return; + } + + try { + playSynth("key"); + } catch (e) {} + + if (e.key === "ArrowUp" && historyIndex > 0) { + historyIndex--; + if (input) input.value = commandHistory[historyIndex]; + } else if ( + e.key === "ArrowDown" && + historyIndex < commandHistory.length - 1 + ) { + historyIndex++; + if (input) input.value = commandHistory[historyIndex]; + } else if (e.key === "ArrowDown") { + historyIndex = commandHistory.length; + if (input) input.value = ""; + } else if (e.key === "Enter") { + runCmd(); + } + }; + + if (input) input.addEventListener("keydown", handleKeydown); + + return () => { + timers.forEach((t) => + typeof t === "number" ? clearInterval(t) : clearTimeout(t), + ); + if (input) input.removeEventListener("keydown", handleKeydown); + if (currentMusic && currentMusic.stop) currentMusic.stop(); + if (body) { + body.classList.remove("hawkins", "meltdown", "fsociety-boot"); + body.style.filter = ""; } }; - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( <> - - .is-dir { color: #5e91ff; font-weight: bold; } - .is-exe { color: var(--phosphor); font-weight: bold; } - `}} /> -
+
+ +
-
- guest@404:~$ +
+ guest@404:~$Β  { - if (e.key === 'Enter') { - e.preventDefault(); - const cmd = (e.target as HTMLInputElement).value.trim(); - (e.target as HTMLInputElement).value = ''; - runCmd(cmd); - } else if (e.key === 'ArrowUp' && historyIndex > 0) { - e.preventDefault(); - const newIndex = historyIndex - 1; - setHistoryIndex(newIndex); - (e.target as HTMLInputElement).value = commandHistory[newIndex] || ''; - } else if (e.key === 'ArrowDown' && historyIndex < commandHistory.length - 1) { - e.preventDefault(); - const newIndex = historyIndex + 1; - setHistoryIndex(newIndex); - (e.target as HTMLInputElement).value = commandHistory[newIndex] || ''; - } else if (e.key === 'ArrowDown') { - e.preventDefault(); - setHistoryIndex(commandHistory.length); - (e.target as HTMLInputElement).value = ''; - } else { - try { - playSynth('key'); - } catch { - // Ignore audio errors - } - } - }} />
diff --git a/app/components/RootProviders.tsx b/app/components/RootProviders.tsx new file mode 100644 index 0000000..4a92600 --- /dev/null +++ b/app/components/RootProviders.tsx @@ -0,0 +1,51 @@ +"use client"; + +import React, { useEffect, useState } from "react"; + +// Lazy load providers to avoid webpack module resolution issues +const AnalyticsProvider = React.lazy(() => + import("@/components/AnalyticsProvider").then((mod) => ({ + default: mod.AnalyticsProvider, + })) +); + +const ToastProvider = React.lazy(() => + import("@/components/Toast").then((mod) => ({ + default: mod.ToastProvider, + })) +); + +const BackgroundBlobs = React.lazy(() => + import("@/components/BackgroundBlobs") +); + +const ChatWidget = React.lazy(() => import("./ChatWidget")); + +export default function RootProviders({ + children, +}: { + children: React.ReactNode; +}) { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + if (!mounted) { + return
{children}
; + } + + return ( + {children}
}> + + + +
{children}
+ +
+
+ + ); +} + diff --git a/app/globals.css b/app/globals.css index 7adc75e..40c5fd2 100644 --- a/app/globals.css +++ b/app/globals.css @@ -121,6 +121,14 @@ div { background: #a8a29e; } +.scrollbar-hide::-webkit-scrollbar { + display: none; +} +.scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; +} + /* Animations */ @keyframes float { 0%, diff --git a/app/layout.tsx b/app/layout.tsx index 984a471..b2a3730 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,11 +2,7 @@ import "./globals.css"; import { Metadata } from "next"; import { Inter } from "next/font/google"; import React from "react"; -import { ToastProvider } from "@/components/Toast"; -import { AnalyticsProvider } from "@/components/AnalyticsProvider"; -import { ClientOnly } from "./components/ClientOnly"; -import BackgroundBlobsClient from "./components/BackgroundBlobsClient"; -import ChatWidget from "./components/ChatWidget"; +import ClientProviders from "./components/ClientProviders"; const inter = Inter({ variable: "--font-inter", @@ -29,16 +25,8 @@ export default function RootLayout({ Dennis Konkol's Portfolio - - - - - - -
{children}
- -
-
+ + {children} ); diff --git a/app/not-found.tsx b/app/not-found.tsx index 547cee7..2cbefdd 100644 --- a/app/not-found.tsx +++ b/app/not-found.tsx @@ -1,5 +1,30 @@ -import KernelPanic404 from './components/KernelPanic404'; +"use client"; + +import { Suspense } from "react"; +import dynamic from "next/dynamic"; + +// Dynamically import KernelPanic404 to avoid SSR issues +const KernelPanic404 = dynamic(() => import("./components/KernelPanic404"), { + ssr: false, + loading: () => ( +
+
Loading terminal...
+
+ ), +}); export default function NotFound() { - return ; + return ( +
+ +
Loading terminal...
+
+ } + > + + + + ); } diff --git a/components/Toast.tsx b/components/Toast.tsx index 0d069d0..7006a03 100644 --- a/components/Toast.tsx +++ b/components/Toast.tsx @@ -139,10 +139,27 @@ interface ToastContextType { const ToastContext = createContext(undefined); +// No-op fallback for SSR or when outside provider +const noopToast: ToastContextType = { + addToast: () => {}, + showToast: () => {}, + showSuccess: () => {}, + showError: () => {}, + showWarning: () => {}, + showInfo: () => {}, + showEmailSent: () => {}, + showEmailError: () => {}, + showProjectSaved: () => {}, + showProjectDeleted: () => {}, + showImportSuccess: () => {}, + showImportError: () => {}, +}; + export const useToast = () => { const context = useContext(ToastContext); + // Return no-op fallback during SSR or if used outside provider if (!context) { - throw new Error('useToast must be used within a ToastProvider'); + return noopToast; } return context; }; diff --git a/next.config.ts b/next.config.ts index 54c4831..dfcd3ee 100644 --- a/next.config.ts +++ b/next.config.ts @@ -29,9 +29,14 @@ const nextConfig: NextConfig = { }, // Performance optimizations - experimental: { - optimizePackageImports: ["lucide-react", "framer-motion"], - }, + // NOTE: `optimizePackageImports` can cause dev-time webpack runtime issues with some setups. + // Keep it enabled for production builds only. + experimental: + process.env.NODE_ENV === "production" + ? { + optimizePackageImports: ["lucide-react", "framer-motion"], + } + : {}, // Image optimization images: { @@ -54,7 +59,7 @@ const nextConfig: NextConfig = { }, // Webpack configuration - webpack: (config, { isServer, dev, webpack }) => { + webpack: (config) => { // Fix for module resolution issues config.resolve.fallback = { ...config.resolve.fallback, @@ -63,24 +68,6 @@ const nextConfig: NextConfig = { tls: false, }; - // Safari + React 19 + Next.js 15 compatibility fixes - if (dev && !isServer) { - // Disable module concatenation to prevent factory initialization issues - config.optimization = { - ...config.optimization, - concatenateModules: false, - providedExports: false, - usedExports: false, - }; - - // Add DefinePlugin to ensure proper environment detection - config.plugins.push( - new webpack.DefinePlugin({ - "process.env.__NEXT_DISABLE_REACT_STRICT_MODE": JSON.stringify(false), - }), - ); - } - return config; },