major: statically-generated resume with Vike
This commit is contained in:
+142
@@ -0,0 +1,142 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# Cloudflare
|
||||
.wrangler/
|
||||
|
||||
# Vercel
|
||||
.vercel/
|
||||
|
||||
# Sentry Vite Plugin
|
||||
.env.sentry-build-plugin
|
||||
|
||||
# aws-cdk
|
||||
.cdk.staging
|
||||
cdk.out
|
||||
@@ -0,0 +1,2 @@
|
||||
nodejs 22.15.0
|
||||
pnpm 9.7.1
|
||||
@@ -0,0 +1,53 @@
|
||||
Generated with [vike.dev/new](https://vike.dev/new) ([version 471](https://www.npmjs.com/package/create-vike/v/0.0.471)) using this command:
|
||||
|
||||
```sh
|
||||
pnpm create vike@latest --react --compiled-css --cloudflare --eslint
|
||||
```
|
||||
|
||||
## Contents
|
||||
|
||||
* [React](#react)
|
||||
|
||||
* [`/pages/+config.ts`](#pagesconfigts)
|
||||
* [Routing](#routing)
|
||||
* [`/pages/_error/+Page.jsx`](#pages_errorpagejsx)
|
||||
* [`/pages/+onPageTransitionStart.ts` and `/pages/+onPageTransitionEnd.ts`](#pagesonpagetransitionstartts-and-pagesonpagetransitionendts)
|
||||
* [SSR](#ssr)
|
||||
* [HTML Streaming](#html-streaming)
|
||||
|
||||
## React
|
||||
|
||||
This app is ready to start. It's powered by [Vike](https://vike.dev) and [React](https://react.dev/learn).
|
||||
|
||||
### `/pages/+config.ts`
|
||||
|
||||
Such `+` files are [the interface](https://vike.dev/config) between Vike and your code. It defines:
|
||||
|
||||
* A default [`<Layout>` component](https://vike.dev/Layout) (that wraps your [`<Page>` components](https://vike.dev/Page)).
|
||||
* A default [`title`](https://vike.dev/title).
|
||||
* Global [`<head>` tags](https://vike.dev/head-tags).
|
||||
|
||||
### Routing
|
||||
|
||||
[Vike's built-in router](https://vike.dev/routing) lets you choose between:
|
||||
|
||||
* [Filesystem Routing](https://vike.dev/filesystem-routing) (the URL of a page is determined based on where its `+Page.jsx` file is located on the filesystem)
|
||||
* [Route Strings](https://vike.dev/route-string)
|
||||
* [Route Functions](https://vike.dev/route-function)
|
||||
|
||||
### `/pages/_error/+Page.jsx`
|
||||
|
||||
The [error page](https://vike.dev/error-page) which is rendered when errors occur.
|
||||
|
||||
### `/pages/+onPageTransitionStart.ts` and `/pages/+onPageTransitionEnd.ts`
|
||||
|
||||
The [`onPageTransitionStart()` hook](https://vike.dev/onPageTransitionStart), together with [`onPageTransitionEnd()`](https://vike.dev/onPageTransitionEnd), enables you to implement page transition animations.
|
||||
|
||||
### SSR
|
||||
|
||||
SSR is enabled by default. You can [disable it](https://vike.dev/ssr) for all your pages or only for some pages.
|
||||
|
||||
### HTML Streaming
|
||||
|
||||
You can enable/disable [HTML streaming](https://vike.dev/stream) for all your pages, or only for some pages while still using it for others.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
-44
@@ -1,44 +0,0 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&display=swap");
|
||||
|
||||
/* @font-face {
|
||||
font-family: Lato;
|
||||
src: url("Lato2OFL/Lato-Regular.ttf");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Lato;
|
||||
src: url("Lato2OFL/Lato-Bold.ttf");
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Lato;
|
||||
src: url("Lato2OFL/Lato-Italic.ttf");
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Lato;
|
||||
src: url("Lato2OFL/Lato-BoldItalic.ttf");
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
} */
|
||||
|
||||
/* @page {
|
||||
@bottom-center {
|
||||
content: "https://sakal.us";
|
||||
font-size: 0.8em;
|
||||
color: #aaa;
|
||||
font-family: Lato;
|
||||
}
|
||||
@top-center {
|
||||
content: "CSS Paged Media Tutorial by Andreas Jung";
|
||||
font-size: 0.8em;
|
||||
color: #aaa;
|
||||
font-family: Lato;
|
||||
}
|
||||
} */
|
||||
|
||||
/* body {
|
||||
font-family: Lato;
|
||||
} */
|
||||
@@ -0,0 +1,179 @@
|
||||
export const contactInfo = {
|
||||
name: "Brian Sakal",
|
||||
email: "brian@sakal.us",
|
||||
phone: "305-930-0248",
|
||||
website: "https://git.sakal.us/avraham",
|
||||
location: "Passaic, NJ",
|
||||
};
|
||||
|
||||
export const mainSkills = [
|
||||
"Javascript/Typescript",
|
||||
"React",
|
||||
"Next.js",
|
||||
"Node.js",
|
||||
"Express.js",
|
||||
"Docker",
|
||||
"MySQL",
|
||||
"Clickhouse",
|
||||
"DevOps",
|
||||
"Kubernetes",
|
||||
"Linux",
|
||||
"Cloudflare",
|
||||
"Vercel",
|
||||
"S3",
|
||||
];
|
||||
|
||||
export const exposedSkills = [
|
||||
"PostgreSQL",
|
||||
"Elasticsearch",
|
||||
"Redis",
|
||||
"RethinkDB",
|
||||
"Helm",
|
||||
"nginx",
|
||||
"React Native",
|
||||
"Swagger",
|
||||
];
|
||||
|
||||
export const employment = [
|
||||
{
|
||||
title: "Lead Developer (Full-Stack)",
|
||||
company: "TorahAnytime.com",
|
||||
location: "Flushing, NY",
|
||||
start: "June 2022",
|
||||
end: "Present",
|
||||
highlights: [
|
||||
// From old resume:
|
||||
// "Fixed/troubleshooted bugs and added features across multiple legacy codebases",
|
||||
// "Consolidated cloud resources by using Kubernetes.",
|
||||
// "Transitioned a legacy Cloudflare/nginx TLD site to Vercel, while maintaining custom nginx routes on the TLD, plus the entire legacy site under a subdomain.",
|
||||
// "Reduced time-to-deployment from 5 minutes to 15 seconds with locally-runnable deploy scripts; besides setting up Drone/Gitlab CI/CD pipelines.",
|
||||
// "Architected custom analytics backend w/ Clickhouse. Reduced query times from minutes to milliseconds.",
|
||||
// "Implemented a custom IVR phone system to dynamically browse content.",
|
||||
// "Deployed and configured various supporting/ancillary services in Kubernetes, including Gitlab, private Docker & NPM registries.",
|
||||
// "Implemented OpenTelemetry tracing visualized in Grafana, decreasing transcoder troubleshooting by 50%.",
|
||||
// "Implemented various asynchronous workflows, including a new video transcoder, in Temporal; thus completely severing our dependence on Vimeo, reducing costs by $40k/year.",
|
||||
// From Otta resume:
|
||||
"General full-stack work (frontend implementation in Next.js, adding endpoints to api, running database migrations in MySQL, updating Clickhouse with those schema changes, etc.)",
|
||||
"Architected and implemented an in-house transcoding/content-delivery system based on Temporal, Cloudflare, and Backblaze B2 to replace Vimeo; saving $70k/year.",
|
||||
"Setup generic events analytics system in Clickhouse to replace MySQL, Redis, and (eventually) Google Analytics, for faster and more granular analytics over arbitrary events and event payloads; significantly improving query times from minutes to milliseconds",
|
||||
"Legacy code maintenance/incremental refactoring",
|
||||
"Consolidated various async jobs (e.g. notifications, daily/weekly digest, delayed release, etc.) into type-safe Temporal workflows, enhancing developer experience and setting conventions for easy implementation of future workflows",
|
||||
"Designed and deployed a multi-instance tRPC server for type-safe endpoints for the frontend",
|
||||
`Adapted Agile/Scrum to accomodate stakeholder expectations of simultaneous planned and unplanned (i.e. during a Sprint) throughput and turnaround, while keeping longer-term goals predictable.`,
|
||||
"Crafted multi-stage Dockerfiles to leverage layer caching in various projects",
|
||||
"Reduced deployment time from 5 minutes to 15 seconds by implementing locally-runnable deploy scripts, besides setting up Github Actions CI/CD pipelines.",
|
||||
"Developed a custom IVR phone system for dynamically browsing our content.",
|
||||
"Deployed and configured various supporting services in Kubernetes such as Grafana, private Docker & NPM registries.",
|
||||
"Implemented OpenTelemetry tracing visualized in Grafana, resulting in 50% decrease in legacy transcoder troubleshooting time.",
|
||||
"Designed various parameterized Grafana dashboards for at-a-glance analysis of user stats.",
|
||||
"Implemented two integrations: MySQL-Clickhouse sync (using Clickhouse primitives), and MySQL-Salesforce sync (on Temporal).",
|
||||
"Transitioned legacy Cloudflare/nginx TLD site to Vercel, while maintaining custom nginx routes on the TLD and hosting the entire legacy site under a subdomain.",
|
||||
],
|
||||
},
|
||||
// {
|
||||
// title: "Assistant Manager",
|
||||
// company: "Sureknit Inc. Property Management",
|
||||
// location: "East Flatbush, NY",
|
||||
// start: "February 2020",
|
||||
// end: "June 2022",
|
||||
// highlights: [
|
||||
// "Kept accurate records of tenant rent payments.",
|
||||
// "Balanced and monitored bank accounts for all subsidiary companies.",
|
||||
// "Furnished necessary documentation for various real estate operations, such as new leases, property sales, etc.",
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// title: "Architect Intern",
|
||||
// company: "Sandy Hacohen",
|
||||
// location: "Flushing, NY",
|
||||
// start: "July 2018",
|
||||
// end: "November 2018",
|
||||
// highlights: [
|
||||
// "Produced architectural drawings of various points-of-view based on given floorplans.",
|
||||
// "Adjusted existing floorplans to spec.",
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// title: "Operations Manager",
|
||||
// company: "Tax Opportunities America",
|
||||
// location: "Flushing, NY",
|
||||
// start: "April 2014",
|
||||
// end: "May 2015",
|
||||
// highlights: [
|
||||
// "Interfaced with clients, prepared necessary documentation and submitted applications to government programs on behalf of clients.",
|
||||
// "Monitored and accommodated deadlines, missing client data, and when client promised to have the data available",
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// title: "Representative",
|
||||
// company: "Computer-Aided Engineering Network (CAEN) Hotline",
|
||||
// location: "U. of Michigan",
|
||||
// start: "2007",
|
||||
// end: "2009, 2010",
|
||||
// highlights: [
|
||||
// "Provided first-response assistance to students and collecting pertinent information to arrange for involvement of specialized staff.",
|
||||
// ],
|
||||
// },
|
||||
];
|
||||
|
||||
export const projectsHobbies = [
|
||||
{
|
||||
title: "Self-host email for the sakal.us domain",
|
||||
highlights: ["Vultr-Hosted", "Postfix for SMTP", "Dovecot for IMAP"],
|
||||
},
|
||||
{
|
||||
title: "Self-host a Kubernetes cluster",
|
||||
highlights: [
|
||||
"k3s",
|
||||
"Private Docker image registry",
|
||||
"cert-manager",
|
||||
"Private coding projects",
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Self-host a Gitea code repository",
|
||||
highlights: [
|
||||
"Deployed within the above Kubernetes cluster. Available at https://git.sakal.us",
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Personal coding blog",
|
||||
highlights: ["Astro", "Cloudflare Pages", "https://blog.sakal.us"],
|
||||
},
|
||||
{
|
||||
title: "Calendar Optimizer project",
|
||||
highlights: [
|
||||
"Stock options research platform",
|
||||
"Preact",
|
||||
"trpc",
|
||||
"Clickhouse",
|
||||
"https://calendar-optimizer-frontend.sakal.us",
|
||||
],
|
||||
},
|
||||
// {
|
||||
// title: "Custom From-Scratch Full-Stack eCommerce website",
|
||||
// highlights: [
|
||||
// "Previously at piazzaoptical.com",
|
||||
// "mithril.js",
|
||||
// "nginx as reverse proxy and TLS termination",
|
||||
// "lua-http on LuaJIT",
|
||||
// "LMDB",
|
||||
// ],
|
||||
// },
|
||||
];
|
||||
|
||||
export const education = [
|
||||
{
|
||||
title: "B.S. in Aerospace Engineering",
|
||||
location: "University of Michigan, Ann Arbor, MI",
|
||||
start: "Sept. 2006",
|
||||
end: "April 2009, Sept. 2010, April 2011",
|
||||
gpa: "3.185",
|
||||
},
|
||||
// {
|
||||
// title: "Ph.D. in Rabbinics",
|
||||
// location: "Rabbinical Seminary of America, Flushing, NY",
|
||||
// start: "April 2009",
|
||||
// end: "April 2010, April 2011, January 2020",
|
||||
// },
|
||||
];
|
||||
@@ -0,0 +1,72 @@
|
||||
import eslint from "@eslint/js";
|
||||
import react from "eslint-plugin-react";
|
||||
import globals from "globals";
|
||||
import tseslint, { type ConfigArray } from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: [
|
||||
"dist/*",
|
||||
// Temporary compiled files
|
||||
"**/*.ts.build-*.mjs",
|
||||
|
||||
// JS files at the root of the project
|
||||
"*.js",
|
||||
"*.cjs",
|
||||
"*.mjs",
|
||||
],
|
||||
},
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
warnOnUnsupportedTypeScriptVersion: false,
|
||||
sourceType: "module",
|
||||
ecmaVersion: "latest",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
1,
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-namespace": 0,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
files: ["**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}"],
|
||||
...react.configs.flat.recommended,
|
||||
languageOptions: {
|
||||
...react.configs.flat.recommended.languageOptions,
|
||||
globals: {
|
||||
...globals.serviceworker,
|
||||
...globals.browser,
|
||||
},
|
||||
},
|
||||
|
||||
settings: {
|
||||
react: {
|
||||
version: "detect",
|
||||
},
|
||||
},
|
||||
} as ConfigArray[number],
|
||||
|
||||
react.configs.flat["jsx-runtime"] as ConfigArray[number],
|
||||
|
||||
{
|
||||
rules: {
|
||||
"react/no-unknown-property": [
|
||||
"error",
|
||||
{
|
||||
ignore: ["css"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
-343
@@ -1,343 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<section class="header">
|
||||
<h2 class="lg bold">Brian Sakal</h2>
|
||||
</section>
|
||||
<section class="contact-info">
|
||||
<ul class="inline">
|
||||
<li>Passaic, NJ</li>
|
||||
<li>305-930-0248</li>
|
||||
<li><a href="https://git.sakal.us/">Git</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="sections">
|
||||
<section class="relevant-skills">
|
||||
<label>
|
||||
<div class="fit-content">
|
||||
<div class="bold">Skills/Technologies</div>
|
||||
</div>
|
||||
</label>
|
||||
<div>
|
||||
<ul class="inline">
|
||||
<li>Docker</li>
|
||||
<li>DevOps (Logging, Monitoring, Grafana, CI/CD)</li>
|
||||
<li>Kubernetes</li>
|
||||
<li>Node.js</li>
|
||||
<li>Javascript/Typescript</li>
|
||||
<li>React</li>
|
||||
<li>MySQL/PostgreSQL</li>
|
||||
<li>Elasticsearch</li>
|
||||
<li>Clickhouse</li>
|
||||
<li>Linux</li>
|
||||
<li>Cloudflare</li>
|
||||
<li>Redis</li>
|
||||
<li>RethinkDB</li>
|
||||
<li>Helm</li>
|
||||
<li>nginx</li>
|
||||
<li>Vercel</li>
|
||||
<li>S3</li>
|
||||
<li>Express.js</li>
|
||||
<li>React</li>
|
||||
<li>React Native</li>
|
||||
<li>Next.js</li>
|
||||
<li>Swagger</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section class="employment">
|
||||
<label>
|
||||
<div class="fit-content">
|
||||
<span class="bold">Employment</span>
|
||||
<span class="sm italic right">(Most recent)</span>
|
||||
</div>
|
||||
</label>
|
||||
<div>
|
||||
<ul class="no-bullet">
|
||||
<li>
|
||||
<div class="space-between">
|
||||
<div>
|
||||
<span class="bold">Senior Full-Stack Developer,</span>
|
||||
<span>TorahAnytime.com, Flushing, NY</span>
|
||||
</div>
|
||||
<div class="italic right">June 2022–Present</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
<!-- <li>
|
||||
Fixed/troubleshooted bugs and added features across multiple
|
||||
legacy codebases
|
||||
</li>
|
||||
<li>Consolidated cloud resources by using Kubernetes.</li> -->
|
||||
<li>
|
||||
Transitioned a legacy Cloudflare/nginx TLD site to Vercel,
|
||||
while maintaining custom nginx routes on the TLD, plus the
|
||||
entire legacy site under a subdomain.
|
||||
</li>
|
||||
<li>
|
||||
Reduced time-to-deployment from 5 minutes to 15 seconds with
|
||||
locally-runnable deploy scripts; besides setting up
|
||||
Drone/Gitlab CI/CD pipelines.
|
||||
</li>
|
||||
<li>
|
||||
Architected custom analytics backend w/ Clickhouse. Reduced
|
||||
query times from minutes to milliseconds.
|
||||
</li>
|
||||
<li>
|
||||
Implemented a custom IVR phone system to dynamically browse
|
||||
content.
|
||||
</li>
|
||||
<li>
|
||||
Deployed and configured various supporting/ancillary
|
||||
services in Kubernetes, including Gitlab, private Docker &
|
||||
NPM registries.
|
||||
</li>
|
||||
<li>
|
||||
Implemented OpenTelemetry tracing visualized in Grafana,
|
||||
decreasing transcoder troubleshooting by 50%.
|
||||
</li>
|
||||
<li>
|
||||
Implemented various asynchronous workflows, including a new
|
||||
video transcoder, in Temporal; thus completely severing our
|
||||
dependence on Vimeo, reducing costs by $40k/year.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="space-between">
|
||||
<div>
|
||||
<span class="bold">Assistant Manager,</span>
|
||||
<span
|
||||
>Sureknit Inc. Property Management, East Flatbush, NY</span
|
||||
>
|
||||
</div>
|
||||
<div class="italic right">February 2020–June 2022</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
<li>Kept accurate records of tenant rent payments.</li>
|
||||
<li>
|
||||
Balanced and monitored bank accounts for all subsidiary
|
||||
companies.
|
||||
</li>
|
||||
<li>
|
||||
Furnished necessary documentation for various real estate
|
||||
operations, such as new leases, property sales, etc.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<!-- <li>
|
||||
<div>
|
||||
<span class="bold">Architect Intern,</span>
|
||||
<span>Sandy Hacohen, Flushing, NY</span>
|
||||
</div>
|
||||
<div class="italic right">July 2018–November 2018</div>
|
||||
<div>
|
||||
<ul>
|
||||
<li>
|
||||
Produced architectural drawings of various points-of-view
|
||||
based on given floorplans.
|
||||
</li>
|
||||
<li>Adjusted existing floorplans to spec.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li> -->
|
||||
<!-- <li>
|
||||
<div class="space-between">
|
||||
<div>
|
||||
<span class="bold">Operations Manager,</span>
|
||||
<span>Tax Opportunities America, Flushing, NY</span>
|
||||
</div>
|
||||
<div class="italic right">April 2014–May 2015</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
<li>
|
||||
Interfaced with clients, prepared necessary documentation
|
||||
and submitted applications to government programs on behalf
|
||||
of clients.
|
||||
</li>
|
||||
<li>
|
||||
Monitored and accommodated deadlines, missing client data,
|
||||
and when client promised to have the data available
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li> -->
|
||||
<!-- <li>
|
||||
<div class="space-between">
|
||||
<div>
|
||||
<span class="bold">Representative,</span>
|
||||
<span
|
||||
>Computer-Aided Engineering Network (CAEN) Hotline, U. of
|
||||
Michigan</span
|
||||
>
|
||||
</div>
|
||||
<div class="italic right">2007–2009, 2010–2011</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
<li>
|
||||
Provided first-response assistance to students and
|
||||
collecting pertinent information to arrange for involvement
|
||||
of specialized staff.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section class="projects-hobbies">
|
||||
<label>
|
||||
<div class="fit-content">
|
||||
<div class="bold">Projects/Hobbies</div>
|
||||
</div>
|
||||
</label>
|
||||
<div>
|
||||
<ul class="no-bullet">
|
||||
<li>
|
||||
<div>
|
||||
<span class="bold"
|
||||
>Self-host email for the sakal.us domain</span
|
||||
>
|
||||
<span
|
||||
><ul class="inline">
|
||||
<li>Vultr-Hosted</li>
|
||||
<li>Postfix for SMTP</li>
|
||||
<li>Dovecot for IMAP</li>
|
||||
</ul></span
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
<span class="bold">Self-host a Kubernetes cluster</span>
|
||||
<span
|
||||
><ul class="inline">
|
||||
<li><code>k3s</code></li>
|
||||
<li>Private Docker image registry</li>
|
||||
<li>
|
||||
<code>cert-manager</code>
|
||||
</li>
|
||||
<li>Private coding projects</li>
|
||||
</ul></span
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
<span class="bold">Self-host a Gitea code repository</span>
|
||||
<span
|
||||
>Deployed within the above Kubernetes cluster. Available at
|
||||
<a href="https://git.sakal.us/">https://git.sakal.us</a></span
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
<span class="bold"
|
||||
>Personal coding blog (<a
|
||||
href="https://git.sakal.us/avraham/blog-astro"
|
||||
>Code</a
|
||||
>)</span
|
||||
>
|
||||
<span
|
||||
><ul class="inline">
|
||||
<li>Astro</li>
|
||||
<li>Cloudflare Pages</li>
|
||||
<li>
|
||||
<a href="https://blog.sakal.us/">https://blog.sakal.us</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
<span class="bold"
|
||||
>Calendar Optimizer project (<a
|
||||
href="https://git.sakal.us/avraham/calendar-optimizer"
|
||||
>Code</a
|
||||
>)</span
|
||||
>
|
||||
<span
|
||||
><ul class="inline">
|
||||
<li>Stock options research platform</li>
|
||||
<li>Preact</li>
|
||||
<li>trpc</li>
|
||||
<li>Clickhouse</li>
|
||||
<li>
|
||||
<a href="https://calendar-optimizer-frontend.sakal.us"
|
||||
>https://calendar-optimizer-frontend.sakal.us</a
|
||||
>
|
||||
</li>
|
||||
</ul></span
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
<span class="bold"
|
||||
>Custom From-Scratch Full-Stack eCommerce website (<a
|
||||
href="https://git.sakal.us/avraham/piazzaoptical.com"
|
||||
>Code</a
|
||||
>)</span
|
||||
>
|
||||
<span
|
||||
><ul class="inline">
|
||||
<li>Previously at piazzaoptical.com</li>
|
||||
<li>
|
||||
<a href="https://mithril.js.org/">mithril.js</a>
|
||||
</li>
|
||||
<li>nginx as reverse proxy and TLS termination</li>
|
||||
<li>
|
||||
<a href="https://daurnimator.github.io/lua-http/0.4/"
|
||||
>lua-http</a
|
||||
>
|
||||
on <a href="https://luajit.org/">LuaJIT</a>
|
||||
</li>
|
||||
<li><a href="http://www.lmdb.tech/doc/">LMDB</a></li>
|
||||
</ul></span
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section class="education">
|
||||
<label>
|
||||
<span class="bold">Education</span>
|
||||
</label>
|
||||
<div>
|
||||
<ul class="no-bullet">
|
||||
<li>
|
||||
<div class="space-between">
|
||||
<div>
|
||||
<span class="bold">B.S. in Aerospace Engineering,</span>
|
||||
<span>University of Michigan, Ann Arbor, MI</span>
|
||||
</div>
|
||||
<div class="italic right">
|
||||
Sept. 2006–April 2009, Sept. 2010–April 2011, GPA 3.185
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<!-- <li>
|
||||
<div>
|
||||
<span class="bold">Ph.D. in Rabbinics,</span>
|
||||
<span>Rabbinical Seminary of America, Flushing, NY</span>
|
||||
</div>
|
||||
<div class="italic right">
|
||||
April 2009–April 2010, April 2011–January 2020
|
||||
</div>
|
||||
</li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,19 @@
|
||||
import "./style.css";
|
||||
|
||||
export default function LayoutDefault({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
css={{
|
||||
display: "flex",
|
||||
maxWidth: 1024,
|
||||
margin: "auto",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* Reset */
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
@import url("./common.css");
|
||||
@page {
|
||||
size: letter;
|
||||
margin: 0.5in;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "vike dev",
|
||||
"build": "vike build",
|
||||
"preview": "run-s build preview:wrangler",
|
||||
"lint": "eslint .",
|
||||
"preview:wrangler": "wrangler pages dev",
|
||||
"deploy:wrangler": "wrangler pages deploy",
|
||||
"deploy": "run-s build deploy:wrangler"
|
||||
},
|
||||
"dependencies": {
|
||||
"vike": "^0.4.237",
|
||||
"@compiled/react": "^0.18.6",
|
||||
"@vitejs/plugin-react": "^5.0.0",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"vike-react": "^0.6.5",
|
||||
"vike-cloudflare": "^0.1.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.2",
|
||||
"vite": "^7.1.2",
|
||||
"vite-plugin-compiled-react": "^1.3.1",
|
||||
"eslint": "^9.33.0",
|
||||
"@eslint/js": "^9.33.0",
|
||||
"typescript-eslint": "^8.39.1",
|
||||
"globals": "^16.3.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"@types/react": "^19.1.10",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@cloudflare/workers-types": "^4.20250816.0",
|
||||
"wrangler": "^4.30.0",
|
||||
"npm-run-all2": "^8.0.4"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { Config } from "vike/types";
|
||||
import vikeReact from "vike-react/config";
|
||||
import Layout from "../layouts/LayoutDefault.js";
|
||||
|
||||
// Default config (can be overridden by pages)
|
||||
// https://vike.dev/config
|
||||
|
||||
export default {
|
||||
// https://vike.dev/Layout
|
||||
Layout,
|
||||
|
||||
// https://vike.dev/head-tags
|
||||
title: "Brian Sakal | Resume",
|
||||
description: "Resume Auto-Generated from Metadata",
|
||||
|
||||
extends: vikeReact,
|
||||
} satisfies Config;
|
||||
@@ -0,0 +1,19 @@
|
||||
import { usePageContext } from "vike-react/usePageContext";
|
||||
|
||||
export default function Page() {
|
||||
const { is404 } = usePageContext();
|
||||
if (is404) {
|
||||
return (
|
||||
<>
|
||||
<h1>404 Page Not Found</h1>
|
||||
<p>This page could not be found.</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<h1>500 Internal Server Error</h1>
|
||||
<p>Something went wrong.</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
import { useData } from "vike-react/useData";
|
||||
import type { Data } from "./+data";
|
||||
import "../../styles.css";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div
|
||||
css={{
|
||||
fontFamily: '"EB Garamond", serif',
|
||||
fontOpticalSizing: "auto",
|
||||
fontWeight: 400,
|
||||
fontStyle: "normal",
|
||||
fontSize: "0.9em",
|
||||
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
css={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "30%",
|
||||
backgroundColor: "lavender",
|
||||
padding: "1em",
|
||||
gap: "1em",
|
||||
}}
|
||||
>
|
||||
<Header />
|
||||
<MainSkills />
|
||||
<ExposedSkills />
|
||||
</div>
|
||||
<div
|
||||
css={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "70%",
|
||||
padding: "1em",
|
||||
}}
|
||||
>
|
||||
<Employment />
|
||||
<ProjectsHobbies />
|
||||
<Education />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Header() {
|
||||
const { contactInfo } = useData<Data>();
|
||||
return (
|
||||
<div
|
||||
css={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<section>
|
||||
<div>
|
||||
<img
|
||||
src="/assets/resume-image.jpg"
|
||||
alt="headshot"
|
||||
css={{ width: "14em", borderRadius: "50%", objectFit: "contain" }}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h2 css={{ marginBottom: "0.3em" }} className="lg bold">
|
||||
{contactInfo.name}
|
||||
</h2>
|
||||
</section>
|
||||
<section css={{ textAlign: "center" }}>
|
||||
<ul className="inline">
|
||||
<li>{contactInfo.phone}</li>
|
||||
<li>{contactInfo.email}</li>
|
||||
</ul>
|
||||
<ul className="inline">
|
||||
<li>{contactInfo.location}</li>
|
||||
<li>
|
||||
<a href={contactInfo.website}>{contactInfo.website}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function MainSkills() {
|
||||
const { mainSkills } = useData<Data>();
|
||||
return (
|
||||
<section className="relevant-skills">
|
||||
<h3>Main Skills/Technologies</h3>
|
||||
<div>
|
||||
<ul className="inline">
|
||||
{mainSkills.map((skill) => (
|
||||
<li>{skill}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function ExposedSkills() {
|
||||
const { exposedSkills } = useData<Data>();
|
||||
return (
|
||||
<section className="relevant-skills">
|
||||
<h3>Have Used</h3>
|
||||
<div>
|
||||
<ul className="inline">
|
||||
{exposedSkills.map((skill) => (
|
||||
<li>{skill}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function Employment() {
|
||||
const { employment } = useData<Data>();
|
||||
return (
|
||||
<section className="employment">
|
||||
<h1>
|
||||
<div className="fit-content">
|
||||
<span className="bold">Employment </span>
|
||||
<span css={{ fontWeight: 300 }} className="sm italic right">
|
||||
(Most recent)
|
||||
</span>
|
||||
</div>
|
||||
</h1>
|
||||
<div>
|
||||
<ul className="no-bullet">
|
||||
{employment.map((employment) => (
|
||||
<li>
|
||||
<div className="space-between">
|
||||
<div>
|
||||
<span className="bold">{employment.title},</span>
|
||||
<span>
|
||||
{employment.company}, {employment.location}
|
||||
</span>
|
||||
</div>
|
||||
<div className="italic right">
|
||||
{employment.start}-{employment.end}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
{employment.highlights.map((highlight) => (
|
||||
<li>{highlight}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function ProjectsHobbies() {
|
||||
const { projectsHobbies } = useData<Data>();
|
||||
return (
|
||||
<section className="projects-hobbies">
|
||||
<h1>
|
||||
<div className="fit-content">
|
||||
<div className="bold">Projects/Hobbies</div>
|
||||
</div>
|
||||
</h1>
|
||||
<div>
|
||||
<ul className="no-bullet">
|
||||
{projectsHobbies.map((projectHobby) => (
|
||||
<li>
|
||||
<div>
|
||||
<span className="bold">{projectHobby.title}</span>
|
||||
<span>
|
||||
<ul className="inline">
|
||||
{projectHobby.highlights.map((highlight) => (
|
||||
<li>{highlight}</li>
|
||||
))}
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function Education() {
|
||||
const { education } = useData<Data>();
|
||||
return (
|
||||
<section className="education">
|
||||
<h1>
|
||||
<span className="bold">Education</span>
|
||||
</h1>
|
||||
<div>
|
||||
<ul className="no-bullet">
|
||||
{education.map((education) => (
|
||||
<li>
|
||||
<div className="space-between">
|
||||
<div>
|
||||
<span className="bold">{education.title},</span>
|
||||
<span>{education.location}</span>
|
||||
</div>
|
||||
<div className="italic right">
|
||||
{education.start}–{education.end}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import * as resumeData from "../../database/resume.js";
|
||||
|
||||
export default function data() {
|
||||
return resumeData;
|
||||
}
|
||||
|
||||
export type Data = ReturnType<typeof data>;
|
||||
Generated
+5280
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"module": "ESNext",
|
||||
"noEmit": true,
|
||||
"moduleResolution": "Bundler",
|
||||
"target": "ES2022",
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable",
|
||||
"ESNext"
|
||||
],
|
||||
"types": [
|
||||
"vite/client",
|
||||
"vike-react",
|
||||
"vike-cloudflare/types"
|
||||
],
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "react"
|
||||
},
|
||||
"exclude": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { pages } from "vike-cloudflare";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import { compiled } from "vite-plugin-compiled-react";
|
||||
import vike from "vike/plugin";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vike(),
|
||||
compiled({
|
||||
extract: true,
|
||||
}),
|
||||
react(),
|
||||
pages(),
|
||||
],
|
||||
build: {
|
||||
target: "es2022",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
name = "my-app"
|
||||
compatibility_date = "2024-09-29"
|
||||
pages_build_output_dir = "./dist/cloudflare"
|
||||
compatibility_flags = [ "nodejs_compat" ]
|
||||
Reference in New Issue
Block a user