Add initial Angular application structure and components
@@ -0,0 +1,17 @@
|
|||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.ts]
|
||||||
|
quote_type = single
|
||||||
|
ij_typescript_use_double_quotes = false
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||||
|
|
||||||
|
# Compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# Node
|
||||||
|
/node_modules
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea/
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
/.angular/cache
|
||||||
|
.sass-cache/
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
|
|
||||||
<title>Julian Lechner</title>
|
|
||||||
<link rel="icon" href="../favicon.ico" />
|
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../Resources/Style.css" />
|
|
||||||
|
|
||||||
<script rel="preload" src="https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js"></script>
|
|
||||||
<script async rel="preload" src="../Resources/Javascript.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<div class="card profile">
|
|
||||||
|
|
||||||
<h1>Imprint</h1>
|
|
||||||
|
|
||||||
<h2>Information according to §5 TMG</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Julian Lechner <br>
|
|
||||||
Ulmenstraße 9 <br>
|
|
||||||
3380 Pöchlarn <br>
|
|
||||||
Lower Austria <br>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<h4>Contact:</h4>
|
|
||||||
Phone: +43 (0) 660 9254001 <br>
|
|
||||||
E-Mail: contact@fraujulian.xyz
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<h4>Abuse Contact:</h4>
|
|
||||||
E-Mail: abuse@fraujulian.xyz
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<h2>Disclaimer:</h2>
|
|
||||||
|
|
||||||
<h3>Liability for content</h3>
|
|
||||||
The contents of our pages have been created with the greatest care. However, we cannot assume any liability for
|
|
||||||
the correctness, completeness and topicality of the contents. As a service provider, we are responsible for our
|
|
||||||
own content on these pages in accordance with § 7 (1) DDG and general legislation. According to §§ 8 to 10 DDG,
|
|
||||||
however, we are not obliged as a service provider to monitor transmitted or stored third-party information or to
|
|
||||||
investigate circumstances that indicate illegal activity. Obligations to remove or block the use of information in
|
|
||||||
accordance with general legislation remain unaffected by this. However, liability in this respect is only possible
|
|
||||||
from the time of knowledge of a specific infringement. As soon as we become aware of such infringements, we will
|
|
||||||
remove this content immediately.
|
|
||||||
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<h3>Liability for links</h3>
|
|
||||||
Our website contains links to external third-party websites over whose content we have no influence. Therefore, we
|
|
||||||
cannot accept any liability for this third-party content. The respective provider or operator of the pages is
|
|
||||||
always responsible for the content of the linked pages. The linked pages were checked for possible legal
|
|
||||||
violations at the time of linking. Illegal content was not recognizable at the time of linking. However, permanent
|
|
||||||
monitoring of the content of the linked pages is not reasonable without concrete evidence of an infringement. If
|
|
||||||
we become aware of any legal infringements, we will remove such links immediately.
|
|
||||||
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<h3>Copyright</h3>
|
|
||||||
The content and works created by the site operators on these pages are subject to German copyright law.
|
|
||||||
Duplication, processing, distribution and any form of commercialization of such material beyond the scope of the
|
|
||||||
copyright law shall require the prior written consent of its respective author or creator. Downloads and copies of
|
|
||||||
this site are only permitted for private, non-commercial use. Insofar as the content on this site was not created
|
|
||||||
by the operator, the copyrights of third parties are respected. In particular, third-party content is identified
|
|
||||||
as such. Should you nevertheless become aware of a copyright infringement, please inform us accordingly. If we
|
|
||||||
become aware of any infringements, we will remove such content immediately.
|
|
||||||
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<h3>Data privacy</h3>
|
|
||||||
The use of our website is generally possible without providing personal data. Insofar as personal data (e.g. name,
|
|
||||||
address or e-mail addresses) is collected on our website, this is always done on a voluntary basis as far as
|
|
||||||
possible. This data will not be passed on to third parties without your express consent.
|
|
||||||
We would like to point out that data transmission over the Internet (e.g. when communicating by e-mail) may be
|
|
||||||
subject to security vulnerabilities. Complete protection of data against access by third parties is not possible.
|
|
||||||
We hereby expressly prohibit the use of contact data published within the scope of the imprint obligation by third
|
|
||||||
parties for sending unsolicited advertising and information material. The operators of the website expressly
|
|
||||||
reserve the right to take legal action in the event of the unsolicited sending of advertising information, such as
|
|
||||||
spam e-mails.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="max60">
|
|
||||||
<div id="short-desc" class="hover-items">
|
|
||||||
<i id="left-arrow" class="fas fa-arrow-right"></i>
|
|
||||||
<a href="../index.html">
|
|
||||||
<u>
|
|
||||||
<h3>Back</h3>
|
|
||||||
</u>
|
|
||||||
</a>
|
|
||||||
<i id="right-arrow" class="fas fa-arrow-left"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p>
|
|
||||||
<a href="/IMPRINT/">IMPRINT</a> | © 2023 - %CURRENT_YEAR% Julian Lechner - All rights reserved.
|
|
||||||
</p>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
BSD 3-Clause License
|
|
||||||
|
|
||||||
Copyright (c) 2025, Julian Lechner
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
# License Agreement
|
|
||||||
|
|
||||||
**Copyright © 2025 Julian Lechner. All rights reserved.**
|
|
||||||
|
|
||||||
## 1. Grant of License
|
|
||||||
|
|
||||||
Subject to the terms and conditions of this Agreement, the Licensor hereby grants the Licensee a limited, non-exclusive, non-transferable, revocable license to access, view, and test the Software solely for personal, non-commercial purposes. **No other rights are granted.** The following actions are **strictly prohibited**:
|
|
||||||
|
|
||||||
- **Copying, reproducing, or replicating** the Software, in whole or in part, except for personal viewing.
|
|
||||||
- **Modifying, merging, adapting, translating, or creating derivative works** based on the Software.
|
|
||||||
- **Distributing, redistributing, transmitting, sublicensing, leasing, renting, or publishing** the Software in any form.
|
|
||||||
- **Selling, reselling, or otherwise exploiting** the Software for any commercial purpose.
|
|
||||||
|
|
||||||
## 2. Termination
|
|
||||||
|
|
||||||
This License Agreement is effective until terminated. This license will **automatically terminate without notice** if you fail to comply with any provision of this Agreement. Upon termination, you must immediately cease all use of the Software and destroy all copies, full or partial, in your possession or control.
|
|
||||||
|
|
||||||
## 3. Legal Compliance and Enforcement
|
|
||||||
|
|
||||||
Unauthorized use of the Software constitutes a violation of intellectual property laws and may result in **severe civil and criminal penalties**. The Licensor reserves the right to seek all remedies available at law and in equity for violations of this Agreement.
|
|
||||||
|
|
||||||
## 4. Disclaimer of Warranties
|
|
||||||
|
|
||||||
The Software is provided **"AS IS"**, without warranty of any kind, express or implied, including but not limited to the warranties of **merchantability**, **fitness for a particular purpose**, and **non-infringement**. The Licensor does not warrant that the Software will meet your requirements or that its operation will be uninterrupted or error-free.
|
|
||||||
|
|
||||||
## 5. Limitation of Liability
|
|
||||||
|
|
||||||
In no event shall the Licensor be liable for any **direct, indirect, incidental, special, consequential, or punitive damages**, including but not limited to loss of profits, data, or use, incurred by you or any third party, whether in an action in contract or tort, arising from your access to, or use of, the Software.
|
|
||||||
|
|
||||||
## 6. Indemnification
|
|
||||||
|
|
||||||
You agree to **indemnify, defend, and hold harmless** the Licensor from and against any and all claims, liabilities, damages, losses, or expenses (including legal fees and costs) arising out of or in any way connected with your violation of this Agreement or use of the Software.
|
|
||||||
|
|
||||||
## 7. Governing Law and Jurisdiction
|
|
||||||
|
|
||||||
This Agreement shall be governed by and construed in accordance with the laws of **Austria**, without regard to its conflict of law principles. Any legal action or proceeding arising under this Agreement will be brought exclusively in the courts located in **Austria**, and you hereby irrevocably consent to personal jurisdiction and venue therein.
|
|
||||||
|
|
||||||
## 8. Entire Agreement
|
|
||||||
|
|
||||||
This Agreement constitutes the **entire understanding** between you and the Licensor regarding the Software and supersedes all prior agreements, whether written or oral.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
For any inquiries regarding permissions, please contact:
|
|
||||||
|
|
||||||
**Julian Lechner**
|
|
||||||
Ulmenstraße 9
|
|
||||||
3380 Pöchlarn
|
|
||||||
|
|
||||||
Email: [fraujulian@lechner.top](mailto:fraujulian@lechner.top)
|
|
||||||
Phone: +43 660 9254001
|
|
||||||
|
|
||||||
Please report any abuse to the following email address:
|
|
||||||
[abuse@fraujulian.xyz](mailto:abuse@fraujulian.xyz)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**By accessing or using this Software, you acknowledge that you have read, understood, and agree to be bound by the terms and conditions of this License Agreement.**
|
|
||||||
@@ -1,13 +1,59 @@
|
|||||||
# 🖼️ FrauJulian's Portfolio Website
|
# AngularPortfolioSeite
|
||||||
|
|
||||||
### [🙋♂️ Website Preview](https://fraujulian.xyz/)
|
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.9.
|
||||||
|
|
||||||
## 👂 Languages/Framework/Packages:
|
## Development server
|
||||||
- Javascript
|
|
||||||
- CSS
|
To start a local development server, run:
|
||||||
- HTML
|
|
||||||
|
```bash
|
||||||
## 📋 Credits:
|
ng serve
|
||||||
~ made by [**FrauJulian**](https://fraujulian.xyz/).
|
```
|
||||||
|
|
||||||
### Greetings from Austria!
|
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng generate component component-name
|
||||||
|
```
|
||||||
|
|
||||||
|
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng generate --help
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
To build the project run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng build
|
||||||
|
```
|
||||||
|
|
||||||
|
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
For end-to-end (e2e) testing, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng e2e
|
||||||
|
```
|
||||||
|
|
||||||
|
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 215 KiB |
|
Before Width: | Height: | Size: 352 KiB |
@@ -1,262 +0,0 @@
|
|||||||
let _pathName = window.location.pathname;
|
|
||||||
let _knowledgeIndex = 0;
|
|
||||||
let _todayDate = new Date();
|
|
||||||
let _birthdayDate = "2009-03-03";
|
|
||||||
let _numberOfLoadedRepositories = 999;
|
|
||||||
let _numberOfShownRepositories = 999;
|
|
||||||
let _customProjects = [
|
|
||||||
{
|
|
||||||
"Title": "Azure Devops Effort Tracker",
|
|
||||||
"Description": "🕙 A desktop application to track the effort of your work items in azure devops.",
|
|
||||||
"Language": "C# - Avalonia",
|
|
||||||
"Link": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Title": "SynRadio",
|
|
||||||
"Description": "🖥️ An internet radio station that is available on various media.",
|
|
||||||
"Language": "TS | JS | HTML | CSS",
|
|
||||||
"Link": "https://www.synradio.de/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Title": "SynHost",
|
|
||||||
"Description": "❓ A support system integrating various platforms and media to offer employees a unified overview.",
|
|
||||||
"Language": "TS | JS",
|
|
||||||
"Link": "https://www.synhost.de/"
|
|
||||||
}];
|
|
||||||
|
|
||||||
if (_pathName.endsWith("/IMPRINT/index.html") || _pathName.endsWith("/IMPRINT/")) {
|
|
||||||
ReplaceCurrentYearPlaceholder();
|
|
||||||
} else {
|
|
||||||
LoadHomepage();
|
|
||||||
}
|
|
||||||
|
|
||||||
function LoadHomepage() {
|
|
||||||
ReplacePlaceholders();
|
|
||||||
LoadGithubProjects();
|
|
||||||
KnowledgeCarousel();
|
|
||||||
}
|
|
||||||
|
|
||||||
function ReplacePlaceholders() {
|
|
||||||
document.getElementById("loading-text").innerHTML = "Projekte werden geladen!";
|
|
||||||
|
|
||||||
ReplaceAgePlaceholder();
|
|
||||||
ReplaceCurrentYearPlaceholder();
|
|
||||||
}
|
|
||||||
|
|
||||||
function ReplaceAgePlaceholder() {
|
|
||||||
let birthDate = new Date("3-3-2009");
|
|
||||||
let diffTimeInMilliseconds = new Date() - birthDate;
|
|
||||||
let diffTimeInYears = diffTimeInMilliseconds / (1000 * 60 * 60 * 24 * 365.25);
|
|
||||||
let tempAge = diffTimeInYears.toFixed(1);
|
|
||||||
let age = tempAge % 1 === 0 ? Math.round(diffTimeInYears) : tempAge;
|
|
||||||
document.body.innerHTML = document.body.innerHTML.replace("%AGE%", age);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ReplaceCurrentYearPlaceholder() {
|
|
||||||
let fullCurrentYear = _todayDate.getFullYear().toString();
|
|
||||||
document.body.innerHTML = document.body.innerHTML.replace("%CURRENT_YEAR%", fullCurrentYear);
|
|
||||||
}
|
|
||||||
|
|
||||||
function KnowledgeCarousel() {
|
|
||||||
let bioContainer = document.getElementsByClassName("bio")[0];
|
|
||||||
let rawListItems = bioContainer.getElementsByTagName("div");
|
|
||||||
bioContainer.style = "display: grid !important;";
|
|
||||||
|
|
||||||
for (let i = 1; i < rawListItems.length; i++) {
|
|
||||||
rawListItems[i].style = "display: none;";
|
|
||||||
}
|
|
||||||
|
|
||||||
_knowledgeIndex++;
|
|
||||||
|
|
||||||
if (_knowledgeIndex > rawListItems.length || _knowledgeIndex === 1) {
|
|
||||||
_knowledgeIndex = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
rawListItems[_knowledgeIndex - 1].style.display = "block";
|
|
||||||
|
|
||||||
setTimeout(KnowledgeCarousel, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function LoadGithubProjects() {
|
|
||||||
const sortOnKey = (key, descending) => {
|
|
||||||
return (a, b) => {
|
|
||||||
a = a[key];
|
|
||||||
b = b[key];
|
|
||||||
return descending ? b - a : a - b;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch(`https://api.github.com/users/fraujulian/repos?per_page=${_numberOfLoadedRepositories}`)
|
|
||||||
.then((rawResponse) => rawResponse.json())
|
|
||||||
.then((allProjects) => {
|
|
||||||
allProjects = allProjects.sort(sortOnKey("stargazers_count", true));
|
|
||||||
|
|
||||||
let projectsDiv = document.getElementById("github_projects");
|
|
||||||
projectsDiv.innerHTML = "";
|
|
||||||
projectsDiv.classList = "";
|
|
||||||
|
|
||||||
for (let i = 0; i < _customProjects.length; i++) {
|
|
||||||
let currentProjectDiv = document.createElement("div");
|
|
||||||
currentProjectDiv.classList = "card hoverable";
|
|
||||||
|
|
||||||
currentProjectDiv.innerHTML = `
|
|
||||||
<div class="media">
|
|
||||||
<div class="media-body">
|
|
||||||
<a href="${_customProjects[i].Link}">
|
|
||||||
<strong class="d-block text-gray-dark">${_customProjects[i].Title}</strong>
|
|
||||||
</a>
|
|
||||||
<div class="stars">
|
|
||||||
${_customProjects[i].Language}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p>${_customProjects[i].Description}</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
projectsDiv.appendChild(currentProjectDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let currentProjectIndex = 0; currentProjectIndex < _numberOfShownRepositories; currentProjectIndex++) {
|
|
||||||
let currentProjectDiv = document.createElement("div");
|
|
||||||
currentProjectDiv.classList = "card hoverable";
|
|
||||||
|
|
||||||
let currentProject = allProjects[currentProjectIndex];
|
|
||||||
|
|
||||||
if (currentProject === undefined || currentProject.fork === true) return;
|
|
||||||
if (currentProject.description == null) currentProject.description = "";
|
|
||||||
if (currentProject.language == null) currentProject.language = "";
|
|
||||||
|
|
||||||
currentProject.name = currentProject.name
|
|
||||||
.replaceAll("_", " ")
|
|
||||||
.replaceAll("-", " ");
|
|
||||||
|
|
||||||
currentProjectDiv.innerHTML = `
|
|
||||||
<div class="media">
|
|
||||||
<div class="media-body">
|
|
||||||
<a href="${currentProject.html_url}">
|
|
||||||
<strong class="d-block text-gray-dark">${currentProject.name}</strong>
|
|
||||||
</a>
|
|
||||||
<div class="stars">
|
|
||||||
${currentProject.language}
|
|
||||||
<i class="far fa-star stargazers"></i>${currentProject.stargazers_count}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p>${currentProject.description}</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
fetch(`https://raw.githubusercontent.com/${currentProject.full_name}/${currentProject.default_branch}/README.md`)
|
|
||||||
.then((rawResponse) => rawResponse.text())
|
|
||||||
.then((readmeText) => {
|
|
||||||
let markdownToHtmlConverter = new showdown.Converter();
|
|
||||||
let readmeInHtml = markdownToHtmlConverter.makeHtml(readmeText);
|
|
||||||
|
|
||||||
let projectReadmeModalDiv = document.createElement("div");
|
|
||||||
projectReadmeModalDiv.classList = "modal github-modal hidden";
|
|
||||||
|
|
||||||
projectReadmeModalDiv.innerHTML = `
|
|
||||||
<div class="card">
|
|
||||||
<a id="projectReadmeModalDiv-Close" style="float: right; cursor: pointer;">❌</a>
|
|
||||||
<a href="${currentProject.html_url}">Visit on GitHub</a>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
${readmeInHtml}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
currentProjectDiv.onclick = function () {
|
|
||||||
projectReadmeModalDiv.classList.remove("hidden");
|
|
||||||
document.body.scrollTop = 0;
|
|
||||||
document.documentElement.scrollTop = 0;
|
|
||||||
document.body.style.opacity = 0.2.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
projectReadmeModalDiv.onclick = function (mouseClick) {
|
|
||||||
if (mouseClick.target === projectReadmeModalDiv ||
|
|
||||||
mouseClick.target === document.getElementById("projectReadmeModalDiv-Close")) {
|
|
||||||
projectReadmeModalDiv.classList.add("hidden");
|
|
||||||
document.body.style.opacity = 1.0.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document
|
|
||||||
.getElementsByTagName("html")[0]
|
|
||||||
.appendChild(projectReadmeModalDiv);
|
|
||||||
});
|
|
||||||
|
|
||||||
projectsDiv.appendChild(currentProjectDiv);
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let longBioText = document.getElementsByClassName("long-bio-text")[0];
|
|
||||||
let isLongBioTextShown = false;
|
|
||||||
|
|
||||||
document.getElementById("short-bio-text").onclick = function () {
|
|
||||||
let leftArrow = document.getElementById("left-arrow");
|
|
||||||
let rightArrow = document.getElementById("right-arrow");
|
|
||||||
|
|
||||||
isLongBioTextShown = !isLongBioTextShown;
|
|
||||||
|
|
||||||
if (isLongBioTextShown) {
|
|
||||||
longBioText.classList.remove("hidden");
|
|
||||||
leftArrow.classList.remove("fa-arrow-right");
|
|
||||||
leftArrow.classList.add("fa-arrow-down");
|
|
||||||
rightArrow.classList.remove("fa-arrow-left");
|
|
||||||
rightArrow.classList.add("fa-arrow-down");
|
|
||||||
leftArrow.style.position = "relative";
|
|
||||||
rightArrow.style.position = "relative";
|
|
||||||
FadeIn(longBioText);
|
|
||||||
} else {
|
|
||||||
longBioText.classList.add("hidden");
|
|
||||||
leftArrow.classList.remove("fa-arrow-down");
|
|
||||||
leftArrow.classList.add("fa-arrow-right");
|
|
||||||
rightArrow.classList.remove("fa-arrow-down");
|
|
||||||
rightArrow.classList.add("fa-arrow-left");
|
|
||||||
leftArrow.style.position = "relative";
|
|
||||||
rightArrow.style.position = "relative";
|
|
||||||
FadeOut(longBioText);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
longBioText.onclick = function (mouseClick) {
|
|
||||||
if (mouseClick.target === longBioText) {
|
|
||||||
longBioText.classList.add("hidden");
|
|
||||||
document.body.style.opacity = 1.0.toString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function FadeOut(element) {
|
|
||||||
let transparency = 1;
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
if (transparency <= 0.1) {
|
|
||||||
clearInterval(interval)
|
|
||||||
element.style.display = 'none';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
transparency *= 0.9;
|
|
||||||
ApplyTransparency(element, transparency);
|
|
||||||
}, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
function FadeIn(element) {
|
|
||||||
let transparency = 0.1;
|
|
||||||
element.style.display = 'block';
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
if (transparency >= 1) {
|
|
||||||
clearInterval(interval);
|
|
||||||
ApplyTransparency(element, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
transparency *= 1.1;
|
|
||||||
ApplyTransparency(element, transparency);
|
|
||||||
}, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ApplyTransparency(element, transparency) {
|
|
||||||
element.style.opacity = transparency;
|
|
||||||
element.style.filter = `alpha(opacity=${Math.round(transparency * 100)})`;
|
|
||||||
}
|
|
||||||
@@ -1,556 +0,0 @@
|
|||||||
::-webkit-scrollbar {
|
|
||||||
width: var(--scroll-width);
|
|
||||||
height: var(--scroll-width);
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background: var(--scroll-thumb-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
|
||||||
background: var(--scroll-track-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--main-padding: 15px;
|
|
||||||
--main-margin: 10px;
|
|
||||||
--main-img-size: 200px;
|
|
||||||
--main-bio-size: 200px;
|
|
||||||
--main-bio-margin: 5px;
|
|
||||||
--main-icon-width: 80px;
|
|
||||||
--main-border-radius: 5px;
|
|
||||||
--padding-big: 20px;
|
|
||||||
--padding-small: 5px;
|
|
||||||
--main-container-width: 750px;
|
|
||||||
--main-txt-color: White;
|
|
||||||
--main-shadow-color: #6F3E38;
|
|
||||||
--donation-modal-height: 200px;
|
|
||||||
--donation-modal-width: 600px;
|
|
||||||
--donation-modal-top: 50%;
|
|
||||||
--scroll-width: 5px;
|
|
||||||
--scroll-thumb-bg: Red;
|
|
||||||
--scroll-track-bg: transparent;
|
|
||||||
--background-image: url("Images/Background.webp");
|
|
||||||
--blur-small: 20px;
|
|
||||||
--blur-large: 160px;
|
|
||||||
--shadow-y: 4px;
|
|
||||||
--shadow-blur: 16px;
|
|
||||||
--shadow-spread: 0;
|
|
||||||
--shadow-hover-y: 8px;
|
|
||||||
--shadow-hover-blur: 16px;
|
|
||||||
--font-size-large: 20px;
|
|
||||||
--width-medium: 60%;
|
|
||||||
--max-width-large: 90%;
|
|
||||||
--grid-column-width: 24%;
|
|
||||||
--portfolio-item-height: 128px;
|
|
||||||
--transition-duration-long: 0.5s;
|
|
||||||
--transition-duration-short: 0.3s;
|
|
||||||
--modal-card-height: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
a,
|
|
||||||
hr {
|
|
||||||
color: var(--main-txt-color);
|
|
||||||
text-decoration-line: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body,
|
|
||||||
html {
|
|
||||||
font-family: 'Outfit', Arial, sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
color: var(--main-txt-color);
|
|
||||||
text-align: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
background-attachment: fixed;
|
|
||||||
background-image: var(--background-image);
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
padding-bottom: var(--main-padding);
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer a {
|
|
||||||
color: var(--main-txt-color);
|
|
||||||
text-decoration-line: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
line-height-step: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav {
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
backdrop-filter: blur(var(--blur-large));
|
|
||||||
box-shadow: 0 var(--shadow-y) var(--shadow-blur) var(--shadow-spread) var(--main-shadow-color);
|
|
||||||
transition: var(--transition-duration-short);
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav li {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav li a {
|
|
||||||
display: block;
|
|
||||||
color: white;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav li a.active {
|
|
||||||
background-color: #2f3136;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav li a:hover:not(.active) {
|
|
||||||
background-color: #111;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav li.left {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bio {
|
|
||||||
text-decoration-line: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bio:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#donate {
|
|
||||||
text-decoration-line: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#donate:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#donateModal {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#github_projects .card {
|
|
||||||
padding: var(--padding-big);
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
#github_projects .card a {
|
|
||||||
color: var(--main-txt-color) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#github_projects .card p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#github_projects .stargazers {
|
|
||||||
padding-right: var(--padding-small);
|
|
||||||
}
|
|
||||||
|
|
||||||
#github_projects .stars {
|
|
||||||
color: var(--main-txt-color) !important;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
#github_projects a {
|
|
||||||
text-transform: capitalize;
|
|
||||||
text-decoration-line: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#left-arrow {
|
|
||||||
position: relative;
|
|
||||||
-webkit-animation: linear infinite alternate;
|
|
||||||
-webkit-animation-name: runLeft;
|
|
||||||
-webkit-animation-duration: 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
#right-arrow {
|
|
||||||
position: relative;
|
|
||||||
-webkit-animation: linear infinite alternate;
|
|
||||||
-webkit-animation-name: runRight;
|
|
||||||
-webkit-animation-duration: 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bio {
|
|
||||||
display: none !important;
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 900;
|
|
||||||
padding: var(--main-padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bio table .right {
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: var(--main-border-radius);
|
|
||||||
backdrop-filter: blur(150px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.long-bio-text {
|
|
||||||
font-size: var(--font-size-large);
|
|
||||||
opacity: 0;
|
|
||||||
width: var(--width-medium);
|
|
||||||
margin-bottom: var(--main-padding) !important;
|
|
||||||
margin: auto;
|
|
||||||
padding: var(--main-margin);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
margin-top: var(--main-padding);
|
|
||||||
box-shadow: 0 var(--shadow-y) var(--shadow-blur) var(--shadow-spread) var(--main-shadow-color);
|
|
||||||
transition: var(--transition-duration-short);
|
|
||||||
backdrop-filter: blur(var(--blur-small));
|
|
||||||
padding: var(--main-padding);
|
|
||||||
text-align: center;
|
|
||||||
color: var(--main-txt-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-projects {
|
|
||||||
display: grid;
|
|
||||||
box-shadow: 0 var(--shadow-y) var(--shadow-blur) var(--shadow-spread) var(--main-shadow-color);
|
|
||||||
transition: var(--transition-duration-short);
|
|
||||||
backdrop-filter: blur(var(--blur-large));
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-projects:hover {
|
|
||||||
box-shadow: 0 var(--shadow-hover-y) var(--shadow-hover-blur) var(--shadow-spread) var(--main-shadow-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:hover {
|
|
||||||
box-shadow: 0 var(--shadow-hover-y) var(--shadow-hover-blur) var(--shadow-spread) var(--main-shadow-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
background: transparent;
|
|
||||||
backdrop-filter: blur(var(--blur-small));
|
|
||||||
margin: auto;
|
|
||||||
width: var(--main-container-width);
|
|
||||||
}
|
|
||||||
|
|
||||||
.github-hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.github-modal img {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.github-modal > .card {
|
|
||||||
height: var(--modal-card-height) !important;
|
|
||||||
overflow-y: auto;
|
|
||||||
text-align: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-container {
|
|
||||||
margin: var(--main-margin);
|
|
||||||
display: grid;
|
|
||||||
justify-content: center;
|
|
||||||
grid-template-columns: auto auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-item {
|
|
||||||
width: var(--main-bio-size);
|
|
||||||
margin-left: var(--main-padding);
|
|
||||||
backdrop-filter: blur(var(--blur-large));
|
|
||||||
border-radius: var(--main-border-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-item h1,
|
|
||||||
.grid-item-start h1 {
|
|
||||||
margin: var(--main-bio-margin);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-item-start {
|
|
||||||
grid-row-start: 1;
|
|
||||||
grid-row-end: 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hover-items {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: auto auto auto;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hover-items a:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hover-items,
|
|
||||||
.hover-items a {
|
|
||||||
color: var(--main-txt-color);
|
|
||||||
padding: var(--main-padding) var(--main-margin);
|
|
||||||
font-size: large;
|
|
||||||
margin: auto;
|
|
||||||
line-height: 1.5em;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hoverable:hover {
|
|
||||||
backdrop-filter: blur(var(--blur-large));
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-area a {
|
|
||||||
color: var(--main-txt-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-area i {
|
|
||||||
justify-content: space-between;
|
|
||||||
width: var(--main-icon-width);
|
|
||||||
padding-top: var(--main-padding);
|
|
||||||
padding-bottom: var(--main-padding);
|
|
||||||
border-radius: var(--main-border-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-area i:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
backdrop-filter: blur(var(--blur-large));
|
|
||||||
}
|
|
||||||
|
|
||||||
.warning-text {
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 900;
|
|
||||||
padding: var(--main-padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
.max60 {
|
|
||||||
max-width: var(--max-width-large);
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-body {
|
|
||||||
color: var(--main-txt-color) !important;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
position: absolute;
|
|
||||||
margin: auto;
|
|
||||||
height: 100vh;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal .card {
|
|
||||||
opacity: 1;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: auto;
|
|
||||||
height: var(--donation-modal-height);
|
|
||||||
width: var(--donation-modal-width);
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nomargin {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, 128px);
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio-done {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(4, var(--grid-column-width));
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio-done-item {
|
|
||||||
height: var(--portfolio-item-height);
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile img {
|
|
||||||
margin: auto;
|
|
||||||
max-width: var(--main-img-size);
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.project {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.project img {
|
|
||||||
opacity: 1;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
transition: var(--transition-duration-long) ease;
|
|
||||||
backface-visibility: hidden;
|
|
||||||
box-shadow: 0 var(--shadow-y) var(--shadow-blur) var(--shadow-spread) var(--main-shadow-color);
|
|
||||||
transition: var(--transition-duration-short);
|
|
||||||
}
|
|
||||||
|
|
||||||
.project p {
|
|
||||||
transition: var(--transition-duration-long) ease;
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
-ms-transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.project:hover img {
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.project:hover p {
|
|
||||||
opacity: 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.refer-area {
|
|
||||||
text-decoration-line: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.social {
|
|
||||||
border: 0;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.social a {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table {
|
|
||||||
color: var(--main-txt-color) !important;
|
|
||||||
font-weight: lighter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes runLeft {
|
|
||||||
0% {
|
|
||||||
left: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
left: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
left: 70%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes runRight {
|
|
||||||
0% {
|
|
||||||
right: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
right: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
right: 70%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width:1025px) {
|
|
||||||
.circle {
|
|
||||||
height: 24px;
|
|
||||||
width: 24px;
|
|
||||||
border-radius: 24px;
|
|
||||||
background-color: black;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 99999999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 700px) {
|
|
||||||
:root {
|
|
||||||
--donation-modal-height: 350px;
|
|
||||||
--donation-modal-width: 600px;
|
|
||||||
--donation-modal-top: 50%;
|
|
||||||
--mobile-margin: 5px;
|
|
||||||
--main-container-width: 95%;
|
|
||||||
--mobile-width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body,
|
|
||||||
html {
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
position: absolute;
|
|
||||||
margin: auto;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal .card {
|
|
||||||
vertical-align: middle;
|
|
||||||
width: 80%;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width:700px) {
|
|
||||||
footer {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav li,
|
|
||||||
ul.nav li.right {
|
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav li.left {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#left-arrow {
|
|
||||||
position: initial !important;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#right-arrow {
|
|
||||||
position: initial !important;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.long-bio-text {
|
|
||||||
width: 95% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-container {
|
|
||||||
grid-template-columns: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-area i {
|
|
||||||
margin-top: var(--mobile-margin);
|
|
||||||
}
|
|
||||||
|
|
||||||
.max60 {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio-done {
|
|
||||||
grid-template-columns: auto;
|
|
||||||
justify-content: initial;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio-done-item {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.short_desc {
|
|
||||||
width: var(--mobile-width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"angular-portfolio-seite": {
|
||||||
|
"projectType": "application",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"style": "scss"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:application",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"browser": "src/main.ts",
|
||||||
|
"polyfills": [
|
||||||
|
"zone.js"
|
||||||
|
],
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"inlineStyleLanguage": "scss",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "public"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"node_modules/@angular/material/prebuilt-themes/rose-red.css",
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": [],
|
||||||
|
"server": "src/main.server.ts",
|
||||||
|
"prerender": true,
|
||||||
|
"ssr": {
|
||||||
|
"entry": "src/server.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"optimization": {
|
||||||
|
"scripts": true,
|
||||||
|
"styles": {
|
||||||
|
"minify": true,
|
||||||
|
"inlineCritical": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"namedChunks": false,
|
||||||
|
"extractLicenses": false,
|
||||||
|
"aot": true,
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "500kB",
|
||||||
|
"maximumError": "1MB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "4kB",
|
||||||
|
"maximumError": "8kB"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"optimization": false,
|
||||||
|
"extractLicenses": false,
|
||||||
|
"sourceMap": true,
|
||||||
|
"namedChunks": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "production"
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"port": 4200
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"buildTarget": "angular-portfolio-seite:build:production"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"buildTarget": "angular-portfolio-seite:build:development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development"
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"polyfills": [
|
||||||
|
"zone.js",
|
||||||
|
"zone.js/testing"
|
||||||
|
],
|
||||||
|
"tsConfig": "tsconfig.spec.json",
|
||||||
|
"inlineStyleLanguage": "scss",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "public",
|
||||||
|
"output": "public"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"node_modules/@angular/material/prebuilt-themes/rose-red.css",
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cli": {
|
||||||
|
"analytics": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"Server": {
|
||||||
|
"Host": "localhost",
|
||||||
|
"Port": 3005
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 259 KiB |
@@ -1,175 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
|
|
||||||
<title>Julian Lechner</title>
|
|
||||||
<link rel="icon" href="favicon.ico" />
|
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css">
|
|
||||||
<link rel="stylesheet" type="text/css" href="Resources/Style.css" />
|
|
||||||
|
|
||||||
<script rel="preload" src="https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js"></script>
|
|
||||||
<script async rel="preload" src="Resources/Javascript.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<section class="container">
|
|
||||||
<div class="card profile">
|
|
||||||
|
|
||||||
<img src="Resources/Images/Logo.webp" width="200px" height="200px" fetchpriority="high" alt="Online Profilbild von Julian Lechner"/>
|
|
||||||
<h1>Hallo! 👋 I'm Julian Lechner!</h1>
|
|
||||||
<h3>📍 Austria, Vienna</h3>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="max60">
|
|
||||||
<div id="short-bio-text" class="hover-items">
|
|
||||||
<i id="left-arrow" class="fas fa-arrow-right"></i>
|
|
||||||
|
|
||||||
<a>
|
|
||||||
<u>
|
|
||||||
<h3>A young enthusiastic developer from Austria!</h3>
|
|
||||||
</u>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<i id="right-arrow" class="fas fa-arrow-left"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="long-bio-text hidden">
|
|
||||||
<p>
|
|
||||||
My name is Julian, many people also call me Julie. I'm %AGE% years old and come from beautiful Austria.
|
|
||||||
I spend most of my time in trains.
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
My biggest hobby apart from software development is diving. Floating in deep water and only thinking
|
|
||||||
about the here and now always brings me back to the depths. I try to practice this hobby as often as
|
|
||||||
possible for fun and my health.
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
I currently work mainly for the Viennese company SobIT Gmbh. This company develops software for most
|
|
||||||
care companies in Austria, both for staff scheduling and for patient registration.
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
I also work for a company called GERLACH SYSTEMS, which is the owner of the SynRadio and SynHost
|
|
||||||
projects. Their main business is the rental of servers, domains, web servers, game servers, etc. at
|
|
||||||
various locations.
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
<a href="mailto:contact@fraujulian.xyz">
|
|
||||||
<h3>Just contact me!</h3>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<noscript>
|
|
||||||
<h2 class="warning-text">Enable JavaScript to see more.</h2>
|
|
||||||
</noscript>
|
|
||||||
|
|
||||||
<div class="bio grid-container">
|
|
||||||
<div class="grid-item-start">
|
|
||||||
<h1>I work with</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>NodeJS</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>JavaScript</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>TypeScript</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>HTML</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>CSS</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>C#</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>.NET</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>WPF</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>Avalonia</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>Ubuntu</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>WebStorm</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>Rider</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>SSMS</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>MySQL</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>Java</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>Github</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>Gitlab</h1>
|
|
||||||
</div>
|
|
||||||
<div class="grid-item">
|
|
||||||
<h1>Azure Devops</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="contact-area">
|
|
||||||
<a href="mailto:contact@fraujulian.xyz">
|
|
||||||
<i class="fa-solid fa-envelope fa-3x"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="tel:+436609254001">
|
|
||||||
<i class="fa-solid fa-phone fa-3x"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="https://discord.com/users/860206216893693973">
|
|
||||||
<i class="fab fa-discord fa-3x"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="https://github.com/fraujulian">
|
|
||||||
<i class="fab fa-github fa-3x"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="https://www.xing.com/profile/Julian_Lechner03274">
|
|
||||||
<i class="fab fa-xing fa-3x"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="https://www.linkedin.com/in/julian-lechner-98b377356/">
|
|
||||||
<i class="fab fa-linkedin fa-3x"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="github_projects" class="card">
|
|
||||||
<h2 id="loading-text" class="warning-text">Enable JavaScript to see more.</h2>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p>
|
|
||||||
<a href="IMPRINT/index.html">IMPRINT</a> | © 2023 - %CURRENT_YEAR% Julian Lechner - All rights reserved.
|
|
||||||
</p>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"name": "angular-portfolio-seite",
|
||||||
|
"version": "3.0.6",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "ng serve",
|
||||||
|
"test": "ng test",
|
||||||
|
"clean": "del-cli dist && echo SUCCEED CLEAN",
|
||||||
|
"compress-images": "imagemin \"public/**/*.{png,jpg,jpeg,ico,webp}\" --plugin.optipng.optimizationLevel=1 --plugin=jpegtran --plugin.webp.lossless=true --out-dir=public",
|
||||||
|
"updatePackageVersions": "ng update @angular/cli @angular/core && ng update && npm update",
|
||||||
|
"updateProjectVersion": "npm version patch --no-git-tag-version && echo SUCCEED UPDATE VERSION",
|
||||||
|
"buildDevelopment": "npm run clean && npm run compress-images && ng build --configuration development && echo SUCCEED DEV BUILD && npm run updateProjectVersion",
|
||||||
|
"buildProduction": "npm run clean && npm run compress-images && ng build --configuration production && echo SUCCEED PROD BUILD && npm run updateProjectVersion",
|
||||||
|
"start": "node dist/server/server.mjs"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "^19.2.14",
|
||||||
|
"@angular/cdk": "^19.2.19",
|
||||||
|
"@angular/common": "^19.2.0",
|
||||||
|
"@angular/compiler": "^19.2.0",
|
||||||
|
"@angular/core": "^19.2.0",
|
||||||
|
"@angular/forms": "^19.2.0",
|
||||||
|
"@angular/material": "^19.2.19",
|
||||||
|
"@angular/platform-browser": "^19.2.0",
|
||||||
|
"@angular/platform-browser-dynamic": "^19.2.0",
|
||||||
|
"@angular/platform-server": "^19.2.0",
|
||||||
|
"@angular/router": "^19.2.0",
|
||||||
|
"@angular/ssr": "^19.2.9",
|
||||||
|
"@fortawesome/angular-fontawesome": "^1.0.0",
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||||
|
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"markdown-it": "^14.1.0",
|
||||||
|
"rxjs": "~7.8.0",
|
||||||
|
"tslib": "^2.3.0",
|
||||||
|
"zone.js": "~0.15.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "^19.2.9",
|
||||||
|
"@angular/cli": "^19.2.9",
|
||||||
|
"@angular/compiler-cli": "^19.2.0",
|
||||||
|
"@types/express": "^4.17.17",
|
||||||
|
"@types/jasmine": "~5.1.0",
|
||||||
|
"@types/markdown-it": "^14.1.2",
|
||||||
|
"@types/node": "^18.18.0",
|
||||||
|
"@types/showdown": "^2.0.6",
|
||||||
|
"del-cli": "^6.0.0",
|
||||||
|
"imagemin-cli": "^8.0.0",
|
||||||
|
"imagemin-jpegtran": "^8.0.0",
|
||||||
|
"imagemin-mozjpeg": "^10.0.0",
|
||||||
|
"imagemin-optipng": "^8.0.0",
|
||||||
|
"imagemin-pngquant": "^10.0.0",
|
||||||
|
"imagemin-webp": "^8.0.0",
|
||||||
|
"jasmine-core": "~5.6.0",
|
||||||
|
"karma": "~6.4.0",
|
||||||
|
"karma-chrome-launcher": "~3.2.0",
|
||||||
|
"karma-coverage": "~2.2.0",
|
||||||
|
"karma-jasmine": "~5.1.0",
|
||||||
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
|
"typescript": "~5.7.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 45 MiB |
|
After Width: | Height: | Size: 295 KiB |
|
After Width: | Height: | Size: 199 KiB |
|
After Width: | Height: | Size: 264 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<router-outlet></router-outlet>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {AppComponent} from './app.component';
|
||||||
|
|
||||||
|
describe('AppComponent', (): void => {
|
||||||
|
beforeEach(async (): Promise<void> => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [AppComponent],
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the app', (): void => {
|
||||||
|
const fixture: ComponentFixture<AppComponent> = TestBed.createComponent(AppComponent);
|
||||||
|
const app: AppComponent = fixture.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have the 'Angular-Portfolio-Seite' title`, (): void => {
|
||||||
|
const fixture: ComponentFixture<AppComponent> = TestBed.createComponent(AppComponent);
|
||||||
|
const app: AppComponent = fixture.componentInstance;
|
||||||
|
expect(app.title).toEqual('Angular-Portfolio-Seite');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title', (): void => {
|
||||||
|
const fixture: ComponentFixture<AppComponent> = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.nativeElement as HTMLElement;
|
||||||
|
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, Angular-Portfolio-Seite');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import {Component} from '@angular/core'
|
||||||
|
import {RouterOutlet} from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
imports: [
|
||||||
|
RouterOutlet
|
||||||
|
],
|
||||||
|
templateUrl: './app.component.html'
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
title: string = "Angular-Portfolio-Seite";
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import {mergeApplicationConfig, ApplicationConfig} from '@angular/core';
|
||||||
|
import {provideServerRendering} from '@angular/platform-server';
|
||||||
|
|
||||||
|
import {appConfig} from './app.config';
|
||||||
|
|
||||||
|
const serverConfig: ApplicationConfig = {
|
||||||
|
providers: [
|
||||||
|
provideServerRendering(),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const config: ApplicationConfig = mergeApplicationConfig(appConfig, serverConfig);
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import {ApplicationConfig, importProvidersFrom, provideZoneChangeDetection} from '@angular/core';
|
||||||
|
import {provideRouter} from '@angular/router';
|
||||||
|
import {BrowserModule, provideClientHydration, withEventReplay} from '@angular/platform-browser';
|
||||||
|
|
||||||
|
import {routes} from './app.routes';
|
||||||
|
import {provideAnimations} from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
|
export const appConfig: ApplicationConfig = {
|
||||||
|
providers: [
|
||||||
|
provideZoneChangeDetection({eventCoalescing: true}),
|
||||||
|
provideRouter(routes),
|
||||||
|
provideClientHydration(withEventReplay()),
|
||||||
|
importProvidersFrom(BrowserModule),
|
||||||
|
provideAnimations()
|
||||||
|
]
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import {Routes} from '@angular/router';
|
||||||
|
|
||||||
|
import {HomeComponent} from './home/home.component';
|
||||||
|
import {ImprintComponent} from './imprint/imprint.component';
|
||||||
|
|
||||||
|
export const routes: Routes = [
|
||||||
|
{path: '', component: HomeComponent, pathMatch: 'full'},
|
||||||
|
{path: 'imprint', component: ImprintComponent, pathMatch: 'full'},
|
||||||
|
{path: '**', redirectTo: ''}
|
||||||
|
];
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<noscript>
|
||||||
|
<div class="container">
|
||||||
|
<div class="card">
|
||||||
|
<h2 id="loading-text" class="warning-text">
|
||||||
|
Enable javascript for the full experience!
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</noscript>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>
|
||||||
|
<a routerLink="/imprint">IMPRINT</a> | © 2023
|
||||||
|
- {{ currentYear }} {{ globalFields.firstname }} {{ globalFields.lastname }} - All rights reserved.
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { FooterComponent } from './footer.component';
|
||||||
|
|
||||||
|
describe('FooterComponent', () => {
|
||||||
|
let component: FooterComponent;
|
||||||
|
let fixture: ComponentFixture<FooterComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [FooterComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(FooterComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import {Component} from '@angular/core';
|
||||||
|
import {RouterLink} from "@angular/router";
|
||||||
|
import {globalFields} from '../../global.fields';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-footer',
|
||||||
|
imports: [
|
||||||
|
RouterLink
|
||||||
|
],
|
||||||
|
templateUrl: './footer.component.html'
|
||||||
|
})
|
||||||
|
export class FooterComponent {
|
||||||
|
protected readonly globalFields: typeof globalFields = globalFields;
|
||||||
|
|
||||||
|
protected readonly currentYear: number = new Date().getFullYear();
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
<section class="container">
|
||||||
|
<div class="card profile">
|
||||||
|
|
||||||
|
<img ngSrc="Logo.png" (click)="openInfo()" priority width="200" height="200" fetchpriority="high" alt="profile picture"/>
|
||||||
|
<h1>Hallo! 👋 I'm {{ globalFields.firstname }} {{ globalFields.lastname }}!</h1>
|
||||||
|
<h3>📍 Austria, Vienna</h3>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="max60">
|
||||||
|
<div id="short-bio-text" class="hover-items" (click)="toggleBio()">
|
||||||
|
<fa-icon id="left-arrow" [icon]=" isLongBioShown ? faArrowDown : faArrowRight "></fa-icon>
|
||||||
|
|
||||||
|
<a>
|
||||||
|
<u>
|
||||||
|
<h3>A young enthusiastic developer from Austria!</h3>
|
||||||
|
</u>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<fa-icon id="right-arrow" [icon]=" isLongBioShown ? faArrowDown : faArrowLeft "></fa-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="long-bio-text" *ngIf="isLongBioShown" @fadeInOut (click)="closeOnOverlayClick($event)">
|
||||||
|
<p>
|
||||||
|
My name is {{ globalFields.firstname }}, many people also call me Julie. I'm {{ age }} years old and come from
|
||||||
|
beautiful Austria.
|
||||||
|
I spend most of my time in trains.
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
My biggest hobby apart from software development is diving. Floating in deep water and only thinking
|
||||||
|
about the here and now always brings me back to the depths. I try to practice this hobby as often as
|
||||||
|
possible for fun and my health.
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
I currently work mainly for the Viennese company SobIT Gmbh. This company develops software for most
|
||||||
|
care companies in Austria, both for staff scheduling and for patient registration.
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
I also work for a company called GERLACH SYSTEMS, which is the owner of the SynRadio and SynHost
|
||||||
|
projects. Their main business is the rental of servers, domains, web servers, game servers, etc. at
|
||||||
|
various locations.
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<a [href]="contactSafeMail">
|
||||||
|
<b><u><h3>Just contact me!</h3></u></b>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="bio grid-container">
|
||||||
|
<div class="grid-item-start">
|
||||||
|
<h1>I work with</h1>
|
||||||
|
</div>
|
||||||
|
<div class="grid-item" *ngFor="let bioText of bioTextsList; let i = index" [hidden]="i !== currentIndex">
|
||||||
|
<h1>{{ bioText }}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="contact-area">
|
||||||
|
<a [href]="contactSafeMail">
|
||||||
|
<span>
|
||||||
|
<fa-icon [icon]="faEnvelope" size="3x"></fa-icon>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="tel:{{globalFields.hrefContactPhone}}">
|
||||||
|
<fa-icon class="fab" [icon]="faPhone" size="3x"></fa-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://discord.com/users/860206216893693973">
|
||||||
|
<fa-icon class="fab" [icon]="faDiscord" size="3x"></fa-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://github.com/fraujulian">
|
||||||
|
<fa-icon class="fab" [icon]="faGithub" size="3x"></fa-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://www.xing.com/profile/Julian_Lechner03274">
|
||||||
|
<fa-icon class="fab" [icon]="faXing" size="3x"></fa-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://www.linkedin.com/in/julian-lechner-98b377356/">
|
||||||
|
<fa-icon class="fab" [icon]="faLinkedin" size="3x"></fa-icon>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div id="github_projects">
|
||||||
|
<div *ngFor="let project of projects">
|
||||||
|
<div class="container" [class.clickable]="project.Clickable" [class.disabled]="!project.Clickable"
|
||||||
|
[style.cursor]="project.Clickable ? 'pointer' : 'default'"
|
||||||
|
(click)="project.Clickable && (project.IsReadmeShown = true)">
|
||||||
|
<div class="card">
|
||||||
|
<div class="media">
|
||||||
|
<div class="media-body">
|
||||||
|
<a href="{{project.Link}}">
|
||||||
|
<u><strong class="d-block text-gray-dark">{{ project.Title }}</strong></u>
|
||||||
|
</a>
|
||||||
|
<div class="stars">
|
||||||
|
{{ project.Languages.join(' | ') }}
|
||||||
|
<ng-container *ngIf="project.Stars != null">
|
||||||
|
<fa-icon [icon]="faStar"></fa-icon>
|
||||||
|
{{ project.Stars }}
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>{{ project.Description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<app-footer ngSkipHydration></app-footer>
|
||||||
|
|
||||||
|
<div *ngFor="let project of projects">
|
||||||
|
<div *ngIf="project.IsReadmeShown" class="modal github-modal">
|
||||||
|
<div class="modal github-modal card big-card">
|
||||||
|
<a class="modalClose" (click)="project.IsReadmeShown = false">❌</a>
|
||||||
|
<a href="{{project.Link}}">Visit on GitHub</a>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<div [innerHTML]="project.Readme"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="isApiRateLimitExceeded" class="modal github-modal">
|
||||||
|
<div class="modal github-modal card mini-card">
|
||||||
|
<a class="modalClose" (click)="isApiRateLimitExceeded = false">❌</a>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<h1 style="text-align: center">You have exceeded the today's github api request limits!</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {HomeComponent} from './home.component';
|
||||||
|
|
||||||
|
describe('HomeComponent', (): void => {
|
||||||
|
let component: HomeComponent;
|
||||||
|
let fixture: ComponentFixture<HomeComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [HomeComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(HomeComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', (): void => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
import {
|
||||||
|
Component,
|
||||||
|
NgZone,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
} from '@angular/core';
|
||||||
|
import {trigger, transition, style, animate} from '@angular/animations';
|
||||||
|
import {faArrowRight, faArrowLeft, faArrowDown, faStar, faEnvelope, faPhone} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import {
|
||||||
|
faDiscord,
|
||||||
|
faGithub,
|
||||||
|
faXing,
|
||||||
|
faLinkedin
|
||||||
|
} from '@fortawesome/free-brands-svg-icons';
|
||||||
|
import {NgForOf, NgIf, NgOptimizedImage} from '@angular/common';
|
||||||
|
import {FaIconComponent, IconDefinition} from '@fortawesome/angular-fontawesome';
|
||||||
|
import {DomSanitizer, SafeUrl} from '@angular/platform-browser';
|
||||||
|
import {interval, Subscription} from 'rxjs';
|
||||||
|
import MarkdownIt from 'markdown-it';
|
||||||
|
|
||||||
|
import {globalFields} from '../../global.fields';
|
||||||
|
import {FooterComponent} from '../footer/footer.component';
|
||||||
|
import {MatDialog} from '@angular/material/dialog';
|
||||||
|
import {StalkerComponent} from '../stalker/stalker.component';
|
||||||
|
|
||||||
|
interface Project {
|
||||||
|
Link: string;
|
||||||
|
Title: string;
|
||||||
|
FullName?: string;
|
||||||
|
Description: string;
|
||||||
|
Languages: string[];
|
||||||
|
DefaultBranch?: string;
|
||||||
|
Stars?: number;
|
||||||
|
IsReadmeShown: boolean;
|
||||||
|
Readme?: string;
|
||||||
|
Clickable?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-home',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
NgOptimizedImage,
|
||||||
|
FooterComponent,
|
||||||
|
NgIf,
|
||||||
|
FaIconComponent,
|
||||||
|
NgForOf
|
||||||
|
],
|
||||||
|
templateUrl: './home.component.html',
|
||||||
|
animations: [
|
||||||
|
trigger('fadeInOut', [
|
||||||
|
transition(':enter', [
|
||||||
|
style({opacity: 0}),
|
||||||
|
animate('300ms ease-in', style({opacity: 1}))
|
||||||
|
]),
|
||||||
|
transition(':leave', [
|
||||||
|
animate('300ms ease-out', style({opacity: 0}))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class HomeComponent implements OnInit, OnDestroy {
|
||||||
|
protected readonly globalFields: typeof globalFields = globalFields;
|
||||||
|
|
||||||
|
protected readonly age: number | string = this.calculateAge('2009-03-03');
|
||||||
|
|
||||||
|
protected isLongBioShown: boolean = false;
|
||||||
|
protected isApiRateLimitExceeded: boolean = false;
|
||||||
|
protected readonly faArrowRight: IconDefinition = faArrowRight;
|
||||||
|
protected readonly faArrowLeft: IconDefinition = faArrowLeft;
|
||||||
|
protected readonly faArrowDown: IconDefinition = faArrowDown;
|
||||||
|
protected readonly faStar: IconDefinition = faStar;
|
||||||
|
protected readonly faEnvelope: IconDefinition = faEnvelope;
|
||||||
|
protected readonly faPhone: IconDefinition = faPhone;
|
||||||
|
readonly faDiscord: IconDefinition = faDiscord;
|
||||||
|
readonly faGithub: IconDefinition = faGithub;
|
||||||
|
readonly faXing: IconDefinition = faXing;
|
||||||
|
readonly faLinkedin: IconDefinition = faLinkedin;
|
||||||
|
|
||||||
|
protected readonly contactSafeMail: SafeUrl;
|
||||||
|
|
||||||
|
protected readonly personalInformation: string = 'You found an easter egg, why are you here!?!\nYou want to know more personal things about me? - Then you will find your information here!:';
|
||||||
|
readonly bioTextsList: string[] = [
|
||||||
|
'C#',
|
||||||
|
'.NET',
|
||||||
|
'.NET Framework',
|
||||||
|
'WPF',
|
||||||
|
'Avalonia',
|
||||||
|
'NodeJS',
|
||||||
|
'Angular',
|
||||||
|
'TypeScript',
|
||||||
|
'JavaScript',
|
||||||
|
'Java',
|
||||||
|
'HTML',
|
||||||
|
'(S)CSS',
|
||||||
|
'Github',
|
||||||
|
'Gitlab',
|
||||||
|
'Azure DevOps',
|
||||||
|
'Ubuntu',
|
||||||
|
'Debian',
|
||||||
|
'SSMS',
|
||||||
|
'MariaDB',
|
||||||
|
'MySQL',
|
||||||
|
'Grandle'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected currentIndex = 0;
|
||||||
|
private sub!: Subscription;
|
||||||
|
|
||||||
|
protected projects: Project[] = [
|
||||||
|
{
|
||||||
|
Link: "https://www.synradio.de/",
|
||||||
|
Title: "SynRadio",
|
||||||
|
Description: "🖥️ An internet radio station that is available on various media.",
|
||||||
|
Languages: ["TypeScript", "JavaScript", "HTML", "CSS"],
|
||||||
|
Clickable: false,
|
||||||
|
IsReadmeShown: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Link: "https://www.synhost.de/",
|
||||||
|
Title: "SynHost",
|
||||||
|
Description: "❓ A support system integrating various platforms and media to offer employees a unified overview.",
|
||||||
|
Languages: ["TypeScript"],
|
||||||
|
Clickable: false,
|
||||||
|
IsReadmeShown: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
constructor(private _sanitizer: DomSanitizer, private zone: NgZone, private dialog: MatDialog) {
|
||||||
|
this.fillProjects();
|
||||||
|
this.contactSafeMail = this._sanitizer.bypassSecurityTrustUrl(`mailto:${globalFields.contactMail}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.zone.runOutsideAngular((): void => {
|
||||||
|
this.sub = interval(1000).subscribe((): void => {
|
||||||
|
this.zone.run((): void => {
|
||||||
|
this.currentIndex = (this.currentIndex + 1) % this.bioTextsList.length;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.sub.unsubscribe();
|
||||||
|
}
|
||||||
|
openInfo(): void {
|
||||||
|
this.dialog.open(StalkerComponent, {
|
||||||
|
width: '420px',
|
||||||
|
data: { message: this.personalInformation }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private fillProjects(): void {
|
||||||
|
const sortOnKey: <T>(key: keyof T, descending: boolean) => (a: T, b: T) => number = <T>(key: keyof T, descending: boolean): (a: T, b: T) => number => {
|
||||||
|
return (a: T, b: T): number => {
|
||||||
|
const aValue = a[key] as number;
|
||||||
|
const bValue = b[key] as number;
|
||||||
|
return descending ? bValue - aValue : aValue - bValue;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch(`https://api.github.com/users/${this.globalFields.githubUsername}/repos?per_page=${this.globalFields.numberOfLoadedRepositories}`)
|
||||||
|
.then(async (rawResponse: Response): Promise<any> => {
|
||||||
|
if (rawResponse.status === 403) {
|
||||||
|
const data = await rawResponse.json();
|
||||||
|
if (data.message && data.documentation_url) {
|
||||||
|
this.isApiRateLimitExceeded = true;
|
||||||
|
}
|
||||||
|
throw new Error('403 Forbidden');
|
||||||
|
}
|
||||||
|
return rawResponse.json();
|
||||||
|
})
|
||||||
|
.then((allProjects: any): void => {
|
||||||
|
allProjects = allProjects.sort(sortOnKey("stargazers_count", true));
|
||||||
|
allProjects.sort(sortOnKey("stargazers_count", true)).forEach((currentProject: any): void => {
|
||||||
|
if (currentProject === undefined || currentProject.fork === true) return;
|
||||||
|
if (currentProject.description == null) currentProject.description = "";
|
||||||
|
if (currentProject.name === "FrauJulian") return;
|
||||||
|
|
||||||
|
let newProject: Project = {
|
||||||
|
Link: "",
|
||||||
|
Title: "",
|
||||||
|
FullName: "",
|
||||||
|
Description: "",
|
||||||
|
Languages: [],
|
||||||
|
DefaultBranch: "",
|
||||||
|
Stars: 0,
|
||||||
|
Clickable: true,
|
||||||
|
IsReadmeShown: false,
|
||||||
|
Readme: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
if (currentProject.language != null) {
|
||||||
|
fetch(currentProject.languages_url)
|
||||||
|
.then((rawResponse: Response): Promise<any> => rawResponse.json())
|
||||||
|
.then((languages: any): void => {
|
||||||
|
newProject.Languages = Object.keys(languages);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
newProject.Languages = [""];
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(`https://raw.githubusercontent.com/${currentProject.full_name}/${currentProject.default_branch}/README.md`)
|
||||||
|
.then((rawResponse: Response): Promise<any> => rawResponse.text())
|
||||||
|
.then((readmeText: string): void => {
|
||||||
|
newProject.Readme = new MarkdownIt({html: true, linkify: true, typographer: true}).render(readmeText);
|
||||||
|
});
|
||||||
|
|
||||||
|
currentProject.name = currentProject.name
|
||||||
|
.replaceAll("_", " ")
|
||||||
|
.replaceAll("-", " ");
|
||||||
|
|
||||||
|
newProject.Link = currentProject.html_url;
|
||||||
|
newProject.Title = currentProject.name;
|
||||||
|
newProject.FullName = currentProject.full_name;
|
||||||
|
newProject.Description = currentProject.description;
|
||||||
|
newProject.DefaultBranch = currentProject.default_branch;
|
||||||
|
newProject.Stars = currentProject.stargazers_count;
|
||||||
|
newProject.IsReadmeShown = false;
|
||||||
|
|
||||||
|
this.projects.push(newProject);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected toggleBio(): void {
|
||||||
|
this.isLongBioShown = !this.isLongBioShown;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected closeOnOverlayClick(evt: MouseEvent): void {
|
||||||
|
if ((evt.target as HTMLElement).classList.contains('long-bio-overlay')) {
|
||||||
|
this.isLongBioShown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private calculateAge(birthDateString: string): number | string {
|
||||||
|
let birthDate: Date = new Date(birthDateString);
|
||||||
|
let now: Date = new Date();
|
||||||
|
let diffMs: number = now.getTime() - birthDate.getTime();
|
||||||
|
let diffYears: number = diffMs / (1000 * 60 * 60 * 24 * 365.25);
|
||||||
|
let tempAge: string = diffYears.toFixed(1);
|
||||||
|
return tempAge.endsWith('.0') ? Math.round(diffYears) : tempAge;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<div class="container">
|
||||||
|
<div class="card profile">
|
||||||
|
|
||||||
|
<h1>Imprint</h1>
|
||||||
|
|
||||||
|
<h2>Information according to §5 ECG</h2>
|
||||||
|
|
||||||
|
{{ globalFields.firstname }} {{ globalFields.lastname }} <br>
|
||||||
|
{{ street }} {{ houseNumber }} <br>
|
||||||
|
{{ zip }} {{ city }} <br>
|
||||||
|
{{ country }} <br>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<h4>Contact:</h4>
|
||||||
|
Phone: <b><u><a href="tel:{{globalFields.hrefContactPhone}}">{{ globalFields.contactPhone }}</a></u></b> <br>
|
||||||
|
E-Mail: <b><u><a [href]="contactSafeMail">{{ globalFields.contactMail }}</a></u></b>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<h4>Abuse Contact:</h4>
|
||||||
|
E-Mail: <b><u><a [href]="abuseSafeMail">{{ abuseMail }}</a></u></b>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<h2>Disclaimer:</h2>
|
||||||
|
|
||||||
|
<h3>Liability for links</h3>
|
||||||
|
Our website contains links to external third-party websites over whose content we have no influence. Therefore, we
|
||||||
|
cannot accept any liability for this third-party content. The respective provider or operator of the pages is
|
||||||
|
always responsible for the content of the linked pages. The linked pages were checked for possible legal
|
||||||
|
violations at the time of linking. Illegal content was not recognizable at the time of linking. However, permanent
|
||||||
|
monitoring of the content of the linked pages is not reasonable without concrete evidence of an infringement. If
|
||||||
|
we become aware of any legal infringements, we will remove such links immediately.
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<h3>Copyright</h3>
|
||||||
|
The content and works created by the site operators on these pages are subject to German copyright law.
|
||||||
|
Duplication, processing, distribution and any form of commercialization of such material beyond the scope of the
|
||||||
|
copyright law shall require the prior written consent of its respective author or creator. Downloads and copies of
|
||||||
|
this site are only permitted for private, non-commercial use. Insofar as the content on this site was not created
|
||||||
|
by the operator, the copyrights of third parties are respected. In particular, third-party content is identified
|
||||||
|
as such. Should you nevertheless become aware of a copyright infringement, please inform us accordingly. If we
|
||||||
|
become aware of any infringements, we will remove such content immediately.
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<h3>Data privacy</h3>
|
||||||
|
The use of our website is generally possible without providing personal data. Insofar as personal data (e.g. name,
|
||||||
|
address or e-mail addresses) is collected on our website, this is always done on a voluntary basis as far as
|
||||||
|
possible. This data will not be passed on to third parties without your express consent.
|
||||||
|
We would like to point out that data transmission over the Internet (e.g. when communicating by e-mail) may be
|
||||||
|
subject to security vulnerabilities. Complete protection of data against access by third parties is not possible.
|
||||||
|
We hereby expressly prohibit the use of contact data published within the scope of the imprint obligation by third
|
||||||
|
parties for sending unsolicited advertising and information material. The operators of the website expressly
|
||||||
|
reserve the right to take legal action in the event of the unsolicited sending of advertising information, such as
|
||||||
|
spam e-mails.
|
||||||
|
|
||||||
|
<div class="max60">
|
||||||
|
<div id="short-desc" class="hover-items" routerLink="">
|
||||||
|
<fa-icon [icon]="faArrowRight"></fa-icon>
|
||||||
|
<a>
|
||||||
|
<u>
|
||||||
|
<h2>Back</h2>
|
||||||
|
</u>
|
||||||
|
</a>
|
||||||
|
<fa-icon [icon]="faArrowLeft"></fa-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<app-footer ngSkipHydration></app-footer>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ImprintComponent } from './imprint.component';
|
||||||
|
|
||||||
|
describe('ImprintComponent', (): void => {
|
||||||
|
let component: ImprintComponent;
|
||||||
|
let fixture: ComponentFixture<ImprintComponent>;
|
||||||
|
|
||||||
|
beforeEach(async (): Promise<void> => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ImprintComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ImprintComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', (): void => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {FooterComponent} from '../footer/footer.component';
|
||||||
|
import {RouterLink} from '@angular/router';
|
||||||
|
import {globalFields} from '../../global.fields';
|
||||||
|
import {DomSanitizer, SafeUrl} from '@angular/platform-browser';
|
||||||
|
import {FaIconComponent, IconDefinition} from '@fortawesome/angular-fontawesome';
|
||||||
|
import {faArrowDown, faArrowLeft, faArrowRight} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-imprint',
|
||||||
|
imports: [
|
||||||
|
FooterComponent,
|
||||||
|
FaIconComponent,
|
||||||
|
RouterLink
|
||||||
|
],
|
||||||
|
templateUrl: './imprint.component.html'
|
||||||
|
})
|
||||||
|
export class ImprintComponent implements OnInit {
|
||||||
|
protected readonly globalFields: typeof globalFields = globalFields;
|
||||||
|
|
||||||
|
protected readonly street: string = 'Ulmenstraße';
|
||||||
|
protected readonly houseNumber: number = 9;
|
||||||
|
protected readonly zip: number = 3380;
|
||||||
|
protected readonly city: string = 'Pöchlarn';
|
||||||
|
protected readonly country: string = 'Austria';
|
||||||
|
protected readonly abuseMail: string = 'abuse@fraujulian.xyz';
|
||||||
|
|
||||||
|
protected contactSafeMail!: SafeUrl;
|
||||||
|
protected abuseSafeMail!: SafeUrl;
|
||||||
|
|
||||||
|
protected readonly faArrowRight: IconDefinition = faArrowRight;
|
||||||
|
protected readonly faArrowLeft: IconDefinition = faArrowLeft;
|
||||||
|
|
||||||
|
constructor(private _sanitizer: DomSanitizer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.contactSafeMail = this._sanitizer.bypassSecurityTrustUrl(`mailto:${globalFields.contactMail}`);
|
||||||
|
this.abuseSafeMail = this._sanitizer.bypassSecurityTrustUrl(`mailto:${this.abuseMail}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<h1 mat-dialog-title>STALKER!!!</h1>
|
||||||
|
|
||||||
|
<div mat-dialog-content *ngFor="let line of lines">
|
||||||
|
{{ line }} <br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button mat-dialog-close>Close</button>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {StalkerComponent} from './stalker.component';
|
||||||
|
|
||||||
|
describe('StalkerComponent', (): void => {
|
||||||
|
let component: StalkerComponent;
|
||||||
|
let fixture: ComponentFixture<StalkerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async (): Promise<void> => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [StalkerComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(StalkerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', (): void => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import {Component, Inject} from '@angular/core';
|
||||||
|
import {
|
||||||
|
MAT_DIALOG_DATA,
|
||||||
|
MatDialogActions,
|
||||||
|
MatDialogClose,
|
||||||
|
MatDialogContent,
|
||||||
|
MatDialogTitle
|
||||||
|
} from '@angular/material/dialog';
|
||||||
|
import {MatButton} from '@angular/material/button';
|
||||||
|
import {NgForOf, CommonModule} from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-stalker',
|
||||||
|
imports: [
|
||||||
|
MatDialogTitle,
|
||||||
|
MatDialogActions,
|
||||||
|
MatDialogContent,
|
||||||
|
MatButton,
|
||||||
|
MatDialogClose,
|
||||||
|
CommonModule
|
||||||
|
],
|
||||||
|
templateUrl: './stalker.component.html'
|
||||||
|
})
|
||||||
|
export class StalkerComponent {
|
||||||
|
lines: string[];
|
||||||
|
|
||||||
|
constructor(@Inject(MAT_DIALOG_DATA) public data: { message: string }) {
|
||||||
|
this.lines = (data.message ?? '').split('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export class globalFields {
|
||||||
|
public static readonly firstname: string = 'Julian';
|
||||||
|
public static readonly lastname: string = 'Lechner';
|
||||||
|
public static readonly contactMail: string = 'contact@fraujulian.xyz';
|
||||||
|
public static readonly contactPhone: string = '+43 (0) 660 9254001';
|
||||||
|
public static readonly hrefContactPhone: string = 'contact@fraujulian.xyz';
|
||||||
|
public static readonly githubUsername: string = 'FrauJulian';
|
||||||
|
public static readonly numberOfLoadedRepositories: number = 999;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<base href="/">
|
||||||
|
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
<title>Lechner Julian</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import {bootstrapApplication} from '@angular/platform-browser';
|
||||||
|
import {ApplicationRef} from '@angular/core';
|
||||||
|
|
||||||
|
import {AppComponent} from './app/app.component';
|
||||||
|
import {config} from './app/app.config.server';
|
||||||
|
|
||||||
|
const bootstrap: () => Promise<ApplicationRef> = (): Promise<ApplicationRef> => bootstrapApplication(AppComponent, config);
|
||||||
|
|
||||||
|
export default bootstrap;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import {bootstrapApplication} from '@angular/platform-browser';
|
||||||
|
|
||||||
|
import {appConfig} from './app/app.config';
|
||||||
|
import {AppComponent} from './app/app.component';
|
||||||
|
|
||||||
|
bootstrapApplication(AppComponent, appConfig)
|
||||||
|
.catch((err: Error): void => console.error(err.stack));
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import {APP_BASE_HREF} from '@angular/common';
|
||||||
|
import {CommonEngine, isMainModule} from '@angular/ssr/node';
|
||||||
|
import express, {Express, NextFunction, Request, Response} from 'express';
|
||||||
|
import {dirname, join, resolve} from 'node:path';
|
||||||
|
import {fileURLToPath} from 'node:url';
|
||||||
|
|
||||||
|
import bootstrap from './main.server';
|
||||||
|
import ProductionConfig from '../configs/Production.json';
|
||||||
|
|
||||||
|
const serverDistFolder: string = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const browserDistFolder: string = resolve(serverDistFolder, '../browser');
|
||||||
|
const indexHtml: string = join(serverDistFolder, 'index.server.html');
|
||||||
|
|
||||||
|
const app: Express = express();
|
||||||
|
const commonEngine: CommonEngine = new CommonEngine();
|
||||||
|
|
||||||
|
app.get(
|
||||||
|
'**',
|
||||||
|
express.static(browserDistFolder, {
|
||||||
|
maxAge: '1y',
|
||||||
|
index: 'index.html'
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
app.get('**', (req: Request, res: Response, next: NextFunction): void => {
|
||||||
|
const {protocol, originalUrl, baseUrl, headers} = req;
|
||||||
|
|
||||||
|
commonEngine
|
||||||
|
.render({
|
||||||
|
bootstrap,
|
||||||
|
documentFilePath: indexHtml,
|
||||||
|
url: `${protocol}://${headers.host}${originalUrl}`,
|
||||||
|
publicPath: browserDistFolder,
|
||||||
|
providers: [{provide: APP_BASE_HREF, useValue: baseUrl}],
|
||||||
|
})
|
||||||
|
.then((html: string): Response => res.send(html))
|
||||||
|
.catch((err: Error): void => next(err.stack));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isMainModule(import.meta.url)) {
|
||||||
|
const host: string = ProductionConfig.Server.Host;
|
||||||
|
const port: number = ProductionConfig.Server.Port;
|
||||||
|
app.listen(port, host, (): void => {
|
||||||
|
console.log(`✔️ Listening on http://${host}:${port}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default app;
|
||||||
@@ -0,0 +1,573 @@
|
|||||||
|
::-webkit-scrollbar {
|
||||||
|
width: var(--scroll-width);
|
||||||
|
height: var(--scroll-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--scroll-thumb-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: var(--scroll-track-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--main-padding: 15px;
|
||||||
|
--main-margin: 10px;
|
||||||
|
--main-img-size: 200px;
|
||||||
|
--main-bio-size: 200px;
|
||||||
|
--main-bio-margin: 5px;
|
||||||
|
--main-icon-width: 80px;
|
||||||
|
--main-border-radius: 5px;
|
||||||
|
--padding-big: 20px;
|
||||||
|
--padding-small: 5px;
|
||||||
|
--main-container-width: 750px;
|
||||||
|
--main-txt-color: White;
|
||||||
|
--main-shadow-color: #6F3E38;
|
||||||
|
--donation-modal-height: 200px;
|
||||||
|
--donation-modal-width: 600px;
|
||||||
|
--donation-modal-top: 50%;
|
||||||
|
--scroll-width: 6px;
|
||||||
|
--scroll-thumb-bg: Red;
|
||||||
|
--scroll-track-bg: transparent;
|
||||||
|
--background-image: url("../public/Background.png");
|
||||||
|
--blur-small: 25px;
|
||||||
|
--blur-large: 180px;
|
||||||
|
--shadow-y: 4px;
|
||||||
|
--shadow-blur: 8px;
|
||||||
|
--shadow-spread: 0;
|
||||||
|
--shadow-hover-y: 8px;
|
||||||
|
--shadow-hover-blur: 16px;
|
||||||
|
--font-size-large: 20px;
|
||||||
|
--width-medium: 60%;
|
||||||
|
--max-width-large: 90%;
|
||||||
|
--grid-column-width: 24%;
|
||||||
|
--portfolio-item-height: 128px;
|
||||||
|
--transition-duration-long: 0.5s;
|
||||||
|
--transition-duration-short: 0.3s;
|
||||||
|
--modal-card-height: 80%;
|
||||||
|
--modal-mini-card-height: 22%;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
font-family: 'Outfit', Arial, sans-serif !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a,
|
||||||
|
hr {
|
||||||
|
color: var(--main-txt-color);
|
||||||
|
text-decoration-line: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body,
|
||||||
|
html {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--main-txt-color);
|
||||||
|
text-shadow: 0 0 5px var(--main-shadow-color);
|
||||||
|
text-align: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
background-attachment: fixed;
|
||||||
|
background-image: var(--background-image);
|
||||||
|
background-position: center center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
padding-bottom: var(--main-padding);
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: var(--main-txt-color);
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
line-height-step: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
backdrop-filter: blur(var(--blur-large));
|
||||||
|
box-shadow: 0 var(--shadow-y) var(--shadow-blur) var(--shadow-spread) var(--main-shadow-color);
|
||||||
|
transition: var(--transition-duration-short);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li a {
|
||||||
|
display: block;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li a.active {
|
||||||
|
background-color: #2f3136;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li a:hover:not(.active) {
|
||||||
|
background-color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li.left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalClose {
|
||||||
|
float: right;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bio {
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bio:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#donate {
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#donate:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#donateModal {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#github_projects .card {
|
||||||
|
padding: var(--padding-big);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#github_projects .card a {
|
||||||
|
color: var(--main-txt-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#github_projects .card p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#github_projects .stargazers {
|
||||||
|
padding-right: var(--padding-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
#github_projects .stars {
|
||||||
|
color: var(--main-txt-color) !important;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#github_projects a {
|
||||||
|
text-transform: capitalize;
|
||||||
|
text-decoration-line: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#left-arrow {
|
||||||
|
position: relative;
|
||||||
|
-webkit-animation: linear infinite alternate;
|
||||||
|
-webkit-animation-name: runLeft;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#right-arrow {
|
||||||
|
position: relative;
|
||||||
|
-webkit-animation: linear infinite alternate;
|
||||||
|
-webkit-animation-name: runRight;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bio {
|
||||||
|
display: grid !important;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
padding: var(--main-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bio table .right {
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: var(--main-border-radius);
|
||||||
|
backdrop-filter: blur(150px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.long-bio-text {
|
||||||
|
font-size: var(--font-size-large);
|
||||||
|
width: var(--width-medium);
|
||||||
|
margin-bottom: var(--main-padding) !important;
|
||||||
|
margin: auto;
|
||||||
|
padding: var(--main-margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin-top: var(--main-padding);
|
||||||
|
box-shadow: 0 var(--shadow-y) var(--shadow-blur) var(--shadow-spread) var(--main-shadow-color);
|
||||||
|
transition: var(--transition-duration-short);
|
||||||
|
backdrop-filter: blur(var(--blur-small));
|
||||||
|
padding: var(--main-padding);
|
||||||
|
text-align: center;
|
||||||
|
color: var(--main-txt-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-projects {
|
||||||
|
display: grid;
|
||||||
|
box-shadow: 0 var(--shadow-y) var(--shadow-blur) var(--shadow-spread) var(--main-shadow-color);
|
||||||
|
transition: var(--transition-duration-short);
|
||||||
|
backdrop-filter: blur(var(--blur-large));
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-projects:hover {
|
||||||
|
box-shadow: 0 var(--shadow-hover-y) var(--shadow-hover-blur) var(--shadow-spread) var(--main-shadow-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
box-shadow: 0 var(--shadow-hover-y) var(--shadow-hover-blur) var(--shadow-spread) var(--main-shadow-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background: transparent;
|
||||||
|
backdrop-filter: blur(var(--blur-small));
|
||||||
|
margin: auto;
|
||||||
|
width: var(--main-container-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-modal img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-modal > .card {
|
||||||
|
overflow-y: auto;
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-card {
|
||||||
|
height: var(--modal-card-height) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-card {
|
||||||
|
height: var(--modal-mini-card-height) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-container {
|
||||||
|
margin: var(--main-margin);
|
||||||
|
display: grid;
|
||||||
|
justify-content: center;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item {
|
||||||
|
width: var(--main-bio-size);
|
||||||
|
margin-left: var(--main-padding);
|
||||||
|
backdrop-filter: blur(var(--blur-large));
|
||||||
|
border-radius: var(--main-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item h1,
|
||||||
|
.grid-item-start h1 {
|
||||||
|
margin: var(--main-bio-margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item-start {
|
||||||
|
grid-row-start: 1;
|
||||||
|
grid-row-end: 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-items {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto auto;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-items a:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-items,
|
||||||
|
.hover-items a {
|
||||||
|
color: var(--main-txt-color);
|
||||||
|
padding: var(--main-padding) var(--main-margin);
|
||||||
|
font-size: large;
|
||||||
|
margin: auto;
|
||||||
|
line-height: 1.5em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hoverable:hover {
|
||||||
|
backdrop-filter: blur(var(--blur-large));
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fab {
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
display: inline-block;
|
||||||
|
font-style: normal;
|
||||||
|
font-variant: normal;
|
||||||
|
line-height: 1;
|
||||||
|
text-rendering: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-area a {
|
||||||
|
color: var(--main-txt-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-area fa-icon {
|
||||||
|
justify-content: space-between;
|
||||||
|
width: var(--main-icon-width);
|
||||||
|
padding-top: var(--main-padding);
|
||||||
|
padding-bottom: var(--main-padding);
|
||||||
|
border-radius: var(--main-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-area fa-icon:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
backdrop-filter: blur(var(--blur-large));
|
||||||
|
}
|
||||||
|
|
||||||
|
.max60 {
|
||||||
|
max-width: var(--max-width-large);
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-body {
|
||||||
|
color: var(--main-txt-color) !important;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .card {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
height: var(--donation-modal-height);
|
||||||
|
width: var(--donation-modal-width);
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nomargin {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, 128px);
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-done {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, var(--grid-column-width));
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-done-item {
|
||||||
|
height: var(--portfolio-item-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile img {
|
||||||
|
margin: auto;
|
||||||
|
max-width: var(--main-img-size);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project img {
|
||||||
|
opacity: 1;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
transition: var(--transition-duration-long) ease;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
box-shadow: 0 var(--shadow-y) var(--shadow-blur) var(--shadow-spread) var(--main-shadow-color);
|
||||||
|
transition: var(--transition-duration-short);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project p {
|
||||||
|
transition: var(--transition-duration-long) ease;
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
-ms-transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project:hover img {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project:hover p {
|
||||||
|
opacity: 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refer-area {
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social {
|
||||||
|
border: 0;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social a {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
color: var(--main-txt-color) !important;
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes runLeft {
|
||||||
|
0% {
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
left: 70%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes runRight {
|
||||||
|
0% {
|
||||||
|
right: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
right: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
right: 70%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 1025px) {
|
||||||
|
.circle {
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
border-radius: 24px;
|
||||||
|
background-color: black;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 99999999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 700px) {
|
||||||
|
:root {
|
||||||
|
--donation-modal-height: 350px;
|
||||||
|
--donation-modal-width: 600px;
|
||||||
|
--donation-modal-top: 50%;
|
||||||
|
--mobile-margin: 5px;
|
||||||
|
--main-container-width: 95%;
|
||||||
|
--mobile-width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body,
|
||||||
|
html {
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
position: absolute;
|
||||||
|
margin: auto;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .card {
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 80%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 700px) {
|
||||||
|
footer {
|
||||||
|
padding-bottom: var(--main-padding);
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li,
|
||||||
|
ul.nav li.right {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li.left {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#left-arrow {
|
||||||
|
position: initial !important;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#right-arrow {
|
||||||
|
position: initial !important;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.long-bio-text {
|
||||||
|
width: 95% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-container {
|
||||||
|
grid-template-columns: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-area i {
|
||||||
|
margin-top: var(--mobile-margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
.max60 {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-done {
|
||||||
|
grid-template-columns: auto;
|
||||||
|
justify-content: initial;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-done-item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.short_desc {
|
||||||
|
width: var(--mobile-width);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||||
|
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/app",
|
||||||
|
"types": [
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/main.ts",
|
||||||
|
"src/main.server.ts",
|
||||||
|
"src/server.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||||
|
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"importHelpers": true,
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ES2022"
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"enableI18nLegacyMessageIdFormat": false,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"strictInputAccessModifiers": true,
|
||||||
|
"strictTemplates": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||||
|
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||