Compare commits

..

No commits in common. "695746a507ef1da969428bb19e6918fad54651d4" and "be8b18a31bf53d4219821f84a007832256985f80" have entirely different histories.

43 changed files with 1 additions and 29173 deletions

View File

@ -1,107 +0,0 @@
kind: pipeline
type: docker
name: analyseAndBuild
steps:
- name: code-analysis
image: sonarsource/sonar-scanner-cli
detach: true
failure: ignore
commands:
- sonar-scanner -Dsonar.projectKey=cv -Dsonar.sources=. -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN
environment:
SONAR_HOST_URL:
from_secret: sonarScannerHostUrl
SONAR_LOGIN:
from_secret: sonarScannerLogin
- name: lintAndBuild
image: node:14
commands:
- npm install
- npm run lint
- npm run build:prod
environment:
VUE_APP_API_BASE_URL:
from_secret: baseurl
- name: saveNodeModules
image: drillster/drone-volume-cache
volumes:
- name: cache
path: /cache
settings:
rebuild: true
mount:
- ./node_modules
cache_key: [ DRONE_REPO_NAME, DRONE_BRANCH ]
trigger:
event:
- push
- pull_request
volumes:
- name: cache
host:
path: /tmp/cache
---
kind: pipeline
type: docker
name: Deploy
steps:
- name: getNodeModules
image: drillster/drone-volume-cache
volumes:
- name: cache
path: /cache
settings:
restore: true
mount:
- ./node_modules
cache_key: [ DRONE_REPO_NAME, DRONE_BRANCH ]
- name: build
image: node:14
commands:
- npm run build:prod
environment:
VUE_APP_API_BASE_URL:
from_secret: baseurl
- name: scpFiles
image: appleboy/drone-scp
settings:
host: amine-louveau.fr
username: ubuntu
key:
from_secret: privateKey
port: 22
target: /home/ubuntu/courses
source: dist/*
- name: deploy
image: appleboy/drone-ssh
settings:
host: amine-louveau.fr
user: ubuntu
key:
from_secret: privateKey
command_timeout: 2m
script:
- cd /home/ubuntu/courses
- mv dist/* ./
- sudo chown www-data:www-data ./*
- sudo rm -rf /var/www/amine/courses/*
- sudo mv ./* /var/www/amine/courses/
trigger:
event:
- promote
target:
- production
volumes:
- name: cache
host:
path: /tmp/cache

23
.gitignore vendored
View File

@ -1,23 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

5
.idea/.gitignore vendored
View File

@ -1,5 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectDictionaryState">
<dictionary name="amine" />
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

View File

@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/cv.iml" filepath="$PROJECT_DIR$/.idea/cv.iml" />
</modules>
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectTasksOptions" suppressed-tasks="Sass;SCSS" />
</project>

View File

@ -1,6 +0,0 @@
projectKey=cv
serverUrl=http://18.0.0.7:9000
serverVersion=9.6.0.59041
dashboardUrl=http://18.0.0.7:9000/dashboard?id=cv
ceTaskId=AYOJWrb2HpE7RRVya8HT
ceTaskUrl=http://18.0.0.7:9000/api/ce/task?id=AYOJWrb2HpE7RRVya8HT

View File

@ -1,3 +1,3 @@
# cv
A CV template, inspired by https://techrez.io/resume/andrew-lu
A CV template, inspired by https://techrez.io/resume/andrew-lu

28477
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +0,0 @@
{
"name": "cv",
"version": "0.1.0",
"private": true,
"dependencies": {
"@headlessui/react": "^1.7.2",
"@heroicons/react": "^2.0.11",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/lodash": "^4.14.186",
"@types/node": "^16.11.62",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.8.4",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.7",
"autoprefixer": "^10.4.12",
"postcss": "^8.4.16",
"sass": "^1.55.0",
"tailwindcss": "^3.1.8"
}
}

View File

@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -1,27 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -1,25 +0,0 @@
.card {
@apply container p-3 bg-gray-200 rounded-md mt-8 mb-8 drop-shadow;
}
.icon {
@apply w-5 inline-block mr-2;
}
.tag {
@apply mb-2 rounded-full p-3 pt-1 pb-1 text-white shadow mr-1 prose prose-sm;
}
.details {
& > * {
padding: 20px 0;
}
& > *:first-child {
padding-top: 0;
}
& > *:last-child {
padding-bottom: 0;
}
}

View File

@ -1,71 +0,0 @@
import React, {useEffect} from 'react';
import Header from './Components/Header';
import './Assets/scss/CV.scss'
import Jobs from './Components/Jobs';
import Education from './Components/Education';
import SideProjects from './Components/SideProjects';
import Languages from './Components/Languages';
import Interests from './Components/Interests';
import Skills from './Components/Skills';
import {Tag, TagCategory} from './Model/tag';
import {Lang} from './Model/lang';
import {EducationYear} from './Model/education';
import {SideProjectCats} from './Model/side-project';
import {JobAtCompany} from './Model/job-at-company';
import {Interest} from './Model/interests';
import {Profile} from './Model/profile';
function CV() {
const tags: Tag[] = []
const langs: Lang[] = []
const ed: EducationYear[] = []
const projs: SideProjectCats[] = []
const jobs: JobAtCompany[] = []
const interests: Interest[] = []
const profile: Profile = {
"name": "",
"title": "",
"quote": "",
"picture": ""
}
document.title = profile.name;
useEffect(() => {
let link = document.querySelector("link[rel~='icon']");
if (!link) {
link = document.createElement('link');
// @ts-ignore
link.rel = 'icon';
document.getElementsByTagName('head')[0].appendChild(link);
}
// @ts-ignore
link.href = profile.picture
}, []);
return (
<div className="CV">
<Header tags={tags} profile={profile}/>
<div className="card flex divide-x divide-gray-600">
<div className="basis-3/4 pr-2 divide-y divide-gray-400 details">
<Jobs jobs={jobs}/>
<Education education={ed}/>
<SideProjects projs={projs}/>
</div>
<div className="basis-1/4 pl-2 divide-y divide-gray-400 details">
<Skills tags={tags}/>
<Languages langs={langs}/>
<Interests interests={interests}/>
</div>
</div>
</div>
);
}
export default CV;

View File

@ -1,17 +0,0 @@
import React, {ComponentProps} from 'react';
import {AcademicCapIcon, BriefcaseIcon} from '@heroicons/react/24/outline';
import {EducationYear} from '../Model/education';
function Education(props: ComponentProps<any>) {
return (<div className="prose max-w-none">
<h3><AcademicCapIcon className="icon"/> Formations</h3>
{props.education.map((e: EducationYear) => <div key={e.endDate} className="mb-5">
<div className="flex justify-between w-full"><h4 className="m-0">{e.school}</h4>
<div>{e.endDate}</div>
</div>
<div>{e.name}</div>
</div>)}
</div>);
}
export default Education;

View File

@ -1,43 +0,0 @@
import React, {ComponentProps} from 'react';
import {CodeBracketIcon, EnvelopeIcon, PhoneIcon, UserPlusIcon} from '@heroicons/react/24/outline';
import {getTagColor, Tag} from '../Model/tag';
import {Profile} from '../Model/profile';
function Header(props: ComponentProps<any>) {
const tags = props.tags.filter((t: Tag) => t.workThing)
const profile: Profile = props.profile
return (<div
className="card flex flex-wrap-reverse">
<div className="basis-1/4">
<img className="w-60 rounded-full shadow-lg lg:divide-x divide-gray-600" src={profile.picture}
/>
</div>
<div className="basis-2/4 prose p-3 prose-sm grow">
<h1>{profile.name}</h1>
<h2>{profile.title}</h2>
<blockquote>{profile.quote}</blockquote>
<div className="prose flex flex-wrap justify-between"> {/* Tags */}
{tags.map((t: Tag) => <button key={t.name} className={"tag " + getTagColor(t)}>{t.name}</button>)}
</div>
</div>
<div className="basis-1/4 lg:divide-y divide-gray-400 prose p-3 grow">
<div className="text-center lg:text-left">
<h3 className="mt-2 mb-1">Me contacter</h3>
<div><EnvelopeIcon className="icon"/><a className="" href={"mailto:" + profile.email}>Par
mail</a></div>
<div><PhoneIcon className="icon"/><a className="" href={"tel:" + profile.phone}>Par
téléphone</a></div>
<h3 className="mt-2 mb-1">Me connaitre</h3>
<div><UserPlusIcon className="icon"/><a className=""
href={profile.linkedin}
target="_blank">Mon linkedin</a></div>
<div><CodeBracketIcon className="icon"/><a className=""
href={profile.source} target="_blank">Mon
code</a></div>
</div>
</div>
</div>);
}
export default Header;

View File

@ -1,14 +0,0 @@
import React, {ComponentProps} from 'react';
import {CalendarDaysIcon, FaceSmileIcon, LanguageIcon} from '@heroicons/react/24/outline';
import {Interest} from '../Model/interests';
function Interests(props: ComponentProps<any>) {
return (<div className="prose">
<h3><FaceSmileIcon className="icon"/> Centre d'intérets</h3>
<ul>
{props.interests.map((i: Interest) => <li key={i.theme}><strong>{i.theme}</strong> : {i.description}</li>)}
</ul>
</div>);
}
export default Interests;

View File

@ -1,16 +0,0 @@
import React, {ComponentProps} from 'react';
import {BriefcaseIcon} from '@heroicons/react/24/outline';
function Job(props: ComponentProps<any>) {
return (<div className="mb-5">
<div className="flex justify-between w-full"><h4 className="m-0">{props.jobTitle}</h4>
<div>{props.start} - {props.end}</div>
</div>
<h5>{props.company}</h5>
<ul>
{props.tasks.map((task: string) => <li key={task}>{task}</li>)}
</ul>
</div>);
}
export default Job;

View File

@ -1,14 +0,0 @@
import React, {ComponentProps} from 'react';
import {BriefcaseIcon} from '@heroicons/react/24/outline';
import Job from './Job';
import {JobAtCompany} from '../Model/job-at-company';
function Jobs(props: ComponentProps<any>) {
return (<div className="prose max-w-none">
<h3><BriefcaseIcon className="icon"/> Expériences professionnelles</h3>
{props.jobs.map((j: JobAtCompany) => <Job jobTitle={j.jobTitle} start={j.start} end={j.end} company={j.company} tasks={j.tasks} key={j.start}></Job>)}
</div>);
}
export default Jobs;

View File

@ -1,14 +0,0 @@
import React, {ComponentProps} from 'react';
import {CalendarDaysIcon, LanguageIcon} from '@heroicons/react/24/outline';
import {Lang} from '../Model/lang';
function Languages(props: ComponentProps<any>) {
return (<div className="prose">
<h3><LanguageIcon className="icon"/> Langues</h3>
<ul>
{props.langs.map((l: Lang) => <li key={l.lang}>{l.lang} : {l.level}</li>)}
</ul>
</div>);
}
export default Languages;

View File

@ -1,23 +0,0 @@
import React, {ComponentProps} from 'react';
import {BeakerIcon} from '@heroicons/react/24/outline';
import {SideProjectCats} from '../Model/side-project';
function SideProjects(props: ComponentProps<any>) {
return (<div className="prose">
<h3><BeakerIcon className="icon"/> Projets personnels</h3>
{props.projs.map((proj: SideProjectCats) => {
return (<div key={proj.category}>
<h4>{proj.category}</h4>
<ul>
{proj.projects.map(p => {
return (<li key={p.description}>
{p.title ? <div><a href={p.url}>{p.title}</a> {p.description}</div> : <div>{p.description}</div>}
</li>)
})}
</ul>
</div>)
})}
</div>);
}
export default SideProjects;

View File

@ -1,23 +0,0 @@
import React, {ComponentProps} from 'react';
import {CalendarDaysIcon, CheckBadgeIcon, LanguageIcon} from '@heroicons/react/24/outline';
import {getTagColor, Tag, TagCategory} from '../Model/tag';
import {forIn, groupBy, map} from 'lodash';
function Skills(props: ComponentProps<any>) {
const tagsByCat = groupBy(props.tags, 'category')
return (<div className="prose">
<h3><CheckBadgeIcon className="icon"/> Compétences</h3>
<div className="flex flex-wrap justify-between">
{map(tagsByCat, (tags, cat) => {
return (<div key={cat}>
<h4 className="m-0 mb-1.5">{cat}</h4>
<div>
{tags.map((t: Tag) => <button key={t.name} className={"tag " + getTagColor(t)}>{t.name}</button>)}
</div>
</div>)
})}
</div>
</div>);
}
export default Skills;

View File

@ -1,5 +0,0 @@
export class EducationYear {
endDate!: string
school!: string
name!: string
}

View File

@ -1,4 +0,0 @@
export class Interest {
theme!: string
description!: string
}

View File

@ -1,7 +0,0 @@
export class JobAtCompany {
jobTitle!: string
start!: string
end!: string
company!: string
tasks!: string[]
}

View File

@ -1,4 +0,0 @@
export class Lang {
lang!: string
level!: string
}

View File

@ -1,10 +0,0 @@
export class Profile {
name!: string
title!: string
quote!: string
picture!: string
email?: string
phone?: string
linkedin?: string
source?: string
}

View File

@ -1,10 +0,0 @@
export class SideProject {
title?: string
url?: string
description!: string
}
export class SideProjectCats {
category!: string
projects!: SideProject[];
}

View File

@ -1,29 +0,0 @@
export function getTagColor(t: Tag) {
switch (t.category) {
case TagCategory.FRONT:
return "bg-rose-500"
case TagCategory.BACK:
return "bg-indigo-600"
case TagCategory.MOBILE:
return "bg-yellow-500"
case TagCategory.DB:
return "bg-emerald-500"
case TagCategory.OTHER:
return "bg-stone-300"
}
};
export enum TagCategory {
FRONT = 'Developpement Front',
BACK = 'Developpement Back',
MOBILE = 'Developpement Mobile',
DB = 'Bases de données',
OTHER = 'Autre'
}
export class Tag {
name: string = ""
workThing: Boolean = true
category!: TagCategory
}

View File

@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -1,19 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import CV from './CV';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<CV />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

View File

@ -1 +0,0 @@
/// <reference types="react-scripts" />

View File

@ -1,15 +0,0 @@
import { ReportHandler } from 'web-vitals';
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

View File

@ -1,5 +0,0 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

View File

@ -1,20 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
container: {
center: true,
},
screens: {
sm: '640px',
md: '768px',
lg: '1024px'
},
},
plugins: [
require('@tailwindcss/typography')
],
}

View File

@ -1,26 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}