diff --git a/build.js b/build.js index 26ef98a..3b782a4 100644 --- a/build.js +++ b/build.js @@ -11,36 +11,57 @@ const argument0 = process.argv[2]; async function main(runMode) { const angularSourceBuffer = fs.readFileSync("buildconfig.json"); const angularSource = JSON.parse(angularSourceBuffer); + const generalConfiguration = angularSource.angular.projects[angularSource.projectName].architect.build.options; + angularSource.angular.projects[angularSource.projectName].architect.build.options = {}; const productionConfiguration = angularSource.angular.projects[angularSource.projectName].architect.build.configurations["production"]; delete angularSource.angular.projects[angularSource.projectName].architect.build.configurations["production"]; + angularSource.languages.forEach((language, languageIndex) => { - const defaultIndex = angularSource.angular.projects[angularSource.projectName].architect.build.options.index; + const defaultIndex = generalConfiguration.index; const defaultIndexName = defaultIndex.split(".").slice(0, -1).join("."); const defaultIndexExtension = defaultIndex.split(".").pop(); const languageSpecificIndex = defaultIndexName + "." + language + ".generated." + defaultIndexExtension; const languageConfiguration = { - "index": languageSpecificIndex, ...angularSource.angular.projects[angularSource.projectName].architect.build.configurations[language] }; delete angularSource.angular.projects[angularSource.projectName].architect.build.configurations[language]; angularSource.angular.projects[angularSource.projectName].architect.build.configurations["production_" + language] = { + ...generalConfiguration, ...productionConfiguration, ...languageConfiguration }; + angularSource.angular.projects[angularSource.projectName].architect.build.configurations["production_" + language].fileReplacements = [ + { + "replace": defaultIndex, + "with": languageSpecificIndex + }, + ...angularSource.angular.projects[angularSource.projectName].architect.build.configurations["production_" + language].fileReplacements + ]; + resolvePaths(angularSource.angular.projects[angularSource.projectName].architect.build.configurations["production_" + language], "assets", language); + angularSource.angular.projects[angularSource.projectName].architect.build.configurations["serve_" + language] = { - "aot": true, + ...generalConfiguration, ...languageConfiguration, + "aot": true, }; + if (angularSource.angular.projects[angularSource.projectName].architect.build.configurations["serve_" + language].fileReplacements === undefined) { + angularSource.angular.projects[angularSource.projectName].architect.build.configurations["serve_" + language].fileReplacements = []; + } + angularSource.angular.projects[angularSource.projectName].architect.build.configurations["serve_" + language].fileReplacements.push({ + "replace": defaultIndex, + "with": languageSpecificIndex + }); angularSource.angular.projects[angularSource.projectName].architect.serve.configurations[language] = { "browserTarget": "cavallium-website:build:serve_"+language, "port": 4200 + languageIndex }; + resolvePaths(angularSource.angular.projects[angularSource.projectName].architect.build.configurations["serve_" + language], "assets", language); // Create index.language.html let indexText = fs.readFileSync(defaultIndex).toString("utf8"); - indexText = indexText.replace("", ""); + indexText = indexText.replace("generate=\"language_attribute\"", "lang=\"" + language + "\""); fs.writeFileSync(languageSpecificIndex, indexText); }); @@ -60,7 +81,14 @@ async function main(runMode) { case "serve": await Promise.all(angularSource.languages.map((language, index) => { console.log("Building for language " + JSON.stringify(language) + (index > 0 ? " (hidden)" : "")); - const childProcess = spawn("ng", ["serve", "--configuration=" + language, "--host=0.0.0.0"], + const arguments = ["serve", "--configuration=" + language]; + if (angularSource.localIpAddress) { + arguments.push("--host=" + angularSource.localIpAddress); + } + if (angularSource.disableHostCheck) { + arguments.push("--disable-host-check"); + } + const childProcess = spawn("ng", arguments, { stdio: [process.stdin, index == 0 ? process.stdout : null, process.stderr] }); return onExit(childProcess); })); @@ -85,4 +113,14 @@ function onExit(childProcess) { reject(err); }); }); +} + +function resolvePaths(obj, elem, language) { + if (obj !== undefined && obj[elem] !== undefined && Array.isArray(obj[elem])) { + obj[elem] = obj[elem].map((asset) => typeof asset === "string" ? asset.replace("_GENERATED_LANGUAGE_", language) : { + "glob": asset.glob.replace("_GENERATED_LANGUAGE_", language), + "input": asset.input.replace("_GENERATED_LANGUAGE_", language), + "output": asset.output.replace("_GENERATED_LANGUAGE_", language) + }); + } } \ No newline at end of file diff --git a/buildconfig.json b/buildconfig.json index a0c3d7c..64918ea 100644 --- a/buildconfig.json +++ b/buildconfig.json @@ -2,6 +2,8 @@ "version": 1, "projectName": "cavallium-website", "languages": ["it", "en"], + "localIpAddress": "0.0.0.0", + "disableHostCheck": true, "angular": { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, @@ -28,7 +30,8 @@ "tsConfig": "src/tsconfig.app.json", "assets": [ "src/favicon.ico", - "src/assets" + "src/assets", + "src/documents" ], "styles": [ "src/styles.scss", @@ -86,7 +89,7 @@ "browserTarget": "cavallium-website:build:production" }, "en": { - "browserTarget": "my-project:build:it" + "browserTarget": "my-project:build:en" }, "it": { "browserTarget": "my-project:build:it" @@ -113,7 +116,8 @@ "scripts": [], "assets": [ "src/favicon.ico", - "src/assets" + "src/assets", + "src/documents" ] } }, diff --git a/package-lock.json b/package-lock.json index 8cb5072..a3a2c24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -673,6 +673,11 @@ "@types/jasmine": "*" } }, + "@types/marked": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.6.5.tgz", + "integrity": "sha512-6kBKf64aVfx93UJrcyEZ+OBM5nGv4RLsI6sR1Ar34bpgvGVRoyTgpxn4ZmtxOM5aDTAaaznYuYUH8bUX3Nk3YA==" + }, "@types/node": { "version": "8.9.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.5.tgz", @@ -2028,6 +2033,17 @@ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, + "clipboard": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", + "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", + "optional": true, + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -2661,6 +2677,12 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "optional": true + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -3624,14 +3646,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3646,20 +3666,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -3776,8 +3793,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -3789,7 +3805,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3804,7 +3819,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3812,14 +3826,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3838,7 +3850,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -3919,8 +3930,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -3932,7 +3942,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4054,7 +4063,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4270,6 +4278,15 @@ "minimatch": "~3.0.2" } }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "optional": true, + "requires": { + "delegate": "^3.1.2" + } + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", @@ -5944,6 +5961,11 @@ "object-visit": "^1.0.0" } }, + "marked": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.2.tgz", + "integrity": "sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA==" + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -6291,6 +6313,17 @@ "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", "dev": true }, + "ngx-markdown": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-7.1.5.tgz", + "integrity": "sha512-boL1eQkdHHwVQuLsRF4eaIxuBx2PoJidO/YStLU2a0u6Q7VCjaZI09oSPgsAmsDjJ/Hu7ZWGPv475H7BGJ8iCw==", + "requires": { + "@types/marked": "^0.6.0", + "marked": "^0.6.0", + "prismjs": "^1.16.0", + "tslib": "^1.9.0" + } + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -7225,6 +7258,14 @@ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true }, + "prismjs": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.16.0.tgz", + "integrity": "sha512-OA4MKxjFZHSvZcisLGe14THYsug/nF6O1f0pAJc0KN0wTyAcLqmsbE+lTGKSpyh+9pEW57+k6pg2AfYR+coyHA==", + "requires": { + "clipboard": "^2.0.0" + } + }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -8008,6 +8049,12 @@ } } }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "optional": true + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -9235,6 +9282,12 @@ "setimmediate": "^1.0.4" } }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "optional": true + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", diff --git a/package.json b/package.json index 13a2230..52b234c 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@angular/platform-browser-dynamic": "~7.2.0", "@angular/router": "~7.2.0", "core-js": "^2.5.4", + "ngx-markdown": "^7.1.5", "rxjs": "~6.3.3", "tslib": "^1.9.0", "zone.js": "~0.8.26" diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 5362b85..57811cf 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -4,6 +4,10 @@ import { ArticleComponent } from "./article/article.component"; import { RouterEmptyComponent } from "./gui/router-empty/router-empty.component"; const routes: Routes = [ + { + path: "", + component: ArticleComponent + }, { path: "article", component: RouterEmptyComponent, diff --git a/src/app/app.component.html b/src/app/app.component.html index 9fde759..dc181b6 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,8 +1,3 @@ - -

- Welcome to {{ title }}! -

-

Welcome to

+ + diff --git a/src/app/app.component.scss b/src/app/app.component.scss index e69de29..78257b2 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -0,0 +1,4 @@ +:host { + display: block; + overflow-y: auto; +} diff --git a/src/app/app.component.ts b/src/app/app.component.ts index af8c30c..d65f13e 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,5 @@ -import { Component } from "@angular/core"; +import { Component, HostListener, ViewChild } from "@angular/core"; +import { NavbarComponent } from "./gui/navbar/navbar.component"; @Component({ selector: "app-root", @@ -6,5 +7,12 @@ import { Component } from "@angular/core"; styleUrls: ["./app.component.scss"] }) export class AppComponent { - title = "cavallium-website"; + title = "cavallium-website"; + + @ViewChild("navbar") navbar: NavbarComponent; + + @HostListener("scroll", ["$event"]) + handleScroll(event: Event) { + this.navbar.onParentScroll(event); + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 7b906a3..711e8de 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -8,21 +8,54 @@ import { NavbarComponent } from "./gui/navbar/navbar.component"; import { FooterComponent } from "./gui/footer/footer.component"; import { ArticleComponent } from "./article/article.component"; import { RouterEmptyComponent } from "./gui/router-empty/router-empty.component"; +import {HttpClientModule} from "@angular/common/http"; +import { MarkdownModule, MarkedOptions, MarkedRenderer, MarkdownComponent } from "ngx-markdown"; +import { BigLogoComponent } from './gui/big-logo/big-logo.component'; @NgModule({ - declarations: [ - AppComponent, - HomeComponent, - NavbarComponent, - FooterComponent, - ArticleComponent, - RouterEmptyComponent - ], - imports: [ - BrowserModule, - AppRoutingModule - ], - providers: [], - bootstrap: [AppComponent] + declarations: [ + AppComponent, + HomeComponent, + NavbarComponent, + FooterComponent, + ArticleComponent, + RouterEmptyComponent, + BigLogoComponent + ], + imports: [ + BrowserModule, + AppRoutingModule, + HttpClientModule, + MarkdownModule.forRoot({ + markedOptions: { + provide: MarkedOptions, + useFactory: markedOptionsFactory, + }, + }), + ], + providers: [], + bootstrap: [AppComponent] }) export class AppModule { } + +export function markedOptionsFactory(): MarkedOptions { + const renderer = new MarkedRenderer(); + + renderer.blockquote = (text: string) => { + return "

" + text + "

"; + }; + /*renderer.warning = (text: string) => { + return ""; + };*/ + + return { + renderer, + gfm: true, + tables: true, + breaks: false, + pedantic: false, + sanitize: false, + smartLists: true, + smartypants: false, + }; +} diff --git a/src/app/article/article.component.html b/src/app/article/article.component.html index 684915b..b6de578 100644 --- a/src/app/article/article.component.html +++ b/src/app/article/article.component.html @@ -1,3 +1,6 @@ -

- article works! -

+ + diff --git a/src/app/article/article.component.scss b/src/app/article/article.component.scss index e69de29..279bc52 100644 --- a/src/app/article/article.component.scss +++ b/src/app/article/article.component.scss @@ -0,0 +1,6 @@ +:host { + display: block; + overflow-x: hidden; + word-break: break-word; + padding: 0 0.5rem; +} \ No newline at end of file diff --git a/src/app/article/article.component.ts b/src/app/article/article.component.ts index abadd4c..b4cd586 100644 --- a/src/app/article/article.component.ts +++ b/src/app/article/article.component.ts @@ -1,19 +1,40 @@ -import { Component, OnInit } from "@angular/core"; +import { Component, OnInit, OnDestroy } from "@angular/core"; import { ActivatedRoute, UrlSegment } from "@angular/router"; +import { map } from "rxjs/operators"; +import { DocumentFetchService } from "../services/document-fetch.service"; +import { DocumentData } from "../symbols/DocumentData"; +import { MarkdownService } from "ngx-markdown"; +import { CurrentDocumentService } from "../services/current-document.service"; @Component({ selector: "app-article", templateUrl: "./article.component.html", styleUrls: ["./article.component.scss"] }) -export class ArticleComponent implements OnInit { +export class ArticleComponent implements OnInit, OnDestroy { - constructor(private activatedRoute: ActivatedRoute) { } + public documentData: DocumentData; + + constructor( + private activatedRoute: ActivatedRoute, + private documentFetcher: DocumentFetchService, + private markdownService: MarkdownService, + private currentDocumentService: CurrentDocumentService + ) { } ngOnInit() { - this.activatedRoute.data.subscribe(console.log); - this.activatedRoute.params.subscribe(console.log); - this.activatedRoute.url.subscribe((url: UrlSegment[]) => console.log(url.map((urlSegment) => urlSegment.path).join("/"))); + this.activatedRoute.url + .pipe(map((urlSegments: UrlSegment[]) => urlSegments.map(urlSegment => urlSegment.path).join("/"))) + .subscribe(async (url: string) => { + const docData: DocumentData = await this.documentFetcher.fetch(url); + this.documentData = docData; + this.currentDocumentService.setCurrentDocument(docData); + }); + + } + + ngOnDestroy() { + this.currentDocumentService.setCurrentDocument(null); } } diff --git a/src/app/gui/big-logo/big-logo.component.html b/src/app/gui/big-logo/big-logo.component.html new file mode 100644 index 0000000..d879c05 --- /dev/null +++ b/src/app/gui/big-logo/big-logo.component.html @@ -0,0 +1,4 @@ + + logo +

Cavallium.it

+
diff --git a/src/app/gui/big-logo/big-logo.component.scss b/src/app/gui/big-logo/big-logo.component.scss new file mode 100644 index 0000000..5ade9cb --- /dev/null +++ b/src/app/gui/big-logo/big-logo.component.scss @@ -0,0 +1,48 @@ +@import "../../../styles-variables.scss"; +:host { + display: block; + background-color: $color-main; + color: white; + text-align: center; + position: relative; + user-select: none; + z-index: 1002; + overflow: hidden; +} +:host:after, :host:before { + content: ""; + display: flex; + clear: both; +} +a { + color: inherit; + text-decoration: none; + display: flex; + justify-content: center; + align-items: center; + margin: -0.5rem; + padding-top: 3rem; + padding-bottom: 2.5rem; + font-size: 1.5rem; +} +h1 { + margin: 0; +} +a > * { + margin: 0.5rem; +} +img { + height: 5rem; +} + +@media screen and (max-width: $mobile-mode-size) { + a { + flex-direction: column; + padding-top: 1rem; + padding-bottom: 0.5rem; + font-size: 1rem; + } + img { + height: 4rem; + } +} diff --git a/src/app/gui/big-logo/big-logo.component.spec.ts b/src/app/gui/big-logo/big-logo.component.spec.ts new file mode 100644 index 0000000..ca0b622 --- /dev/null +++ b/src/app/gui/big-logo/big-logo.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BigLogoComponent } from './big-logo.component'; + +describe('BigLogoComponent', () => { + let component: BigLogoComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ BigLogoComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(BigLogoComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/gui/big-logo/big-logo.component.ts b/src/app/gui/big-logo/big-logo.component.ts new file mode 100644 index 0000000..efab995 --- /dev/null +++ b/src/app/gui/big-logo/big-logo.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-big-logo', + templateUrl: './big-logo.component.html', + styleUrls: ['./big-logo.component.scss'] +}) +export class BigLogoComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/src/app/gui/navbar/navbar.component.html b/src/app/gui/navbar/navbar.component.html index cf7832c..e25911d 100644 --- a/src/app/gui/navbar/navbar.component.html +++ b/src/app/gui/navbar/navbar.component.html @@ -1,18 +1,22 @@ - - -
- -
- -
- +
+ + +
+
>
\ No newline at end of file diff --git a/src/app/gui/navbar/navbar.component.scss b/src/app/gui/navbar/navbar.component.scss index e69de29..8dbcb16 100644 --- a/src/app/gui/navbar/navbar.component.scss +++ b/src/app/gui/navbar/navbar.component.scss @@ -0,0 +1,123 @@ +@import "../../../styles-variables"; +:host { + position: sticky; + top: 0; + overflow: initial; + display: block; + background-color: $color-main; + color: white; + z-index: 1001; +} +.shadow-container { + overflow-x: hidden; + display: flex; + box-shadow: 0 -2rem 2rem 2rem transparent; + transition: box-shadow ease-in-out 0.2s; +} +.shadow-container.overflow { + overflow-x: scroll; + -ms-overflow-style: none; // IE 10+ + scrollbar-width: none; // Firefox + justify-content: center; +} +.shadow-container.overflow.overflow-max { + justify-content: flex-start; +} +.shadow-container.overflow::-webkit-scrollbar { + display: none; // Safari and Chrome +} +.shadow-container.sticked { + box-shadow: 0 -2rem 2rem 2rem #0000006e; +} +:host:after, :host:before { + content: ""; + display: flex; + clear: both; +} +.header-logo, .header-logo-space { + padding: 1rem 0rem; + text-align: right; + vertical-align: middle; + flex: 0 0 6.2rem; + opacity: 0; + pointer-events: none; + user-select: none; + position: relative; + top: -5rem; + color: inherit; + text-decoration: none; + transition: opacity ease-in-out 0.4s, top ease-in-out 0s 0.4s; +} +.header-logo.visible { + opacity: 1; + pointer-events: initial; + font-size: initial; + top: 0; + transition: opacity ease-in-out 0.3s, top ease-in-out 0.3s; +} +.header-logo-space { + flex: 0 1 6rem; +} +.header-logo.overflow, .header-logo-space.overflow { + position: fixed; + top: 0; + visibility: hidden; + pointer-events: none; +} +.header-nav { + flex: 1 0 auto; +} +.header-nav.overflow { + flex: 0 0 auto; +} +.header-nav.overflow-max { + padding-right: 1.5rem; +} +.header-nav a { + color: inherit; + text-decoration: none; + flex: 1 1 100%; + padding: 0 0.5rem; +} +.header-nav ul { + list-style: none; + padding-inline-start: 0; + margin: 0; + display: flex; + justify-content: center; +} +.header-nav li { + flex: 0 0 auto; + text-align: center; + display: flex; +} +.header-nav span { + display: block; + padding: 1rem 0.2rem; + border-bottom: 0rem solid transparent; + padding-bottom: 1rem; + transition: border-bottom-color ease-in-out 0.2s, border-bottom-width ease-in-out 0.2s, padding-bottom ease-in-out 0.2s; +} +.header-nav li:hover span, .header-nav li .force-focus span { + border-bottom-color: white; + border-bottom-width: 0.2rem; + border-bottom-color: white; + padding-bottom: 0.8rem; +} +.overflow-max-indicator { + position: absolute; + right: 0; + top: 0; + bottom: 0; + opacity: 0; + pointer-events: none; + padding: 1rem 0; + font-weight: 800; + width: 2rem; + text-align: right; + padding-right: 0.25rem; + box-shadow: -2rem 0 0.5rem -0.5rem $color-main inset; +} +.overflow-max-indicator.visible { + opacity: 1; +} \ No newline at end of file diff --git a/src/app/gui/navbar/navbar.component.ts b/src/app/gui/navbar/navbar.component.ts index 015e37d..b1d2ed9 100644 --- a/src/app/gui/navbar/navbar.component.ts +++ b/src/app/gui/navbar/navbar.component.ts @@ -1,38 +1,84 @@ -import { Component, OnInit } from "@angular/core"; +import { Component, OnInit, HostListener, Input, ElementRef, ViewChild, AfterViewInit } from "@angular/core"; import { NavigationLink } from "src/app/symbols/NavigationLink"; +import { ActivatedRoute, UrlSegment } from "@angular/router"; +import { map } from "rxjs/operators"; +import { CurrentDocumentService } from "src/app/services/current-document.service"; @Component({ selector: "app-navbar", templateUrl: "./navbar.component.html", styleUrls: ["./navbar.component.scss"] }) -export class NavbarComponent implements OnInit { +export class NavbarComponent implements OnInit, AfterViewInit { public navigationLinks: NavigationLink[] = [ { - text: "Software", + text: "Cardboard bug", address: "/article/software" }, { text: "Midi23D", - address: "/article/midi23d" + address: "/article/software/midi23d" }, { text: "Calculator", address: "/article/calculator", - newtab: true + newtab: false }, { text: "Github", address: "https://github.com/Cavallium/WarpPI", external: true, - newtab: false + newtab: true }, ]; + stickedOnTop = false; + overflowLogo = false; + overflowMax = false; + @ViewChild("navlogo") navLogo: ElementRef; + @ViewChild("navbuttons") navButtons: ElementRef; - constructor() { } + constructor(private elRef: ElementRef, public currentDocument: CurrentDocumentService) { } ngOnInit() { + // TODO: fare la parte dei percorsi preselezionati } + ngAfterViewInit() { + setTimeout(() => { + this.updateSticked(); + this.updateSize(); + }); + } + + @Input() + public onParentScroll(event: Event) { + this.updateSticked(); + } + + private updateSticked() { + this.stickedOnTop = this.elRef.nativeElement.getBoundingClientRect().top <= 0; + } + + private updateSize() { + if (this.overflowLogo === false + && (this.navButtons.nativeElement.offsetWidth + this.navLogo.nativeElement.offsetWidth) > this.elRef.nativeElement.offsetWidth) { + this.overflowLogo = true; + } else if (this.overflowLogo === true + && this.navButtons.nativeElement.offsetWidth + this.navLogo.nativeElement.offsetWidth < this.elRef.nativeElement.offsetWidth - 30) { + this.overflowLogo = false; + } + if (this.overflowMax === false + && this.navButtons.nativeElement.offsetWidth > this.elRef.nativeElement.offsetWidth) { + this.overflowMax = true; + } else if (this.overflowMax === true + && this.navButtons.nativeElement.offsetWidth < this.elRef.nativeElement.offsetWidth) { + this.overflowMax = false; + } + } + + @HostListener("window:resize", ["$event"]) + handleResize(event: Event) { + this.updateSize(); + } } diff --git a/src/app/services/current-document.service.spec.ts b/src/app/services/current-document.service.spec.ts new file mode 100644 index 0000000..7e26a7e --- /dev/null +++ b/src/app/services/current-document.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { CurrentDocumentService } from './current-document.service'; + +describe('CurrentDocumentService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: CurrentDocumentService = TestBed.get(CurrentDocumentService); + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/current-document.service.ts b/src/app/services/current-document.service.ts new file mode 100644 index 0000000..5f6adbb --- /dev/null +++ b/src/app/services/current-document.service.ts @@ -0,0 +1,21 @@ +import { Injectable } from "@angular/core"; +import { Observable, BehaviorSubject } from "rxjs"; +import { DocumentData } from "../symbols/DocumentData"; + +@Injectable({ + providedIn: "root" +}) +export class CurrentDocumentService { + + private documentSubject = new BehaviorSubject(null); + + constructor() { } + + public onDocumentChange(): Observable { + return this.documentSubject.asObservable(); + } + + public setCurrentDocument(data: DocumentData) { + this.documentSubject.next(data); + } +} diff --git a/src/app/services/document-fetch.service.ts b/src/app/services/document-fetch.service.ts index ced52d9..84725b7 100644 --- a/src/app/services/document-fetch.service.ts +++ b/src/app/services/document-fetch.service.ts @@ -1,44 +1,64 @@ import { Injectable } from "@angular/core"; -import { Observable } from "rxjs"; import { DocumentData } from "../symbols/DocumentData"; -import { HttpClient, Request, Response } from "selenium-webdriver/http"; -import { encodeUriSegment } from "@angular/router/src/url_tree"; +import { HttpClient } from "@angular/common/http"; +import { take } from "rxjs/operators"; @Injectable({ providedIn: "root" }) export class DocumentFetchService { + private language: string; - constructor(private http: HttpClient) {} + constructor(private http: HttpClient) { + this.language = document.body.parentElement.lang; + } public async fetch(unsafeId: string): Promise { const encodedId = this.encodeId(unsafeId); - const response: Response = await this.http.send(new Request("GET", "/documents/" + encodedId + ".md")); - if (response.status === 200) { - return { - found: true, - id: encodedId, - content: await response.body - }; + try { + return await this.fetchWithLanguage(encodedId, this.language); + } catch (e) { + try { + return await this.fetchWithLanguage(encodedId, "en"); + } catch (e) { + return { + found: false, + id: encodedId, + content: await this.fetchErrorContent(404) + }; + } } + } + + private async fetchWithLanguage(unsafeId: string, language: string): Promise { + const encodedId = this.encodeId(unsafeId); + const response: string = await this.http.get("/documents/" + encodedId + "." + language + ".md", { responseType: "text" }) + .pipe(take(1)).toPromise(); return { - found: false, + found: true, id: encodedId, - content: await this.fetchErrorContent(404) + content: await response }; } public async fetchErrorContent(errorCode: number): Promise { if (errorCode > 0 && errorCode <= 700) { - const response: Response = await this.http.send(new Request("GET", "/documents/" + errorCode + ".md")); - if (response.status === 200) { - return await response.body; + try { + const response: string = await this.http.get("/documents/" + errorCode + "." + this.language + ".md", { responseType: "text" }) + .pipe(take(1)).toPromise(); + return response; + } catch (e) { } } return "Error " + errorCode + "."; } private encodeId(id: string): string { - return id.split("/").map(encodeUriSegment).filter((part) => part !== "." && part !== "..").join("/"); + const encoded = id.split("/").map(encodeURIComponent).filter((part) => part.length > 0 && part !== "." && part !== "..").join("/"); + if (encoded.length > 0) { + return encoded; + } else { + return "index"; + } } } diff --git a/src/assets/drone.min.svg b/src/assets/drone.min.svg new file mode 100644 index 0000000..1574838 --- /dev/null +++ b/src/assets/drone.min.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/documents/404.en.md b/src/documents/404.en.md new file mode 100644 index 0000000..c285f07 --- /dev/null +++ b/src/documents/404.en.md @@ -0,0 +1,3 @@ +# 404 Error + +## Page not found diff --git a/src/documents/404.it.md b/src/documents/404.it.md new file mode 100644 index 0000000..f483630 --- /dev/null +++ b/src/documents/404.it.md @@ -0,0 +1,3 @@ +# Errore 404 + +## Pagina non trovata diff --git a/src/documents/index.en.md b/src/documents/index.en.md new file mode 100644 index 0000000..8731030 --- /dev/null +++ b/src/documents/index.en.md @@ -0,0 +1,5 @@ +# Welcome to Cavallium.it + +This page is a test. + +**Bold.** *Cantami o diva del pelide achille l'ira funesta che infiniti addusse lutti agli achei.* \ No newline at end of file diff --git a/src/documents/index.it.md b/src/documents/index.it.md new file mode 100644 index 0000000..e7f1350 --- /dev/null +++ b/src/documents/index.it.md @@ -0,0 +1,5 @@ +# Benvenuto in Cavallium.it + +Questa pagina รจ una prova. + +**Prova in grassetto.** *Cantami o diva del pelide achille l'ira funesta che infiniti addusse lutti agli achei.* \ No newline at end of file diff --git a/src/documents/software.en.md b/src/documents/software.en.md new file mode 100644 index 0000000..281106d --- /dev/null +++ b/src/documents/software.en.md @@ -0,0 +1,29 @@ +# LG G2 Cardboard fix + +## Fixing the double vision on your LG G2 using Cardboard + +### When this problem occurs + +If you have installed a custom rom on your LG G2 probably the DPI setting has changed. +The DPI setting is used to calculate the pixel density, and consequently the real measures of your screen. Google Cardboard calculates the distance between eyes using the DPI setting, and if it's wrong some apps using the old CardBoard SDK don't show properly. + +#### Here's an example + +With 480 DPI (CyanogenMod default setting)
+*same length in inches:* 4 + +With 424 DPI (LG G2 real DPI)
+*same length in inches:* 3 + +### How to fix it + +Please choose the method that you prefer + +#### Method 1 + +***Fixing the problem for some apps, keeping your current DPI setting.*** + +1. Open Cardboard app +2. Tap **Settings** +3. Tap **Change** +4. Scan with your camera this QR-Code:
[warning]WARNING: If you do this you can't go back to the default settings![warning] \ No newline at end of file diff --git a/src/documents/software.it.md b/src/documents/software.it.md new file mode 100644 index 0000000..b9ffc32 --- /dev/null +++ b/src/documents/software.it.md @@ -0,0 +1,55 @@ +# LG G2 Cardboard fix + +## Fixing the double vision on your LG G2 using Cardboard + +### When this problem occurs + +If you have installed a custom rom on your LG G2 probably the DPI setting has changed. +The DPI setting is used to calculate the pixel density, and consequently the real measures of your screen. Google Cardboard calculates the distance between eyes using the DPI setting, and if it's wrong some apps using the old CardBoard SDK don't show properly. + +#### Here's an example + +With 480 DPI (CyanogenMod default setting)
+*same length in inches:* 4 + +With 424 DPI (LG G2 real DPI)
+*same length in inches:* 3 + +### How to fix it + +Please choose the method that you prefer + +#### Method 1 + +***Fixing the problem for some apps, keeping your current DPI setting.*** + +1. Open Cardboard app +2. Tap **Settings** +3. Tap **Change** +4. Scan with your camera this QR-Code:
[warning]WARNING: If you do this you can't go back to the default settings![warning] + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/documents/software/midi23d.en.md b/src/documents/software/midi23d.en.md new file mode 100644 index 0000000..82a2752 --- /dev/null +++ b/src/documents/software/midi23d.en.md @@ -0,0 +1,3 @@ +# Midi23D + +This is a test page \ No newline at end of file diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 3612073..8b7239d 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,3 +1,3 @@ export const environment = { - production: true + production: true }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 7b4f817..c5a517a 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -3,7 +3,7 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false + production: false }; /* diff --git a/src/index.html b/src/index.html index 7516355..9b1c283 100644 --- a/src/index.html +++ b/src/index.html @@ -1,8 +1,8 @@ - + - CavalliumWebsite + Cavallium.it diff --git a/src/styles-variables.scss b/src/styles-variables.scss new file mode 100644 index 0000000..0fc5ee0 --- /dev/null +++ b/src/styles-variables.scss @@ -0,0 +1,2 @@ +$color-main: #3F51B5; +$mobile-mode-size: 425px; \ No newline at end of file diff --git a/src/styles.scss b/src/styles.scss index 3219489..461258b 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,4 +1,8 @@ /* You can add global styles to this file, and also import other style files */ +html, body, body, app-root { + height: 100%; + max-height: 100%; +} body { margin: 0; font-family: "Muli-custom", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;