+ Hi my name is Xavier Royer and I'm a physics major and Computer
+ Science minor at Cal Poly! I love working on any STEM related
+ projects. Other things I enjoy are reading literature, running,
+ basketball, spikeball, learning new things, and pretty much
+ anything outdoors!
+
+
+
+
+ >
+ );
+}
+
+/*
+
+ Xavier's Website
+
+
+*/
diff --git a/bootcamp-milestone-2/src/app/projectData.ts b/bootcamp-milestone-2/src/app/projectData.ts
new file mode 100644
index 000000000..a14f63659
--- /dev/null
+++ b/bootcamp-milestone-2/src/app/projectData.ts
@@ -0,0 +1,27 @@
+import connectDB from "../database/database";
+import Project from "../database/projectSchema";
+
+var projects
+
+export default getProjects;
+
+export async function getProjects() {
+ await connectDB(false); // ensure DB connection
+
+ try {
+ // query for all blogs and sort by date (newest first)
+ const projectResults = await Project.find().sort({ date: -1 }).orFail();
+ console.log("projectresults " + projectResults);
+ return projectResults;
+ } catch (err: any) {
+ console.log("error: " +err?.message);
+ return [];
+ }
+}
+
+/*
+export async function getProject(slug: string) {
+ projects = await getProjects()
+ return projects.find(b => b.slug === slug);
+}
+*/
\ No newline at end of file
diff --git a/bootcamp-milestone-2/src/app/projects/page.tsx b/bootcamp-milestone-2/src/app/projects/page.tsx
new file mode 100644
index 000000000..c484169fb
--- /dev/null
+++ b/bootcamp-milestone-2/src/app/projects/page.tsx
@@ -0,0 +1,26 @@
+import ProjectPreview from '@/src/components/projectPreview';
+import _blogs from '../blogData';
+import getProjects from '../projectData';
+
+export default async function Project() {
+ const projects = await getProjects();
+ console.log("test");
+ console.log(projects);
+ return (
+
+ <>
+
+
+ {projects.map(project =>
+
+ )}
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/bootcamp-milestone-2/src/app/resume/page.tsx b/bootcamp-milestone-2/src/app/resume/page.tsx
new file mode 100644
index 000000000..2a66ed94c
--- /dev/null
+++ b/bootcamp-milestone-2/src/app/resume/page.tsx
@@ -0,0 +1,15 @@
+
+
+
+export default function Resume() {
+ return (
+ <>
+
+
+ Resume
+
+
+
+ >
+)
+}
diff --git a/bootcamp-milestone-2/src/components/blogPreview.module.css b/bootcamp-milestone-2/src/components/blogPreview.module.css
new file mode 100644
index 000000000..a91161af6
--- /dev/null
+++ b/bootcamp-milestone-2/src/components/blogPreview.module.css
@@ -0,0 +1,61 @@
+/*Blog Page code*/
+
+/*blog background*/
+.blog body {
+ background-color: rgba(240, 236, 228, 1);
+}
+
+/*container for all blog events*/
+#blog-events {
+ width: 400px;
+ display: flex;
+ flex-direction: column;
+ outline-width: 0px;
+ outline-color: aqua;
+ outline-style: solid;
+ margin-bottom: 50px;
+}
+
+/*Blog event container*/
+.post-container {
+ display: flex;
+ overflow: hidden;
+ flex-direction: row;
+ min-width: 400px;
+ min-height: 200px;
+ outline-width: 5px;
+ outline-color: purple;
+ outline-style: solid;
+}
+
+/*blog post description text container*/
+.post-container .description-container {
+ display: flex;
+ flex-direction: column;
+ max-width: 45%;
+ min-height: 200px;
+ margin: 10px;
+ overflow: hidden;
+ max-height: 200px;
+}
+
+/*description header text styling*/
+.post-container .description-container h3 {
+ font-size: medium;
+}
+
+/*blog post image container*/
+.post-container .image-container {
+ max-width: 45%;
+ margin: 10px;
+ outline-width: 0px;
+ overflow: hidden;
+ max-height: 200px;
+}
+
+/*blog image scale to fit container*/
+.post-container .image-container img {
+ object-fit: contain;
+ height: 100%;
+ width: 100%;
+}
\ No newline at end of file
diff --git a/bootcamp-milestone-2/src/components/blogPreview.tsx b/bootcamp-milestone-2/src/components/blogPreview.tsx
new file mode 100644
index 000000000..827bdb910
--- /dev/null
+++ b/bootcamp-milestone-2/src/components/blogPreview.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import style from './blogPreview.module.css'
+import Image from 'next/image';
+import Link from 'next/link';
+
+export default function BlogPreview(props: any) {
+ return (
+ // replace everything between the
&
tags
+ // with your code from earlier milestones
+ <>
+
+ {props.title};
+
+
+
+
Description:
+
+ {props.description}
+
{(props.date)}
+
+
+
+
+
+
+
+ >
+
+ );
+}
\ No newline at end of file
diff --git a/bootcamp-milestone-2/src/components/commentPreview.tsx b/bootcamp-milestone-2/src/components/commentPreview.tsx
new file mode 100644
index 000000000..9759c7c3b
--- /dev/null
+++ b/bootcamp-milestone-2/src/components/commentPreview.tsx
@@ -0,0 +1,28 @@
+import type {IComment} from "@/src/database/blogSchema"
+{/* When we pass props, the name that we use to pass values
+ is the key for the type
+*/}
+type CommentProps = {
+ comment: IComment;
+}
+
+
+{/* Modularizing code into seperate functions is useful.
+ Makes your code look nicer and allows for better readability.
+ */}
+function parseCommentTime(time: Date){
+ if (!time) return "Unknown";
+ return time.toString();
+}
+
+function Comment({ comment }: CommentProps) {
+ return (
+
+
{comment.user}
+
{comment.comment}
+ {parseCommentTime(comment.time)}
+
+ );
+}
+
+export default Comment;
\ No newline at end of file
diff --git a/bootcamp-milestone-2/src/components/footer.module.css b/bootcamp-milestone-2/src/components/footer.module.css
new file mode 100644
index 000000000..28ae9963f
--- /dev/null
+++ b/bootcamp-milestone-2/src/components/footer.module.css
@@ -0,0 +1,13 @@
+
+/* CSS for page footer */
+.footer {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: black;
+ color: white;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ height: 2.5rem;
+}
\ No newline at end of file
diff --git a/bootcamp-milestone-2/src/components/footer.tsx b/bootcamp-milestone-2/src/components/footer.tsx
new file mode 100644
index 000000000..c0d921d4d
--- /dev/null
+++ b/bootcamp-milestone-2/src/components/footer.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+import style from "./footer.module.css";
+import Link from "next/link";
+
+export default function Navbar() {
+ return (
+
+ );
+}
+
diff --git a/bootcamp-milestone-2/src/components/navbar.module.css b/bootcamp-milestone-2/src/components/navbar.module.css
new file mode 100644
index 000000000..acd75836c
--- /dev/null
+++ b/bootcamp-milestone-2/src/components/navbar.module.css
@@ -0,0 +1,37 @@
+/* CSS for navigation bar */
+.navbar {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ width: 100%;
+ height: 15%;
+ z-index: 10;
+ min-height: 15%;
+ min-height: 75px;
+
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ text-align: center;
+
+ background-color: black;
+ color: white;
+ padding: 0px 0px;
+}
+
+.navlist {
+ display: flex;
+ flex-direction: row;
+ position: relative;
+ right: 30px;
+ list-style: none;
+}
+
+.navbar a {
+ color: white;
+ font-weight: bold;
+ margin: 0 12px;
+ text-decoration: none;
+ letter-spacing: 2px;
+ font-size: larger;
+}
diff --git a/bootcamp-milestone-2/src/components/navbar.tsx b/bootcamp-milestone-2/src/components/navbar.tsx
new file mode 100644
index 000000000..a4b02a10e
--- /dev/null
+++ b/bootcamp-milestone-2/src/components/navbar.tsx
@@ -0,0 +1,26 @@
+import React from "react";
+import style from "./navbar.module.css";
+import Link from "next/link";
+
+export default function Navbar() {
+ return (
+ // replace everything in between the & tags
+ // with your navbar code from your earlier milestones
+ // NOTE: we use "class" in HTML but React is quirky so we have to
+ // change all the "class" to "className"
+
+
+
+ );
+}
diff --git a/bootcamp-milestone-2/src/components/projectPreview.module.css b/bootcamp-milestone-2/src/components/projectPreview.module.css
new file mode 100644
index 000000000..290e1c0bf
--- /dev/null
+++ b/bootcamp-milestone-2/src/components/projectPreview.module.css
@@ -0,0 +1,61 @@
+/*Blog Page code*/
+
+/*blog background*/
+.project body {
+ background-color: rgba(240, 236, 228, 1);
+}
+
+/*container for all blog events*/
+#projects {
+ width: 400px;
+ display: flex;
+ flex-direction: column;
+ outline-width: 0px;
+ outline-color: aqua;
+ outline-style: solid;
+ margin-bottom: 50px;
+}
+
+/*Blog event container*/
+.project-container {
+ display: flex;
+ overflow: hidden;
+ flex-direction: row;
+ min-width: 400px;
+ min-height: 200px;
+ outline-width: 5px;
+ outline-color: purple;
+ outline-style: solid;
+}
+
+/*blog post description text container*/
+.project-container .description-container {
+ display: flex;
+ flex-direction: column;
+ max-width: 45%;
+ min-height: 200px;
+ margin: 10px;
+ overflow: hidden;
+ max-height: 200px;
+}
+
+/*description header text styling*/
+.project-container .description-container h3 {
+ font-size: medium;
+}
+
+/*blog post image container*/
+.project-container .video-container {
+ max-width: 45%;
+ margin: 10px;
+ outline-width: 0px;
+ overflow: hidden;
+ max-height: 200px;
+}
+
+/*blog image scale to fit container*/
+.project-container .video-container video {
+ object-fit: contain;
+ height: 100%;
+ width: 100%;
+}
\ No newline at end of file
diff --git a/bootcamp-milestone-2/src/components/projectPreview.tsx b/bootcamp-milestone-2/src/components/projectPreview.tsx
new file mode 100644
index 000000000..3c38de895
--- /dev/null
+++ b/bootcamp-milestone-2/src/components/projectPreview.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import style from './projectPreview.module.css'
+import Image from 'next/image';
+import Link from 'next/link';
+
+export default function ProjectPreview(props: any) {
+ return (
+ <>
+
{(props.title)}
+
+
+
+
+
+
+
+
Description:
+
+ {props.description}
+
+
+
+
+
+ >
+
+ );
+}
\ No newline at end of file
diff --git a/bootcamp-milestone-2/src/database/blogSchema.ts b/bootcamp-milestone-2/src/database/blogSchema.ts
new file mode 100644
index 000000000..633c0876e
--- /dev/null
+++ b/bootcamp-milestone-2/src/database/blogSchema.ts
@@ -0,0 +1,54 @@
+import mongoose, { Schema } from "mongoose";
+
+// typescript type (can also be an interface)
+type Blog = {
+ title: string;
+ date: Date;
+ description: string; // for preview
+ image: string; // url for string in public
+ image_alt: string; // alt for image
+ slug: string;
+ comments: IComment[]; // array for comments
+};
+
+export type IComment = {
+ user: string;
+ comment: string;
+ time: Date;
+}
+
+const commentSchema = new Schema(
+ {
+ user: { type: String, required: true },
+ comment:{ type: String, required: true },
+ time: { type: Date, required: true, default: Date.now },
+ }
+);
+
+
+// mongoose schema
+const blogSchema = new Schema(
+ {
+ title: { type: String, required: true },
+ date: { type: Date, required: false, default: new Date()},
+ description: { type: String, required: true },
+ image: { type: String, required: true },
+ image_alt: { type: String, required: true },
+ //content: { type: String, required: true },
+ slug: { type: String, required: true },
+ comments: { type: [commentSchema], required: false, default: [] },
+ /*comments: [{
+ user: { type: String, required: true },
+ comment: { type: String, required: true },
+ time: { type: Date, required: true, default: new Date() }
+ }],*/
+ },
+ { collection: "Blogs"
+ }
+)
+
+// defining the collection and model
+const BlogModel = mongoose.models['Blogs'] ||
+ mongoose.model('Blogs', blogSchema);
+
+export default BlogModel;
\ No newline at end of file
diff --git a/bootcamp-milestone-2/src/database/database.ts b/bootcamp-milestone-2/src/database/database.ts
new file mode 100644
index 000000000..fc069c0e1
--- /dev/null
+++ b/bootcamp-milestone-2/src/database/database.ts
@@ -0,0 +1,32 @@
+// db.ts
+import mongoose from "mongoose";
+import Project from "../database/projectSchema";
+
+const blog_url: string = process.env.MONGO_URI_BLOG as string;
+const project_url: string = process.env.MONGO_URI_PROJECT as string;
+let connection: typeof mongoose;
+
+/**
+ * Makes a connection to a MongoDB database. If a connection already exists, does nothing
+ * Call this function at the start of api routes and data fetches
+ * @returns {Promise}
+ */
+const connectDB = async (blogs = true) => {
+ console.log("Connecting to database...");
+ if (!connection) {
+ //if (blogs){
+ connection = await mongoose.connect(blog_url);
+ //}
+ //else{
+ // connection = await mongoose.connect(project_url);
+ //}
+
+ console.log("db:", mongoose.connection.name); // BlogsDB
+ console.log("collection:", Project.collection.name); // Blogs
+ console.log("count:", await Project.countDocuments({})); // should be 3
+
+ return connection;
+ }
+};
+
+export default connectDB;
diff --git a/bootcamp-milestone-2/src/database/projectSchema.ts b/bootcamp-milestone-2/src/database/projectSchema.ts
new file mode 100644
index 000000000..e116a7f41
--- /dev/null
+++ b/bootcamp-milestone-2/src/database/projectSchema.ts
@@ -0,0 +1,28 @@
+import mongoose, { Schema } from "mongoose";
+
+// typescript type (can also be an interface)
+type Project = {
+ title: string;
+ video: String;
+ video_alt: String;
+ description: string; // for preview
+};
+
+
+// mongoose schema
+const projectSchema = new Schema(
+ {
+ title: { type: String, required: true },
+ video: { type: String, required: true, },
+ video_alt: { type: String, required: true },
+ description: { type: String, required: true }
+ },
+ { collection: "Projects"
+ }
+)
+
+// defining the collection and model
+const Project = mongoose.models['Projects'] ||
+ mongoose.model('Projects', projectSchema);
+
+export default Project;
\ No newline at end of file
diff --git a/bootcamp-milestone-2/tsconfig.json b/bootcamp-milestone-2/tsconfig.json
new file mode 100644
index 000000000..3a13f90a7
--- /dev/null
+++ b/bootcamp-milestone-2/tsconfig.json
@@ -0,0 +1,34 @@
+{
+ "compilerOptions": {
+ "target": "ES2017",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./*"]
+ }
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts",
+ ".next/dev/types/**/*.ts",
+ "**/*.mts"
+ ],
+ "exclude": ["node_modules"]
+}
diff --git a/contact.html b/contact.html
new file mode 100644
index 000000000..c8b3165ae
--- /dev/null
+++ b/contact.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+ Contanct page
+
+
+
+
+
+
+
+
+ Contact
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 000000000..47f509782
--- /dev/null
+++ b/index.html
@@ -0,0 +1,65 @@
+
+
+
+
+
+ Xavier's Website
+
+
+
+
+
+
+
+ Xavier Royer
+
+
+
+
+
+
+
+
+
+ Hi my name is Xavier Royer and I'm a physics major and Computer Science minor at Cal Poly! I love working on any STEM related projects. Other things I enjoy are reading literature, running, basketball, spikeball, learning new things, and pretty much anything outdoors!
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000..75f4476b4
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,29 @@
+{
+ "name": "bootcamp-project-2024",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "bootcamp-project-2024",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "typescript": "^5.9.3"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..53e48021e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "bootcamp-project-2024",
+ "version": "1.0.0",
+ "description": "This is how we will be tracking your milestones throughout bootcamp! By the end of bootcamp, you will have a fullstack personal portfolio website.",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/Xavier-Royer/bootcamp-project-2024.git"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "bugs": {
+ "url": "https://github.com/Xavier-Royer/bootcamp-project-2024/issues"
+ },
+ "homepage": "https://github.com/Xavier-Royer/bootcamp-project-2024#readme",
+ "dependencies": {
+ "typescript": "^5.9.3"
+ }
+}
diff --git a/portfolio.html b/portfolio.html
new file mode 100644
index 000000000..e6e03033c
--- /dev/null
+++ b/portfolio.html
@@ -0,0 +1,198 @@
+
+
+
+
+
+ Porfolio Page
+
+
+
+
+
+
+
+
+ Portfolio
+
+
+
+
+
+
+ Color-Jumper
+
+
+
+
+
+
+
+
Description:
+
Color-Jumper is a fast paced mobile game I've been developing with my coding partner 7teen.
+ It's currently in beta release for both the apple and play store. It was developed using the Godot engine, and github for version control.
+
+
+
+
+
+
+ Circular Calendar Application
+
+
+
+
+
+
+
+
Description:
+
This application was created for a client who need a calendar task manager app that would give them a visual representation of their year. The development proccess included a full product life cycle including extensive planning documents (UML, flowcharts, GUI sketches, success criteria) as well as a prototype and maintenance phase. It also included client feedback in an agile style development cycle to suit the client's needs.
+
+
+
+
+
+
+
+ Catapult Optimization Paper
+
+
+
+
+
+
+
+
+
+
+
+
+
Description:
+
I researched and wrote a paper on catapult opimziation for my VEX Robotic's team's robot. It focused on finding the optimal motor load to produce the greatest projectile distance per reload time, as well as finding the right moment of inertia of the arm to produce a collision with peak energy conservation. At then end, the catapult was able to shoot around 70% further.
+
+
+
+
+
+
+
+
+
+ VEX High Stakes Robot
+
+
+
+
+
+
+
+
+
+
Description:
+
This was the robot my team designed for the high stakes competetion. It included autonmous PID controlled driving, as well as an auto reject feature for wrong colored rings. I also filmed and editied the reveal video showcasing on the left.
+
+
+
+
+
+
+
+ PID autonmous Robot
+
+
+
+
+
+
+
+
Description:
+
This robot used a vision sensor and a PID loop to scan an area for where game-objects were located and then drive up and capture them. The vision sensor acted as a feedback system which made the autonomous routes more accurate than when simply hard coding the location of the objects.
+
+
+
+
+
+
+ River Racer
+
+
+
+
+
+
+
+
+
+
+
Description:
+
My first ever 3D game and game jam entry, Ricer Racer is a endless runner game in which you avoid rocks, trees and turtles as you try and collect trash. The game was made for the teamseas game jam in an effort to raise enviornemntal awareness of water pollution.
+
+
+
+
+
+
+ Xtreme Golf
+
+
+
+
+
+
+
Description:
+
Xtreme Golf is a mini golf puzzle-based game. Navigate interconnected stages in order to complete the level, while avodiing obstacles and traps. This game was also made as part of a game jam in one week.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resume.html b/resume.html
new file mode 100644
index 000000000..994051be4
--- /dev/null
+++ b/resume.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+ Resume page
+
+
+
+
+
+
+
+