Initial Commit
This commit is contained in:
parent
428910d835
commit
c842a38c41
10
src/app.css
10
src/app.css
@ -3,16 +3,6 @@
|
||||
@import 'tailwindcss/components';
|
||||
@import 'tailwindcss/utilities';
|
||||
|
||||
* {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
*:not(a),
|
||||
*:not(button),
|
||||
*:not(input) {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* @font-face {
|
||||
font-family: 'Nunita';
|
||||
src: url('$lib/assets/fonts/Nunito-VariableFont_wght.ttf');
|
||||
|
@ -1,37 +0,0 @@
|
||||
<script>
|
||||
import MaterialSymbolsPerson from '~icons/material-symbols/person';
|
||||
import MaterialSymbolsMail from '~icons/material-symbols/mail';
|
||||
</script>
|
||||
|
||||
<div class="w-screen h-screen flex justify-center items-center">
|
||||
<form action="?/contact" class="w-full min-h-full dark:bg-surface-900 bg-surface-200 lg:w-1/2 lg:min-h-max p-8 rounded-md pr-12 lg:pr-8">
|
||||
<h1 class="h1 font-bold ps-4 pb-4">Contact Us</h1>
|
||||
<hr class="opacity-25" />
|
||||
<p class="pt-4">Fullname</p>
|
||||
<div class="input-group input-group-divider grid-cols-[auto_1fr_auto] mb-4">
|
||||
<div class="input-group-shim"><MaterialSymbolsPerson /></div>
|
||||
<input type="text" placeholder="John Doe" required />
|
||||
</div>
|
||||
<p>Email</p>
|
||||
<div class="input-group input-group-divider grid-cols-[auto_1fr_auto] mb-4">
|
||||
<div class="input-group-shim"><MaterialSymbolsMail /></div>
|
||||
<input type="email" placeholder="john@example.com" required />
|
||||
</div>
|
||||
<p>Subject</p>
|
||||
<div class="input-group input-group-divider grid-cols-[auto_1fr_auto] mb-4">
|
||||
<div class="input-group-shim"><MaterialSymbolsMail /></div>
|
||||
<select class="select" required>
|
||||
<option value="other" disabled selected hidden>Choose Subject</option>
|
||||
<option value="request">Work Request</option>
|
||||
<option value="upload">Upload Request</option>
|
||||
<option value="support">Support Request</option>
|
||||
<option value="other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
<p>Your Message</p>
|
||||
<textarea class="textarea mb-4" rows="4" placeholder="..." required ></textarea>
|
||||
<div class="w-full text-end">
|
||||
<button type="submit" class="btn variant-filled-primary">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -1,44 +0,0 @@
|
||||
<script>
|
||||
import Hero from "$lib/components/Hero.svelte";
|
||||
import ArrowDown from "~icons/material-symbols/keyboard-double-arrow-down-rounded";
|
||||
import { crossfade, fade, fly } from "svelte/transition";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let isAtTop = true;
|
||||
|
||||
onMount(() => {
|
||||
const handleScroll = () => {
|
||||
isAtTop = window.scrollY === 0;
|
||||
};
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
return () => window.removeEventListener("scroll", handleScroll);
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Add these classes to your root container (likely in app.html or layout.svelte) -->
|
||||
<style>
|
||||
:global(html) {
|
||||
scroll-snap-type: y mandatory;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Add scroll-snap-align to your sections -->
|
||||
<header class="fancy-background align-center flex h-screen flex-col justify-between p-4 hero scroll-snap-start">
|
||||
<div class=""></div>
|
||||
<Hero></Hero>
|
||||
<div
|
||||
class="transition-all duration-300 text-xl self-center ease-in-out relative slide h-6"
|
||||
class:opacity-0={!isAtTop}
|
||||
>
|
||||
{#if isAtTop}
|
||||
<div
|
||||
class="animate-bounce"
|
||||
in:fly={{ x: 200, duration: 300 }}
|
||||
out:fly={{ x: -200, duration: 300 }}
|
||||
>
|
||||
<ArrowDown></ArrowDown>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</header>
|
@ -1,38 +0,0 @@
|
||||
<script>
|
||||
import BackwardsLogo from "$lib/assets/Backwards.png";
|
||||
|
||||
import MdiGithub from '~icons/mdi/github';
|
||||
import MdiYoutube from '~icons/mdi/youtube';
|
||||
import MdiDiscord from '~icons/mdi/discord';
|
||||
import MdiLinkedin from '~icons/mdi/linkedin';
|
||||
import CibGitea from '~icons/cib/gitea';
|
||||
|
||||
</script>
|
||||
|
||||
<div class="text-center h-max self-center" id="hero">
|
||||
<h1 class="h1 overflow-hidden">Backwards Development</h1>
|
||||
<h4 class="h4">A Software Development and Distribution Company</h4>
|
||||
<div class="flex justify-evenly pt-4">
|
||||
<a href="https://github.com/BackwardsUser/" class="btn variant-filled-surface text-2xl p-3 rounded-md spin">
|
||||
<span class="block spinner duration-500"><MdiGithub /></span>
|
||||
</a>
|
||||
<a href="https://git.backwards.dev/" class="btn variant-filled-surface text-2xl p-3 rounded-md spin">
|
||||
<span class="block spinner duration-500"><CibGitea /></span>
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/in/alexander-harding-71b661265/" class="btn variant-filled-surface text-2xl p-3 rounded-md spin">
|
||||
<span class="block spinner duration-500"><MdiLinkedin /></span>
|
||||
</a>
|
||||
<a href="https://www.youtube.com/@BackwardsDevelopment" class="btn variant-filled-surface text-2xl p-3 rounded-md spin">
|
||||
<span class="block spinner duration-500"><MdiYoutube /></span>
|
||||
</a>
|
||||
<a href="https://discord.gg/Zhq9yjhHKr" class="btn variant-filled-surface text-2xl p-3 rounded-md spin">
|
||||
<span class="block spinner duration-500"><MdiDiscord /></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.spin:hover>.spinner {
|
||||
transform: rotateZ(360deg);
|
||||
}
|
||||
</style>
|
@ -1,29 +0,0 @@
|
||||
<script>
|
||||
import MaterialSymbolsArrowForwardRounded from "~icons/material-symbols/arrow-forward-rounded";
|
||||
import MaterialSymbolsLabProfileOutline from '~icons/material-symbols/lab-profile-outline';
|
||||
|
||||
let mediaPageOnline = false;
|
||||
|
||||
</script>
|
||||
|
||||
<div class="w-screen h-screen flex flex-col justify-center items-center">
|
||||
<h2 class="h2 font-bold">Backwards Media</h2>
|
||||
<h3 class="h3">Upload and Share Media with your Friends</h3>
|
||||
<div class="flex flex-row controls pt-4 gap-12">
|
||||
<a href={mediaPageOnline ? "https://media.backwards.dev/" : ""} class="btn variant-filled-primary cool-hover opacity-50 cursor-not-allowed">
|
||||
<span>Try it out</span>
|
||||
<span class="effect duration-500 ease-in-out rounded-xl"><MaterialSymbolsArrowForwardRounded /></span>
|
||||
</a>
|
||||
<a href="/about#media" class="btn variant-ghost-surface cool-hover">
|
||||
<span>Learn more</span>
|
||||
<span class="effect duration-500 ease-in-out rounded-xl"><MaterialSymbolsLabProfileOutline /></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* dumb ass name :(, cool ass animation :) */
|
||||
.cool-hover:hover>.effect {
|
||||
transform: rotateZ(360deg);
|
||||
}
|
||||
</style>
|
@ -1,50 +0,0 @@
|
||||
<script>
|
||||
import { Avatar } from "@skeletonlabs/skeleton";
|
||||
import projects from "$lib/data/projects.json";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
const fallbackThumbnail = "/Image_not_available.png"; // Set a valid default image path
|
||||
|
||||
function handleImageError(event, type) {
|
||||
if (type === "thumbnail") {
|
||||
event.target.src = fallbackThumbnail;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<div class="min-h-screen">
|
||||
<h2 class="h2 text-center w-screen pt-4 overflow-hidden">Projects</h2>
|
||||
<div class="flex flex-wrap gap-4 p-4 w-max max-w-full m-auto">
|
||||
{#each projects as project}
|
||||
<a href={project.url} class="card w-min variant-glass-surface card-hover overflow-hidden flex flex-col">
|
||||
<header>
|
||||
<img
|
||||
src={project.thumbnail || fallbackThumbnail}
|
||||
class="bg-black/50 aspect=[21/9] object-cover flex justify-center items-center"
|
||||
alt={project.name}
|
||||
loading="lazy"
|
||||
on:error={handleImageError}>
|
||||
</header>
|
||||
<div class="p-4 space-y-4 flex-auto">
|
||||
<h3 class="h3" data-toc-ignore>{project.name}</h3>
|
||||
<article>
|
||||
<p>
|
||||
{project.description}
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
<hr class="opacity-50" />
|
||||
<footer class="p-4 flex text-nowrap justify-start items-center space-x-4">
|
||||
<Avatar src={project.author.icon || fallbackAvatar} width="w-8" />
|
||||
<div class="flex-auto gap-6 flex justify-between items-center">
|
||||
<h6 class="font-bold" data-toc-ignore>
|
||||
By {project.author.username}
|
||||
</h6>
|
||||
<small>Updated {project.date}</small>
|
||||
</div>
|
||||
</footer>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
@ -1,36 +0,0 @@
|
||||
<script>
|
||||
import Techs from '$lib/data/techstack.json';
|
||||
import { Avatar } from '@skeletonlabs/skeleton';
|
||||
</script>
|
||||
|
||||
<!-- <div class="w-screen h-screen text-center pb-32 flex justify-center items-center px-8">
|
||||
<div class="wrapper h-max overflow-visible">
|
||||
<h2 class="h2 font-bold pb-0 w-full overflow-hidden">My Current Tech Stack</h2>
|
||||
<span class="text-sm pt-0 text-surface-700 dark:text-surface-200">Subject to change</span>
|
||||
<div class="pt-4 m-auto w-max max-w-full h-max flex flex-wrap gap-4 justify-center">
|
||||
{#each Techs as tech}
|
||||
<a href="{tech.url}" class="min-w-72 flex flex-row justify-between items-center card card-hover p-4 hover:bg-surface-700 rounded-lg">
|
||||
<Avatar class="p-2" src={tech.logo} alt={`Logo of ${tech.name}`} />
|
||||
<span class="text-xl">{tech.name}</span>
|
||||
<div class="spacer"></div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="w-screen h-max min-h-screen flex flex-col justify-center items-center py-32">
|
||||
<div class="header-wrapper text-center overflow-visible">
|
||||
<h2 class="flex-shrink-0 flex-grow-1 h2 font-bold pb-0 w-full overflow-hidden">My Current Tech Stack</h2>
|
||||
<span class="text-sm pt-0 text-surface-700 dark:text-surface-200">Subject to Change</span>
|
||||
</div>
|
||||
<div class="pt-4 w-max max-w-full h-max flex flex-wrap gap-4 justify-center overflow-visible">
|
||||
{#each Techs as tech}
|
||||
<a href="{tech.url}" class="min-w-72 flex flex-row justify-between items-center card card-hover p-4 dark:hover:bg-surface-700 hover:bg-surface-200 rounded-lg">
|
||||
<Avatar class="p-2" src={tech.logo} alt={`Logo of ${tech.name}`} />
|
||||
<span class="text-xl">{tech.name}</span>
|
||||
<div class="spacer"></div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
7
src/lib/components/items/BrandIcon.svelte
Normal file
7
src/lib/components/items/BrandIcon.svelte
Normal file
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
export let url, icon;
|
||||
</script>
|
||||
|
||||
<a href={url} class="btn variant-filled-surface text-2xl p-3 rounded-md spin">
|
||||
<span class="block spinner duration-500"><svelte:component this={icon}></svelte:component></span>
|
||||
</a>
|
@ -1,98 +1,56 @@
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import Header from "$lib/components/Header.svelte";
|
||||
import { fly } from "svelte/transition";
|
||||
import Media from "$lib/components/Media.svelte";
|
||||
import Contact from "$lib/components/Contact.svelte";
|
||||
import TechStack from "$lib/components/TechStack.svelte";
|
||||
import Projects from "$lib/components/Projects.svelte";
|
||||
|
||||
/* IMPORTANT */
|
||||
// Anything added into the page directly will likely break the page's scrolling behaviour
|
||||
// To properly add something to the main page, make it into a component and add it to the array.
|
||||
// This array is in order of how they are to be displayed, modifying their positions will modify them in page.
|
||||
import BrandIcon from "$lib/components/items/BrandIcon.svelte";
|
||||
|
||||
let slides = [
|
||||
Header,
|
||||
Projects,
|
||||
TechStack,
|
||||
Contact,
|
||||
// Media,
|
||||
];
|
||||
import MdiGithub from '~icons/mdi/github';
|
||||
import MdiYoutube from '~icons/mdi/youtube';
|
||||
import MdiDiscord from '~icons/mdi/discord';
|
||||
import MdiLinkedin from '~icons/mdi/linkedin';
|
||||
import CibGitea from '~icons/cib/gitea';
|
||||
|
||||
const brands = [
|
||||
{ url: "https://www.github.com/BackwardsUser", icon: CibGitea },
|
||||
{ url: "https://www.youtube.com/@BackwardsDevelopment", icon: MdiYoutube },
|
||||
{ url: "https://discord.gg/Zhq9yjhHKr", icon: MdiDiscord },
|
||||
{ url: "https://www.linkedin.com/in/alexander-harding-71b661265/", icon: MdiLinkedin },
|
||||
{ url: "https://git.backwards.dev/", icon: CibGitea },
|
||||
]
|
||||
|
||||
let currentSection = 0;
|
||||
|
||||
// Update the current section based on scroll position
|
||||
const handleScroll = () => {
|
||||
const sections = document.querySelectorAll(".section");
|
||||
const scrollTop = document.querySelector(".scroll-container").scrollTop;
|
||||
sections.forEach((section, index) => {
|
||||
if (section.offsetTop <= scrollTop + window.innerHeight / 2) {
|
||||
currentSection = index;
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<div id="main" class="scroll-container" on:scroll={handleScroll}>
|
||||
{#each slides as content}
|
||||
<section class="section">
|
||||
<svelte:component this={content} />
|
||||
</section>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<!-- Tracker -->
|
||||
{#if currentSection > 0}
|
||||
<div in:fly={{ x: 50, duration: 300 }} out:fly={{ x: 50, duration: 300 }} class="tracker">
|
||||
{#each slides.slice(1) as _, i}
|
||||
<div class="tracker-dot {i + 1 === currentSection ? 'active' : ''}"></div>
|
||||
{/each}
|
||||
<main class="grid wrapper justify-center items-center">
|
||||
<div class="left w-full h-2/3 bg-surface-500 text-center">
|
||||
<h4 class="h4">Tools</h4>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="header-wrapper">
|
||||
<header class="w-full h-screen flex flex-col justify-center items-center">
|
||||
<h1 class="h1">Alexander Harding</h1>
|
||||
<h4 class="h4">Software and Application Developer</h4>
|
||||
<div class="cards w-full flex justify-between">
|
||||
{#each brands as brand}
|
||||
<BrandIcon url={brand.url} icon={brand.icon} />
|
||||
{/each}
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
<div class="right w-full h-2/3 bg-surface-500 text-center">
|
||||
<h4 class="h4">Downloads</h4>
|
||||
</div>
|
||||
<div class="main">
|
||||
<div class="projects"></div>
|
||||
<div class="contact"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.scroll-container {
|
||||
scroll-snap-type: y mandatory;
|
||||
overflow-y: auto;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
scroll-behavior: smooth;
|
||||
.wrapper {
|
||||
grid-template-columns: 0.5fr 2fr 0.5fr;
|
||||
}
|
||||
|
||||
.section {
|
||||
min-height: 100vh; /* Full viewport height */
|
||||
width: 100vw;
|
||||
.left {
|
||||
border-radius: 0 0.5em 0.5em 0;
|
||||
}
|
||||
|
||||
/* Scroll Snapping works well with a mouse, but without it feels forced, weird and wrong. */
|
||||
@media (width >= 64rem) {
|
||||
.section {
|
||||
scroll-snap-align: center;
|
||||
}
|
||||
.right {
|
||||
border-radius: 0.5em 0 0 0.5em;
|
||||
}
|
||||
|
||||
/* Tracker Styles */
|
||||
.tracker {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
right: 20px;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.tracker-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
@apply bg-surface-600;
|
||||
border-radius: 50%;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.tracker-dot.active {
|
||||
@apply bg-primary-600;
|
||||
}
|
||||
</style>
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user