From aa325d54517f317e6dfd1d070d95a3c66ab9e000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedek=20L=C3=A1szl=C3=B3?= Date: Mon, 8 Apr 2024 17:29:36 +0200 Subject: [PATCH] basic auth + feed layout --- README.md | 31 +- src/app/app-routing.module.ts | 15 + src/app/app.component.html | 337 +----------------- src/app/app.config.ts | 2 +- src/app/app.module.ts | 14 + src/app/app.routes.ts | 3 - src/app/auth/auth-routing.module.ts | 16 + src/app/auth/auth.component.html | 1 + src/app/auth/auth.component.scss | 24 ++ src/app/auth/auth.component.spec.ts | 23 ++ src/app/auth/auth.component.ts | 10 + src/app/auth/auth.module.ts | 23 ++ src/app/auth/login/login.component.html | 28 ++ src/app/auth/login/login.component.scss | 0 src/app/auth/login/login.component.spec.ts | 23 ++ src/app/auth/login/login.component.ts | 24 ++ src/app/auth/register/register.component.html | 37 ++ src/app/auth/register/register.component.scss | 0 .../auth/register/register.component.spec.ts | 23 ++ src/app/auth/register/register.component.ts | 23 ++ src/app/feed/feed-routing.module.ts | 11 + src/app/feed/feed.component.html | 10 + src/app/feed/feed.component.scss | 0 src/app/feed/feed.component.spec.ts | 23 ++ src/app/feed/feed.component.ts | 10 + src/app/feed/feed.module.ts | 22 ++ .../shared/side-menu/side-menu.component.html | 5 + .../shared/side-menu/side-menu.component.scss | 26 ++ .../side-menu/side-menu.component.spec.ts | 23 ++ .../shared/side-menu/side-menu.component.ts | 13 + .../shared/top-menu/top-menu.component.html | 5 + .../shared/top-menu/top-menu.component.scss | 21 ++ .../top-menu/top-menu.component.spec.ts | 23 ++ src/app/shared/top-menu/top-menu.component.ts | 12 + src/app/shared/views/post/post.component.html | 5 + src/app/shared/views/post/post.component.scss | 16 + .../shared/views/post/post.component.spec.ts | 23 ++ src/app/shared/views/post/post.component.ts | 14 + .../small-user/small-user.component.html | 3 + .../small-user/small-user.component.scss | 21 ++ .../small-user/small-user.component.spec.ts | 23 ++ .../views/small-user/small-user.component.ts | 12 + src/app/user/user-routing.module.ts | 11 + src/app/user/user.component.html | 1 + src/app/user/user.component.scss | 0 src/app/user/user.component.spec.ts | 23 ++ src/app/user/user.component.ts | 10 + src/app/user/user.module.ts | 17 + src/assets/placeholder-profile-picture.png | Bin 0 -> 11377 bytes src/styles.scss | 30 ++ 50 files changed, 703 insertions(+), 367 deletions(-) create mode 100644 src/app/app-routing.module.ts create mode 100644 src/app/app.module.ts delete mode 100644 src/app/app.routes.ts create mode 100644 src/app/auth/auth-routing.module.ts create mode 100644 src/app/auth/auth.component.html create mode 100644 src/app/auth/auth.component.scss create mode 100644 src/app/auth/auth.component.spec.ts create mode 100644 src/app/auth/auth.component.ts create mode 100644 src/app/auth/auth.module.ts create mode 100644 src/app/auth/login/login.component.html create mode 100644 src/app/auth/login/login.component.scss create mode 100644 src/app/auth/login/login.component.spec.ts create mode 100644 src/app/auth/login/login.component.ts create mode 100644 src/app/auth/register/register.component.html create mode 100644 src/app/auth/register/register.component.scss create mode 100644 src/app/auth/register/register.component.spec.ts create mode 100644 src/app/auth/register/register.component.ts create mode 100644 src/app/feed/feed-routing.module.ts create mode 100644 src/app/feed/feed.component.html create mode 100644 src/app/feed/feed.component.scss create mode 100644 src/app/feed/feed.component.spec.ts create mode 100644 src/app/feed/feed.component.ts create mode 100644 src/app/feed/feed.module.ts create mode 100644 src/app/shared/side-menu/side-menu.component.html create mode 100644 src/app/shared/side-menu/side-menu.component.scss create mode 100644 src/app/shared/side-menu/side-menu.component.spec.ts create mode 100644 src/app/shared/side-menu/side-menu.component.ts create mode 100644 src/app/shared/top-menu/top-menu.component.html create mode 100644 src/app/shared/top-menu/top-menu.component.scss create mode 100644 src/app/shared/top-menu/top-menu.component.spec.ts create mode 100644 src/app/shared/top-menu/top-menu.component.ts create mode 100644 src/app/shared/views/post/post.component.html create mode 100644 src/app/shared/views/post/post.component.scss create mode 100644 src/app/shared/views/post/post.component.spec.ts create mode 100644 src/app/shared/views/post/post.component.ts create mode 100644 src/app/shared/views/small-user/small-user.component.html create mode 100644 src/app/shared/views/small-user/small-user.component.scss create mode 100644 src/app/shared/views/small-user/small-user.component.spec.ts create mode 100644 src/app/shared/views/small-user/small-user.component.ts create mode 100644 src/app/user/user-routing.module.ts create mode 100644 src/app/user/user.component.html create mode 100644 src/app/user/user.component.scss create mode 100644 src/app/user/user.component.spec.ts create mode 100644 src/app/user/user.component.ts create mode 100644 src/app/user/user.module.ts create mode 100644 src/assets/placeholder-profile-picture.png diff --git a/README.md b/README.md index 796e308..f0dc0f8 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,4 @@ -# Quack - -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.3. - -## Development server - -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. - -## Code scaffolding - -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. - -## Build - -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. - -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Running end-to-end tests - -Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +- `ng new && cd ` +- `ng g module app --routing --flat` +- `rm app.routes.ts`, `import { routes } from './app-routing.module';` > *app.config.ts* +- `ng g moudle --route= --module=app` \ No newline at end of file diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts new file mode 100644 index 0000000..651b7b3 --- /dev/null +++ b/src/app/app-routing.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +export const routes: Routes = [ + { path: 'auth', loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule) }, + { path: 'feed', loadChildren: () => import('./feed/feed.module').then(m => m.FeedModule) }, + { path: 'user', loadChildren: () => import('./user/user.module').then(m => m.UserModule) }, + { path: '', redirectTo: 'feed', pathMatch: 'full'} +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/src/app/app.component.html b/src/app/app.component.html index 36093e1..12b5d24 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,336 +1 @@ - - - - - - - - - - - -
-
-
- -

Hello, {{ title }}

-

Congratulations! Your app is running. 🎉

-
- -
-
- @for (item of [ - { title: 'Explore the Docs', link: 'https://angular.dev' }, - { title: 'Learn with Tutorials', link: 'https://angular.dev/tutorials' }, - { title: 'CLI Docs', link: 'https://angular.dev/tools/cli' }, - { title: 'Angular Language Service', link: 'https://angular.dev/tools/language-service' }, - { title: 'Angular DevTools', link: 'https://angular.dev/tools/devtools' }, - ]; track item.title) { - - {{ item.title }} - - - - - } -
- -
-
-
- - - - - - - - - - - + \ No newline at end of file diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 6c6ef60..d273453 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,7 +1,7 @@ import { ApplicationConfig } from '@angular/core'; import { provideRouter } from '@angular/router'; -import { routes } from './app.routes'; +import { routes } from './app-routing.module'; export const appConfig: ApplicationConfig = { providers: [provideRouter(routes)] diff --git a/src/app/app.module.ts b/src/app/app.module.ts new file mode 100644 index 0000000..4a53d5a --- /dev/null +++ b/src/app/app.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { AppRoutingModule } from './app-routing.module'; + + +@NgModule({ + declarations: [], + imports: [ + CommonModule, + AppRoutingModule + ] +}) +export class AppModule { } diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts deleted file mode 100644 index dc39edb..0000000 --- a/src/app/app.routes.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Routes } from '@angular/router'; - -export const routes: Routes = []; diff --git a/src/app/auth/auth-routing.module.ts b/src/app/auth/auth-routing.module.ts new file mode 100644 index 0000000..a2bd1c3 --- /dev/null +++ b/src/app/auth/auth-routing.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { LoginComponent } from './login/login.component'; +import { RegisterComponent } from './register/register.component'; + +const routes: Routes = [ + { path: 'login', component: LoginComponent}, + { path: 'register', component: RegisterComponent}, + { path: '', redirectTo: 'login', pathMatch: 'full'} +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AuthRoutingModule { } diff --git a/src/app/auth/auth.component.html b/src/app/auth/auth.component.html new file mode 100644 index 0000000..f66eb69 --- /dev/null +++ b/src/app/auth/auth.component.html @@ -0,0 +1 @@ +

auth works!

diff --git a/src/app/auth/auth.component.scss b/src/app/auth/auth.component.scss new file mode 100644 index 0000000..62d7372 --- /dev/null +++ b/src/app/auth/auth.component.scss @@ -0,0 +1,24 @@ +form { + padding: 10px; + margin-top: 40px; +} + +label { + display: inline-block; +} + +input { + float: right; +} + +button { + width: 50%; + border: none; + background: none; + transition: background-color 0.3s; +} + +button:hover { + background-color: var(--highlight-color); + cursor: pointer; +} \ No newline at end of file diff --git a/src/app/auth/auth.component.spec.ts b/src/app/auth/auth.component.spec.ts new file mode 100644 index 0000000..973f2cf --- /dev/null +++ b/src/app/auth/auth.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AuthComponent } from './auth.component'; + +describe('AuthComponent', () => { + let component: AuthComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AuthComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(AuthComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/auth/auth.component.ts b/src/app/auth/auth.component.ts new file mode 100644 index 0000000..985768d --- /dev/null +++ b/src/app/auth/auth.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-auth', + templateUrl: './auth.component.html', + styleUrl: './auth.component.scss' +}) +export class AuthComponent { + +} diff --git a/src/app/auth/auth.module.ts b/src/app/auth/auth.module.ts new file mode 100644 index 0000000..2d70754 --- /dev/null +++ b/src/app/auth/auth.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { AuthRoutingModule } from './auth-routing.module'; +import { AuthComponent } from './auth.component'; +import { ReactiveFormsModule } from '@angular/forms'; +import { LoginComponent } from './login/login.component'; +import { RegisterComponent } from './register/register.component'; + + +@NgModule({ + declarations: [ + AuthComponent, + LoginComponent, + RegisterComponent + ], + imports: [ + CommonModule, + AuthRoutingModule, + ReactiveFormsModule + ] +}) +export class AuthModule { } diff --git a/src/app/auth/login/login.component.html b/src/app/auth/login/login.component.html new file mode 100644 index 0000000..7aa3031 --- /dev/null +++ b/src/app/auth/login/login.component.html @@ -0,0 +1,28 @@ +
+
+ + + + + + + + + + + + +
+ + + +
+ + + +
+ + +
+
+
diff --git a/src/app/auth/login/login.component.scss b/src/app/auth/login/login.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/auth/login/login.component.spec.ts b/src/app/auth/login/login.component.spec.ts new file mode 100644 index 0000000..1e19e5d --- /dev/null +++ b/src/app/auth/login/login.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoginComponent } from './login.component'; + +describe('LoginComponent', () => { + let component: LoginComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [LoginComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/auth/login/login.component.ts b/src/app/auth/login/login.component.ts new file mode 100644 index 0000000..55c3ad7 --- /dev/null +++ b/src/app/auth/login/login.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.scss', '../auth.component.scss'] +}) +export class LoginComponent { + loginForm = new FormGroup({ + username: new FormControl(''), + password: new FormControl('') + }); + + constructor(private router: Router) { + this.loginForm.addValidators([Validators.required]); + } + + login() { + if (this.loginForm.valid) this.router.navigateByUrl("/feed"); + else alert("missing username or password"); + } +} diff --git a/src/app/auth/register/register.component.html b/src/app/auth/register/register.component.html new file mode 100644 index 0000000..002064d --- /dev/null +++ b/src/app/auth/register/register.component.html @@ -0,0 +1,37 @@ +
+
+ + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + +
+
+
+ diff --git a/src/app/auth/register/register.component.scss b/src/app/auth/register/register.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/auth/register/register.component.spec.ts b/src/app/auth/register/register.component.spec.ts new file mode 100644 index 0000000..3a5dfc8 --- /dev/null +++ b/src/app/auth/register/register.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RegisterComponent } from './register.component'; + +describe('RegisterComponent', () => { + let component: RegisterComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RegisterComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(RegisterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/auth/register/register.component.ts b/src/app/auth/register/register.component.ts new file mode 100644 index 0000000..dd8a270 --- /dev/null +++ b/src/app/auth/register/register.component.ts @@ -0,0 +1,23 @@ +import { Component } from '@angular/core'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; + +@Component({ + selector: 'app-register', + templateUrl: './register.component.html', + styleUrls: ['./register.component.scss', '../auth.component.scss'] +}) +export class RegisterComponent { + registerForm = new FormGroup({ + username: new FormControl(''), + password: new FormControl(''), + rePassword: new FormControl('') + }); + + constructor() { + this.registerForm.addValidators([Validators.required, Validators.minLength(3)]); + } + + register() { + if (!this.registerForm.valid) alert("failed to register"); + } +} diff --git a/src/app/feed/feed-routing.module.ts b/src/app/feed/feed-routing.module.ts new file mode 100644 index 0000000..45e2581 --- /dev/null +++ b/src/app/feed/feed-routing.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { FeedComponent } from './feed.component'; + +const routes: Routes = [{ path: '', component: FeedComponent }]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class FeedRoutingModule { } diff --git a/src/app/feed/feed.component.html b/src/app/feed/feed.component.html new file mode 100644 index 0000000..910ede2 --- /dev/null +++ b/src/app/feed/feed.component.html @@ -0,0 +1,10 @@ + + +
+ + + + + + +
diff --git a/src/app/feed/feed.component.scss b/src/app/feed/feed.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/feed/feed.component.spec.ts b/src/app/feed/feed.component.spec.ts new file mode 100644 index 0000000..f553cb2 --- /dev/null +++ b/src/app/feed/feed.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FeedComponent } from './feed.component'; + +describe('FeedComponent', () => { + let component: FeedComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [FeedComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(FeedComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/feed/feed.component.ts b/src/app/feed/feed.component.ts new file mode 100644 index 0000000..3e8ee0c --- /dev/null +++ b/src/app/feed/feed.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-feed', + templateUrl: './feed.component.html', + styleUrl: './feed.component.scss' +}) +export class FeedComponent { + +} diff --git a/src/app/feed/feed.module.ts b/src/app/feed/feed.module.ts new file mode 100644 index 0000000..7dec5d2 --- /dev/null +++ b/src/app/feed/feed.module.ts @@ -0,0 +1,22 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { FeedRoutingModule } from './feed-routing.module'; +import { FeedComponent } from './feed.component'; +import { TopMenuComponent } from '../shared/top-menu/top-menu.component'; +import { SideMenuComponent } from '../shared/side-menu/side-menu.component'; +import { PostComponent } from '../shared/views/post/post.component'; + +@NgModule({ + declarations: [ + FeedComponent + ], + imports: [ + CommonModule, + FeedRoutingModule, + TopMenuComponent, + SideMenuComponent, + PostComponent + ] +}) +export class FeedModule { } diff --git a/src/app/shared/side-menu/side-menu.component.html b/src/app/shared/side-menu/side-menu.component.html new file mode 100644 index 0000000..a251418 --- /dev/null +++ b/src/app/shared/side-menu/side-menu.component.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/app/shared/side-menu/side-menu.component.scss b/src/app/shared/side-menu/side-menu.component.scss new file mode 100644 index 0000000..c60e7bd --- /dev/null +++ b/src/app/shared/side-menu/side-menu.component.scss @@ -0,0 +1,26 @@ +.side-menu { + display: block; + position: fixed; + width: 100px; + height: 100vh; + margin: 0; + padding: 0; + + background-color: rgb(163, 163, 163); + + button { + display: block; + background: none; + border: none; + + padding: 10px; + + transition: background-color 1s; + width: 100%; + + } + + button:hover { + background-color: var(--highlight-color); + } +} \ No newline at end of file diff --git a/src/app/shared/side-menu/side-menu.component.spec.ts b/src/app/shared/side-menu/side-menu.component.spec.ts new file mode 100644 index 0000000..69742e1 --- /dev/null +++ b/src/app/shared/side-menu/side-menu.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SideMenuComponent } from './side-menu.component'; + +describe('SideMenuComponent', () => { + let component: SideMenuComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SideMenuComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SideMenuComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/side-menu/side-menu.component.ts b/src/app/shared/side-menu/side-menu.component.ts new file mode 100644 index 0000000..95aec5a --- /dev/null +++ b/src/app/shared/side-menu/side-menu.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +@Component({ + selector: 'app-side-menu', + standalone: true, + imports: [RouterModule], + templateUrl: './side-menu.component.html', + styleUrl: './side-menu.component.scss' +}) +export class SideMenuComponent { + +} diff --git a/src/app/shared/top-menu/top-menu.component.html b/src/app/shared/top-menu/top-menu.component.html new file mode 100644 index 0000000..82b68b6 --- /dev/null +++ b/src/app/shared/top-menu/top-menu.component.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/app/shared/top-menu/top-menu.component.scss b/src/app/shared/top-menu/top-menu.component.scss new file mode 100644 index 0000000..48a7f23 --- /dev/null +++ b/src/app/shared/top-menu/top-menu.component.scss @@ -0,0 +1,21 @@ +.logo::before { + content: 'Quack'; +} + +menu { + margin: 0; + padding: 10px; + display: flex; + align-items: center; + + background: var(--highlight-color); +} + +#search-container { + margin: auto; +} + +#search-container input { + display: inline-block; + width: 300px; +} \ No newline at end of file diff --git a/src/app/shared/top-menu/top-menu.component.spec.ts b/src/app/shared/top-menu/top-menu.component.spec.ts new file mode 100644 index 0000000..d10414c --- /dev/null +++ b/src/app/shared/top-menu/top-menu.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TopMenuComponent } from './top-menu.component'; + +describe('TopMenuComponent', () => { + let component: TopMenuComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TopMenuComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TopMenuComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/top-menu/top-menu.component.ts b/src/app/shared/top-menu/top-menu.component.ts new file mode 100644 index 0000000..835c980 --- /dev/null +++ b/src/app/shared/top-menu/top-menu.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-top-menu', + standalone: true, + imports: [], + templateUrl: './top-menu.component.html', + styleUrl: './top-menu.component.scss' +}) +export class TopMenuComponent { + +} diff --git a/src/app/shared/views/post/post.component.html b/src/app/shared/views/post/post.component.html new file mode 100644 index 0000000..de128a1 --- /dev/null +++ b/src/app/shared/views/post/post.component.html @@ -0,0 +1,5 @@ +
+ +
Post content blblblblblblbllblb
+ +
\ No newline at end of file diff --git a/src/app/shared/views/post/post.component.scss b/src/app/shared/views/post/post.component.scss new file mode 100644 index 0000000..f937d42 --- /dev/null +++ b/src/app/shared/views/post/post.component.scss @@ -0,0 +1,16 @@ +.post-container { + width: max(50%, 250px); + margin: 10px auto; + + div { + padding: 0 10px; + } + + img { + width: 90%; + margin: 10px auto; + display: block; + border-radius: 4px; + } +} + diff --git a/src/app/shared/views/post/post.component.spec.ts b/src/app/shared/views/post/post.component.spec.ts new file mode 100644 index 0000000..7808ae8 --- /dev/null +++ b/src/app/shared/views/post/post.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PostComponent } from './post.component'; + +describe('PostComponent', () => { + let component: PostComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [PostComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(PostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/views/post/post.component.ts b/src/app/shared/views/post/post.component.ts new file mode 100644 index 0000000..78a6046 --- /dev/null +++ b/src/app/shared/views/post/post.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; + +import { SmallUserComponent } from '../small-user/small-user.component'; + +@Component({ + selector: 'app-post', + standalone: true, + imports: [SmallUserComponent], + templateUrl: './post.component.html', + styleUrl: './post.component.scss' +}) +export class PostComponent { + +} diff --git a/src/app/shared/views/small-user/small-user.component.html b/src/app/shared/views/small-user/small-user.component.html new file mode 100644 index 0000000..f340219 --- /dev/null +++ b/src/app/shared/views/small-user/small-user.component.html @@ -0,0 +1,3 @@ +
+ Username +
\ No newline at end of file diff --git a/src/app/shared/views/small-user/small-user.component.scss b/src/app/shared/views/small-user/small-user.component.scss new file mode 100644 index 0000000..072df0e --- /dev/null +++ b/src/app/shared/views/small-user/small-user.component.scss @@ -0,0 +1,21 @@ +div { + width: 100%; + padding: 10px; +} + +img { + display: inline-block; + width: 50px; + border-radius: 50%; + aspect-ratio: 1; +} + +span { + display: inline-block; + padding-left: 10px; + transform: translateY(-60%); +} + +span::before { + content: '@'; +} \ No newline at end of file diff --git a/src/app/shared/views/small-user/small-user.component.spec.ts b/src/app/shared/views/small-user/small-user.component.spec.ts new file mode 100644 index 0000000..d2a4293 --- /dev/null +++ b/src/app/shared/views/small-user/small-user.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SmallUserComponent } from './small-user.component'; + +describe('SmallUserComponent', () => { + let component: SmallUserComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SmallUserComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SmallUserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/views/small-user/small-user.component.ts b/src/app/shared/views/small-user/small-user.component.ts new file mode 100644 index 0000000..8c262cc --- /dev/null +++ b/src/app/shared/views/small-user/small-user.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-small-user', + standalone: true, + imports: [], + templateUrl: './small-user.component.html', + styleUrl: './small-user.component.scss' +}) +export class SmallUserComponent { + +} diff --git a/src/app/user/user-routing.module.ts b/src/app/user/user-routing.module.ts new file mode 100644 index 0000000..3a55d86 --- /dev/null +++ b/src/app/user/user-routing.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { UserComponent } from './user.component'; + +const routes: Routes = [{ path: '', component: UserComponent }]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class UserRoutingModule { } diff --git a/src/app/user/user.component.html b/src/app/user/user.component.html new file mode 100644 index 0000000..d039bb7 --- /dev/null +++ b/src/app/user/user.component.html @@ -0,0 +1 @@ +

user works!

diff --git a/src/app/user/user.component.scss b/src/app/user/user.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/user/user.component.spec.ts b/src/app/user/user.component.spec.ts new file mode 100644 index 0000000..7d16b25 --- /dev/null +++ b/src/app/user/user.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserComponent } from './user.component'; + +describe('UserComponent', () => { + let component: UserComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [UserComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(UserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/user/user.component.ts b/src/app/user/user.component.ts new file mode 100644 index 0000000..8d6911d --- /dev/null +++ b/src/app/user/user.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-user', + templateUrl: './user.component.html', + styleUrl: './user.component.scss' +}) +export class UserComponent { + +} diff --git a/src/app/user/user.module.ts b/src/app/user/user.module.ts new file mode 100644 index 0000000..1594b39 --- /dev/null +++ b/src/app/user/user.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { UserRoutingModule } from './user-routing.module'; +import { UserComponent } from './user.component'; + + +@NgModule({ + declarations: [ + UserComponent + ], + imports: [ + CommonModule, + UserRoutingModule + ] +}) +export class UserModule { } diff --git a/src/assets/placeholder-profile-picture.png b/src/assets/placeholder-profile-picture.png new file mode 100644 index 0000000000000000000000000000000000000000..c436d2ce4591404e1333fdbce9144027547ccf83 GIT binary patch literal 11377 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