diff --git a/.internals/icons/inkscape-banner_1200x1200.svg b/.internals/icons/inkscape-banner_1200x1200.svg
new file mode 100644
index 00000000..57024df2
--- /dev/null
+++ b/.internals/icons/inkscape-banner_1200x1200.svg
@@ -0,0 +1,225 @@
+
+
diff --git a/.internals/icons/inkscape-banner_1200x630.svg b/.internals/icons/inkscape-banner_1200x630.svg
new file mode 100644
index 00000000..a4d7fb31
--- /dev/null
+++ b/.internals/icons/inkscape-banner_1200x630.svg
@@ -0,0 +1,225 @@
+
+
diff --git a/.internals/icons/inkscape-banner_630x1200.svg b/.internals/icons/inkscape-banner_630x1200.svg
new file mode 100644
index 00000000..2a0eb46e
--- /dev/null
+++ b/.internals/icons/inkscape-banner_630x1200.svg
@@ -0,0 +1,225 @@
+
+
diff --git a/Angular/.ci/build_unix-any.sh b/Angular/.ci/build_unix-any.sh
index 0e5571ef..5bbae10a 100644
--- a/Angular/.ci/build_unix-any.sh
+++ b/Angular/.ci/build_unix-any.sh
@@ -1,6 +1,7 @@
#!/bin/sh
# Copyright 2023 (Holloway) Chew, Kean Ho
#
+#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at:
@@ -46,7 +47,7 @@ fi
I18N_Build "$PROJECT_ANGULAR"
__current_path="$PWD" && cd "${PROJECT_PATH_ROOT}/${PROJECT_ANGULAR}"
-ANGULAR_Build
+./build.sh.ps1
___process=$?
cd "$__current_path" && unset __current_path
if [ $___process -ne 0 ]; then
diff --git a/Angular/.ci/build_windows-any.ps1 b/Angular/.ci/build_windows-any.ps1
index 34318d58..0e3da71c 100644
--- a/Angular/.ci/build_windows-any.ps1
+++ b/Angular/.ci/build_windows-any.ps1
@@ -1,5 +1,6 @@
# Copyright 2023 (Holloway) Chew, Kean Ho
#
+#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at:
@@ -20,6 +21,7 @@ if (-not (Test-Path -Path $env:PROJECT_PATH_ROOT)) {
}
. "${env:LIBS_AUTOMATACI}\services\io\fs.ps1"
+. "${env:LIBS_AUTOMATACI}\services\io\os.ps1"
. "${env:LIBS_AUTOMATACI}\services\i18n\translations.ps1"
. "${env:LIBS_AUTOMATACI}\services\compilers\angular.ps1"
@@ -46,7 +48,7 @@ if ($___process -ne 0) {
$null = I18N-Build "${env:PROJECT_ANGULAR}"
$__current_path = Get-Location
$null = Set-Location "${env:PROJECT_PATH_ROOT}\${env:PROJECT_ANGULAR}"
-$___process = ANGULAR-Build
+$___process = OS-Exec "./build.sh.ps1"
$null = Set-Location "${__current_path}"
$null = Remove-Variable __current_path
if ($___process -ne 0) {
diff --git a/Angular/.ci/clean_unix-any.sh b/Angular/.ci/clean_unix-any.sh
new file mode 100644
index 00000000..ed970d5f
--- /dev/null
+++ b/Angular/.ci/clean_unix-any.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Copyright 2024 (Holloway) Chew, Kean Ho
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at:
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+
+
+
+# initialize
+if [ "$PROJECT_PATH_ROOT" = "" ]; then
+ >&2 printf "[ ERROR ] - Please run from automataCI/ci.sh.ps1 instead!\n"
+ return 1
+fi
+
+. "${LIBS_AUTOMATACI}/services/io/fs.sh"
+
+
+
+
+# execute
+__current_path="$PWD"
+cd "${PROJECT_PATH_ROOT}/${PROJECT_ANGULAR}"
+
+FS_Remove_Silently "dist"
+FS_Remove_Silently "node_modules"
+
+cd "$__current_path"
+unset __current_path
+
+
+
+
+# report status
+return 0
diff --git a/Angular/.ci/clean_windows-any.ps1 b/Angular/.ci/clean_windows-any.ps1
new file mode 100644
index 00000000..ebce945f
--- /dev/null
+++ b/Angular/.ci/clean_windows-any.ps1
@@ -0,0 +1,42 @@
+# Copyright 2024 (Holloway) Chew, Kean Ho
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy
+# of the License at:
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+
+
+# initialize
+if (-not (Test-Path -Path $env:PROJECT_PATH_ROOT)) {
+ Write-Error "[ ERROR ] - Please run from automataCI\ci.sh.ps1 instead!`n"
+ return 1
+}
+
+. "${env:LIBS_AUTOMATACI}\services\io\fs.ps1"
+
+
+
+
+# execute
+$__current_path = Get-Location
+$null = Set-Location "${env:PROJECT_PATH_ROOT}\${env:PROJECT_ANGULAR}"
+
+$null = FS-Remove-Silently "dist"
+$null = FS-Remove-Silently "node_modules"
+
+$null = Set-Location "${__current_path}"
+$null = Remove-Variable __current_path
+
+
+
+
+# report status
+return 0
diff --git a/Angular/.ci/materialize_unix-any.sh b/Angular/.ci/materialize_unix-any.sh
index 2a67a691..5ccbc69d 100644
--- a/Angular/.ci/materialize_unix-any.sh
+++ b/Angular/.ci/materialize_unix-any.sh
@@ -1,6 +1,7 @@
#!/bin/sh
# Copyright 2023 (Holloway) Chew, Kean Ho
#
+#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at:
@@ -38,7 +39,7 @@ fi
I18N_Build "$PROJECT_ANGULAR"
__current_path="$PWD" && cd "${PROJECT_PATH_ROOT}/${PROJECT_ANGULAR}"
-ANGULAR_Build
+./build.sh.ps1
___process=$?
cd "$__current_path" && unset __current_path
if [ $___process -ne 0 ]; then
diff --git a/Angular/.ci/materialize_windows-any.ps1 b/Angular/.ci/materialize_windows-any.ps1
index fc9501c7..ea895b3d 100644
--- a/Angular/.ci/materialize_windows-any.ps1
+++ b/Angular/.ci/materialize_windows-any.ps1
@@ -1,5 +1,6 @@
# Copyright 2023 (Holloway) Chew, Kean Ho
#
+#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at:
@@ -39,7 +40,7 @@ if ($___process -ne 0) {
$null = I18N-Build "${env:PROJECT_ANGULAR}"
$__current_path = Get-Location
$null = Set-Location "${env:PROJECT_PATH_ROOT}\${env:PROJECT_ANGULAR}"
-$___process = Angular-Build
+$___process = OS-Exec "./build.sh.ps1"
$null = Set-Location "${__current_path}"
$null = Remove-Variable __current_path
if ($___process -ne 0) {
diff --git a/Angular/.ci/prepare_unix-any.sh b/Angular/.ci/prepare_unix-any.sh
index 95cf2688..cbd1631e 100644
--- a/Angular/.ci/prepare_unix-any.sh
+++ b/Angular/.ci/prepare_unix-any.sh
@@ -1,6 +1,7 @@
#!/bin/sh
# Copyright 2023 (Holloway) Chew, Kean Ho
#
+#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at:
diff --git a/Angular/.ci/prepare_windows-any.ps1 b/Angular/.ci/prepare_windows-any.ps1
index 712970f6..48c28f27 100644
--- a/Angular/.ci/prepare_windows-any.ps1
+++ b/Angular/.ci/prepare_windows-any.ps1
@@ -1,5 +1,6 @@
# Copyright 2023 (Holloway) Chew, Kean Ho
#
+#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at:
diff --git a/Angular/.ci/test_unix-any.sh b/Angular/.ci/test_unix-any.sh
index 27796a0f..10d5306f 100644
--- a/Angular/.ci/test_unix-any.sh
+++ b/Angular/.ci/test_unix-any.sh
@@ -1,6 +1,7 @@
#!/bin/sh
# Copyright 2023 (Holloway) Chew, Kean Ho
#
+#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at:
@@ -50,7 +51,7 @@ else
return 1
fi
- CHROME_BIN="${___browser}" ANGULAR_Test
+ CHROME_BIN="${___browser}" ./test.sh.ps1
if [ $? -ne 0 ]; then
I18N_Run_Failed
return 1
diff --git a/Angular/.ci/test_windows-any.ps1 b/Angular/.ci/test_windows-any.ps1
index 53b5c1a9..e7966bb5 100644
--- a/Angular/.ci/test_windows-any.ps1
+++ b/Angular/.ci/test_windows-any.ps1
@@ -1,5 +1,6 @@
# Copyright 2023 (Holloway) Chew, Kean Ho
#
+#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at:
@@ -51,7 +52,7 @@ if ($(OS-Is-Run-Simulated) -eq 0) {
}
$env:CHROME_BIN = $___browser
- $___process = ANGULAR-Test
+ $___process = OS-Exec "./test.sh.ps1"
if ($___process -ne 0) {
$null = I18N-Run-Failed
return 1
diff --git a/Angular/README.md b/Angular/README.md
index 42442fc9..422d2d30 100644
--- a/Angular/README.md
+++ b/Angular/README.md
@@ -1,29 +1,79 @@
# AutomataCI Static Site Generator Angular Setup
-This document is mainly for Angular developer to understand what is going on
-with the organization here. Most of the resources are the same.
+This document is mainly for the project developers including junior role to
+understand what is going on in the workspace and how to operate it.
+Most of the Angular resources should be the same.
## Directory Structures
-Unlike what was recommended by Angular, AutomataCI prepares 2 separate
+Unlike what was recommended by Angular, AutomataCI prepared 2 clearly separated
components directories:
1. `contents/` - organize the pages
2. `services/` - where your libraries and components stays
+3. `assets/` - any static files located at the root of the site.
-The `contents/` structures the website page hirarchy and imports the `services/`
-libraries to construct the page.
+The root directory is programmed to be here, where all the `app.*.ts` and
+`main.*.ts` are located.
+
+The `contents/` component directory structures the website page hirarchy.
+Each page imports component libraries from the `services/` directory for
+constructing its content. All components in both directories are both using
+Angular Components to operate seamlessly.
+
+For internationalization (i18n), it is best to keep it as service libraries
+while retaining the `contents/` directory as the page rendering template. You
+can pass the language code using the `app.routes.ts` routing mechanism and
+have them rendered accordingly.
+
+To avoid path conflicts, you should always check the `assets/` availability
+before creating the content inside `content/` directory.
+
+For better separation of concerns:
+
+1. `content/` components is recommended to have `PAGE_` prefix for clarity
+2. `service/` components can remain to be anything but is best to be organized
+ into directory for later module construction and etc.
+
+
+
+
+## Operations
+
+Due to Angular's limitation (dating Angular 18), You are **strongly advised**
+to use the prepared Polygot shell for commands:
+
+```
+$ cd workspace/ # get into your Angular workspace as current directory
+
+$ # run any of the following matching your intention:
+$ ./serve.sh.ps1 # for development
+$ ./test.sh.ps1 # for test run
+$ ./build.sh.ps1 # for build
+```
+
+This is mainly due to Angular does not have any pre-initialization function
+that can setup the workspace's critical data files dynamically
+(example: `assets/manifest.webmanifest`, `assets/CNAME`, and etc) before the
+actual start-up. To workaround this challenge, a 2-steps execution is done
+inside these scripts where the `init.sh.ps1` (sourced by others) is
+responsible for building and updating these critical data files using the
+Angular server-side-rendering capability.
+
+These are Polygot scripts which means it should work for both UNIX and Windows
+operating system natively.
## Server-Side Rendering (SSR) or Static Site Generation (SSG) First
-There is a high chance this project is likely being used to generate JAM Stack.
-Hence, AutomataCI prioritizes the SSR and SSG (pre-rendering) facilities.
+AutomataCI prioritizes the SSR and SSG (pre-rendering) facilities over other
+modes. There is a high chance this project is likely being used to generate
+JAM stack static website.
@@ -31,49 +81,218 @@ Hence, AutomataCI prioritizes the SSR and SSG (pre-rendering) facilities.
## Setting website Base URL
To set the Base URL, make sure you update the `baseHref` and `deployUrl` data
-inside `angular.json`:
+inside the `angular.json` as follows:
```
-diff --git a/angular/angular.json b/angular/angular.json
-index 5379d9e..fb2e8fa 100644
---- a/angular/angular.json
-+++ b/angular/angular.json
-@@ -46,6 +46,8 @@
- },
- "configurations": {
- "production": {
-+ "baseHref": "https://www.example.com/",
-+ "deployUrl": "https://www.example.com/",
- "budgets": [
- {
- "type": "initial",
+{
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "version": 1,
+ "newProjectRoot": "projects",
+ "projects": {
+ "app": {
+ ...
+ "architect": {
+ "build": {
+ ...
+ "configurations": {
+ "production": {
+ "baseHref": "https://www.example.com/",
+ "deployUrl": "https://www.example.com/",
+ ...
+ ...
+}
```
-Then make sure you edit `assets/CNAME` and add only the domain name inside. This
-is for GitHub or GitLab authentication use.
+`baseHref` is for the website base URL while `deployUrl` is for the asset-only
+base URL.
+
+**DO NOT PASS ANY OF THEM IN VIA ARGUMENTS**. The workspace initialization is
+sourced `angular.json` only. Failure can cause unknown and time-consuming
+concequences.
+
+
+
+
+## PWA Web Manifest & CNAME
+
+By default, AutomataCI prepared the workspace to generate their critical data
+files dynamically using the 2-steps operational workaround.
+
+To modify them, look for these generator files and modify accordingly:
+
+* `init.pwa.ts` - for generating `assets/manifest.webmanifest` file.
+* `init.cname.ts` - for generating the `assets/CNAME` file.
+
+
+
+
+## Site-Level Metadata
+
+By default, AutomataCI prepared a site-level metadata file for default values
+rendering purposes located at:
+
+* `init.metadata.ts` - a constant object holding the site-level data.
+
+This affects a lot of built-in facilities like `assets/manifest.webmanifest` and
+page rendering.
+
+
+
+
+## Site Logos & Favicons
+
+This workspace comes with a default placement for logos & favicons
+pre-programmed located at `assets/logos/` directory. Updating all the graphic
+files will update the project entirely.
+
+These logos are reusable outside of favicon usage especially those `.svg`
+format.
+
+To add/remove a logo, look for:
+
+1. `init.pwa.ts` web manifest generator.
+2. `app.html` head section.
+
+
+
+
+## Update Screenshots
+
+Baseline PWA requires 3 basic screenshots located inside `assets/screenshots/`
+for:
+
+* `wide` form factor (recommended `1200x630` size)
+* `narrow` form factor (recommended `630x1200` size)
+* any form factor (recommended `1200x1200` size)
+
+To add/remove a logo, look for `init.pwa.ts` web manifest generator. For more
+technical specifications, please refer to the following:
+
+1. https://web.dev/articles/add-manifest
+2. https://developer.mozilla.org/en-US/docs/Web/Manifest/screenshots
+
+
+
+
+## Open-Graph Metadata
+
+By default, AutomataCI setup the default image thumbnails located inside the
+`assets/thumbnails/` directory. These images serve as the fall back images
+in case the page-level ones failed.
+
+By practice, these Open-Graph metadata must be updated at page-level.
+
+Recommended media dimension would be:
+
+1. `1200x630` - horizontal widescreen presentation
+2. `1200x1200` - square presentation
+3. `480x480` - fallback presentation
+
+You are free to alter the thumbnails located in `app.html` head section.
+
+For image, please use:
+
+```
+
+
+
+
+
+```
+
+For video, please use:
+
+```
+
+
+
+
+
+```
+
+For audio, please use:
+
+```
+
+
+```
+
+For more technical specification, please refer to the following:
+
+1. https://ogp.me/
+
+
+
+
+## LD+JSON Search Engine Optimization Schematic Data
+
+By default, AutomataCI only setup the default empty tag in the `app.html`.
+
+These LD+JSON SEO schematic data must be updated at the page-level rendering.
+For more technical specifications, please refer to the following:
+
+1. https://schema.org/docs/full.html
+
+
+
+
+## Sitemaps & `Robots.txt` Search Engine Optimization Configurations
+
+By default, AutomataCI generates the following automatically:
+
+* 1 index sitemap (`assets/sitemap.xml`)
+* all the pages' sitemap inside `assets/sitemaps/` directory
+* 1 robot text file (`assets/robots.txt`)
+
+The sitemaps are complying to the 50,000 entries limit.
+
+This is done by:
+
+1. parsing the `prerender-routes.txt` url list
+2. add from `url_add` specific url list
+3. remove from `url_remove` specific url list
+
+To add/remove urls or modify the `robots.txt` policy:
+
+* `init.sitemaps.ts` - the generator script.
+
+Look for:
+
+1. `url_add` - add additional URLs after `prerender-routes.txt`
+2. `url_remove` - remove URLs right before writing.
+3. `robots_policy` - the `robots.txt` without the `Sitemap: ` field (added
+ automatically whenever available).
+
-Then update the `assets/manifest.webmanifest` for PWA settings. Specifically,
-look for `start_url` and etc.
+## `browserconfig.xml` fallback configuration
+While deemed obselete, this file is generated for backward compatibilities and
+silencing those automated requests. AutomataCI automatically generate this
+config file into `assets/browserconfig.xml` based on the site-level metadata
+information.
-## For development
-Everything is the same as Angular: `$ ng serve`
+## `.nojekyll` configuration file
+Specific to GitHub, it is required to generate this configuration file for
+static site generator not using [Jekyll](https://jekyllrb.com/).
-## For Tests
-Everything is the same as Angular: `$ ng test` OR `$ ng e2e`
+## `CNAME` configuration file
+Specific to GitHub, AutomataCI generates the `assets/CNAME` configuration file
+as requested for custom domain implementations. By default, this file is not
+generated and will be hosted on GitHub Pages.
-## For Production
+To set the domain, please refer to:
-Everything is the same as Angular: `$ ng build`
+* `init.cname.ts` - generator file
-For full automation, use: `$ ./automataCI/ci.sh.ps1 build`
+Look for `const data = ''; // override the content here` and specify the domain
+value into it.
diff --git a/Angular/app.html b/Angular/app.html
index 44f7ea9b..5f91b72c 100644
--- a/Angular/app.html
+++ b/Angular/app.html
@@ -1,15 +1,20 @@
-
- Website
+
+ TITLE
-
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Angular/app.routes.ts b/Angular/app.routes.ts
index 88719dd8..9a370472 100644
--- a/Angular/app.routes.ts
+++ b/Angular/app.routes.ts
@@ -11,10 +11,29 @@ import { Page_Lang } from "./contents/lang/page";
export const routes: Routes = [
- { path: '', component: Page_Root },
- { path: 'en', component: Page_Lang, data: { lang: 'en' } },
+ // landing page
+ {
+ path: '',
+ component: Page_Root,
+ data: {
+ lang: '',
+ },
+ },
+
+
+ // main page by language
+ {
+ path: 'en',
+ component: Page_Lang,
+ data: {
+ lang: 'en',
+ },
+ },
// catch all
- { path: '**', component: Page_404 },
+ {
+ path: '**',
+ component: Page_404,
+ },
];
diff --git a/Angular/assets/CNAME b/Angular/assets/CNAME
deleted file mode 100644
index 396d471f..00000000
--- a/Angular/assets/CNAME
+++ /dev/null
@@ -1 +0,0 @@
-www.example.com
diff --git a/Angular/assets/browserconfig.xml b/Angular/assets/browserconfig.xml
index 9c8fceb5..f63e6aa2 100644
--- a/Angular/assets/browserconfig.xml
+++ b/Angular/assets/browserconfig.xml
@@ -2,11 +2,11 @@
-
-
-
-
-
+
+
+
+
+
#021B79
diff --git a/Angular/assets/logos/icon_180x180.png b/Angular/assets/logos/icon_180x180.png
new file mode 100644
index 00000000..1c4b730c
Binary files /dev/null and b/Angular/assets/logos/icon_180x180.png differ
diff --git a/Angular/assets/logos/icon_76x76.png b/Angular/assets/logos/icon_76x76.png
new file mode 100644
index 00000000..06b76431
Binary files /dev/null and b/Angular/assets/logos/icon_76x76.png differ
diff --git a/Angular/assets/manifest.webmanifest b/Angular/assets/manifest.webmanifest
index 0c451c8f..c18b6ecf 100644
--- a/Angular/assets/manifest.webmanifest
+++ b/Angular/assets/manifest.webmanifest
@@ -1,32 +1,31 @@
{
- "name": "Brand Name",
- "short_name": "brand",
+ "name": "Your Site-Level Website Name Here",
+ "short_name": "brand-name-here",
"lang": "en",
- "description": "description here",
+ "description": "Your site-level description here",
"categories": [
- "CAT 1",
- "CAT 2",
- "CAT 3"
+ "keyword 1",
+ "keyword 2"
],
- "id": "#0000FF",
- "theme_color": "#0000FF",
- "background_color": "#021B79",
+ "id": "/",
+ "start_url": "/",
+ "scope": "/",
"display": "standalone",
"display_override": [
"standalone",
"minimal-ui",
"browser"
],
- "scope": "./",
- "start_url": "./",
"orientation": "any",
- "prefer_related_applications": false,
+ "theme_color": "#0000FF",
+ "background_color": "#021B79",
"protocol_handlers": [
{
"protocol": "web+brand",
"url": "/?query=%s"
}
],
+ "prefer_related_applications": false,
"related_applications": [
{
"id": "/",
@@ -36,140 +35,174 @@
],
"screenshots": [
{
- "label": "Brand Name",
- "platform": "wide",
+ "label": "Welcome",
+ "form_factor": "wide",
"sizes": "1200x630",
- "src": "/logos/icon_512x512.png",
+ "src": "https://www.example.com/screenshots/screenshot-welcome_1200x630.png",
+ "type": "image/png"
+ },
+ {
+ "label": "Welcome",
+ "form_factor": "narrow",
+ "sizes": "630x1200",
+ "src": "https://www.example.com/screenshots/screenshot-welcome_630x1200.png",
+ "type": "image/png"
+ },
+ {
+ "label": "Welcome",
+ "sizes": "1200x1200",
+ "src": "https://www.example.com/screenshots/screenshot-welcome_1200x1200.png",
"type": "image/png"
}
],
"shortcuts": [
{
- "description": "To Main Dashboard",
+ "description": "Dashboard",
"icons": [
{
"purpose": "any",
"sizes": "1200x1200",
- "src": "/logos/icon_1200x1200.png",
+ "src": "https://www.example.com/logos/icon_1200x1200.png",
"type": "image/png"
}
],
- "name": "Home \\u0026 Dashboard",
+ "name": "Dashboard",
"short_name": "Dashboard",
"url": "/"
}
],
"icons": [
{
- "src": "/logos/icon_57x57.png",
+ "src": "https://www.example.com/logos/icon_57x57.png",
"sizes": "57x57",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_60x60.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_60x60.png",
"sizes": "60x60",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_70x70.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_70x70.png",
"sizes": "70x70",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_72x72.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_76x76.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_76x76.png",
"sizes": "76x76",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_96x96.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_114x114.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_114x114.png",
"sizes": "114x114",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_120x120.png",
- "sizes": "96x96",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_120x120.png",
+ "sizes": "120x120",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_128x128.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_144x144.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_144x144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_150x150.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_150x150.png",
"sizes": "150x150",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_152x152.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_152x152.png",
"sizes": "152x152",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_180x180.png",
- "sizes": "152x152",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_180x180.png",
+ "sizes": "180x180",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_192x192.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_310x310.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_310x310.png",
"sizes": "310x310",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_384x384.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_384x384.png",
"sizes": "384x384",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_480x480.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_480x480.png",
"sizes": "480x480",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_512x512.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_1024x1024.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_1024x1024.png",
"sizes": "1024x1024",
"type": "image/png",
"purpose": "any"
- }, {
- "src": "/logos/icon_1200x1200.svg",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_1200x1200.svg",
"sizes": "1200x1200",
"type": "image/svg+xml",
"purpose": "any"
- }, {
- "src": "/logos/icon_1200x1200.png",
+ },
+ {
+ "src": "https://www.example.com/logos/icon_1200x1200.png",
"sizes": "1200x1200",
"type": "image/png",
"purpose": "any"
- }, {
- "purpose": "maskable any",
+ },
+ {
+ "src": "https://www.example.com/logos/icon-monochrome_1200x1200.svg",
"sizes": "1200x1200",
- "src": "/logos/icon-monochrome_1200x1200.svg",
- "type": "image/svg+xml"
+ "type": "image/svg+xml",
+ "purpose": "maskable"
}
]
-}
+}
\ No newline at end of file
diff --git a/Angular/assets/robots.txt b/Angular/assets/robots.txt
index c2a49f4f..7864a4f3 100644
--- a/Angular/assets/robots.txt
+++ b/Angular/assets/robots.txt
@@ -1,2 +1,3 @@
+Sitemap: https://www.example.com/sitemap.xml
User-agent: *
Allow: /
diff --git a/Angular/assets/screenshots/screenshot-welcome_1200x1200.png b/Angular/assets/screenshots/screenshot-welcome_1200x1200.png
new file mode 100644
index 00000000..871d70c9
Binary files /dev/null and b/Angular/assets/screenshots/screenshot-welcome_1200x1200.png differ
diff --git a/Angular/assets/screenshots/screenshot-welcome_1200x630.png b/Angular/assets/screenshots/screenshot-welcome_1200x630.png
new file mode 100644
index 00000000..b5226a40
Binary files /dev/null and b/Angular/assets/screenshots/screenshot-welcome_1200x630.png differ
diff --git a/Angular/assets/screenshots/screenshot-welcome_630x1200.png b/Angular/assets/screenshots/screenshot-welcome_630x1200.png
new file mode 100644
index 00000000..1a75e7c8
Binary files /dev/null and b/Angular/assets/screenshots/screenshot-welcome_630x1200.png differ
diff --git a/Angular/assets/sitemap.xml b/Angular/assets/sitemap.xml
new file mode 100644
index 00000000..823a5ad1
--- /dev/null
+++ b/Angular/assets/sitemap.xml
@@ -0,0 +1,7 @@
+
+
+
+ https://www.example.com/sitemaps/sitemap-page-1.xml
+ 2024-10-29T13:29:38+08:00
+
+
diff --git a/Angular/assets/sitemaps/sitemap-page-1.xml b/Angular/assets/sitemaps/sitemap-page-1.xml
new file mode 100644
index 00000000..eadfa8c9
--- /dev/null
+++ b/Angular/assets/sitemaps/sitemap-page-1.xml
@@ -0,0 +1,11 @@
+
+
+
+ https://www.example.com/
+ 2024-10-29T13:29:38+08:00
+
+
+ https://www.example.com/en
+ 2024-10-29T13:29:38+08:00
+
+
diff --git a/Angular/assets/thumbnails/default_1200x1200.png b/Angular/assets/thumbnails/default_1200x1200.png
new file mode 100644
index 00000000..871d70c9
Binary files /dev/null and b/Angular/assets/thumbnails/default_1200x1200.png differ
diff --git a/Angular/assets/thumbnails/default_1200x630.png b/Angular/assets/thumbnails/default_1200x630.png
new file mode 100644
index 00000000..b5226a40
Binary files /dev/null and b/Angular/assets/thumbnails/default_1200x630.png differ
diff --git a/Angular/assets/thumbnails/default_480x480.png b/Angular/assets/thumbnails/default_480x480.png
new file mode 100644
index 00000000..886c70b4
Binary files /dev/null and b/Angular/assets/thumbnails/default_480x480.png differ
diff --git a/Angular/build.sh.ps1 b/Angular/build.sh.ps1
new file mode 100755
index 00000000..b4266a7b
--- /dev/null
+++ b/Angular/build.sh.ps1
@@ -0,0 +1,52 @@
+echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#"
+@ECHO OFF
+REM LICENSE CLAUSES HERE
+REM ----------------------------------------------------------------------------
+
+
+
+
+REM ############################################################################
+REM # Windows BATCH Codes #
+REM ############################################################################
+echo "[ ERROR ] --> powershell.exe !!!"
+exit /b 1
+REM ############################################################################
+REM # Windows BATCH Codes #
+REM ############################################################################
+RUN_AS_BATCH
+#> | Out-Null
+
+
+
+
+echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null
+################################################################################
+# Windows POWERSHELL Codes #
+################################################################################
+# execute
+$null = . ".\init.sh.ps1"
+$null = Clear-Host
+$null = ng build --configuration production
+################################################################################
+# Windows POWERSHELL Codes #
+################################################################################
+exit
+<#
+RUN_AS_POWERSHELL
+
+
+
+
+################################################################################
+# Unix Main Codes #
+################################################################################
+# execute
+. "./init.sh.ps1"
+clear
+ng build --configuration production
+################################################################################
+# Unix Main Codes #
+################################################################################
+exit $?
+#>
diff --git a/Angular/init.browserconfig-xml.ts b/Angular/init.browserconfig-xml.ts
new file mode 100644
index 00000000..61279829
--- /dev/null
+++ b/Angular/init.browserconfig-xml.ts
@@ -0,0 +1,52 @@
+/*
+ * COPYRIGHT LICENSE NOTICE HERE
+ */
+import { Get_Base_URL, METADATA_SITE, Yield_URL } from './init.metadata';
+import * as fs from 'fs';
+
+
+
+
+/* exported function for creating the browserconfig.xml file */
+export function Create_Browser_Config_XML() {
+ const dir_build = 'assets';
+ const filepath = dir_build + '/' + 'browserconfig.xml';
+
+
+ /* bail if file exists */
+ try {
+ if (fs.existsSync(filepath)) {
+ return;
+ }
+ } catch {
+ ;
+ }
+
+
+ /* create directory */
+ if (!fs.existsSync(dir_build)) {
+ fs.mkdirSync(dir_build, { recursive: true });
+ }
+
+
+ /* create new file */
+ let data = Get_Base_URL();
+ fs.writeFileSync(filepath,`
+
+
+
+
+
+
+
+
+ ${METADATA_SITE.Color_Theme_Background}
+
+
+
+`);
+
+
+ /* report status */
+ console.log(`✓ ${filepath} generated successfully.`);
+}
diff --git a/Angular/init.cname.ts b/Angular/init.cname.ts
new file mode 100644
index 00000000..b7de6bda
--- /dev/null
+++ b/Angular/init.cname.ts
@@ -0,0 +1,45 @@
+/*
+ * COPYRIGHT LICENSE NOTICE HERE
+ */
+import { Get_Base_URL, METADATA_SITE } from './init.metadata';
+import * as fs from 'fs';
+
+
+
+
+const data = ''; // override the content here
+
+
+
+
+/* exported function for creating the CNAME configuration file */
+export function Create_CNAME() {
+ const dir_build = 'assets';
+ const filepath = dir_build + '/' + 'CNAME';
+
+
+ /* bail if file exists */
+ try {
+ if (fs.existsSync(filepath)) {
+ return;
+ }
+ } catch {
+ ;
+ }
+
+
+ /* create directory */
+ if (!fs.existsSync(dir_build)) {
+ fs.mkdirSync(dir_build, { recursive: true });
+ }
+
+
+ /* create new file */
+ if (data) {
+ fs.writeFileSync(filepath, data);
+ }
+
+
+ /* report status */
+ console.log(`✓ ${filepath} generated successfully.`);
+}
diff --git a/Angular/init.metadata.ts b/Angular/init.metadata.ts
new file mode 100644
index 00000000..30ee0b53
--- /dev/null
+++ b/Angular/init.metadata.ts
@@ -0,0 +1,106 @@
+/*
+ * COPYRIGHT LICENSE NOTICE HERE
+ */
+import * as fs from 'fs';
+import { join } from 'path';
+
+
+
+
+export const METADATA_SITE = {
+ Name: {
+ "en": "Your Site-Level Website Name Here",
+ },
+ SKU: "brand-name-here",
+ ID: "", // example: com.example.www.project
+ Description: {
+ "en": "Your site-level description here",
+ },
+ Keywords: {
+ "en": [
+ "keyword 1",
+ "keyword 2",
+ ],
+ },
+ Color_Theme_Foreground: "#0000FF",
+ Color_Theme_Background: "#021B79",
+ Owner: [{
+ "en": {
+ Call_Sign: "any call sign or nickname",
+ Title: "any given recongized title",
+ Family_Name: "first name",
+ Given_Name: "last name",
+ Brand: "any associated trademark or brand",
+ Description: "internal description here",
+ Slogan: "the owner's tagline",
+ Contacts: {
+ Email: "name@domain.tld",
+ Facebook: "https://www.facebook.com/USERNAME",
+ BlueSky: "https://bsky.app/profile/USERNAME",
+ Instagram: "https://www.instagram.com/USERNAME",
+ Mastodon: "https://[SERVER]/@USERNAME",
+ Call: "tel:123456789",
+ WhatsApp: "https://wa.me/123456789",
+ Telegram: "https://t.me/[LINK_OR_PHONE_NUMBER]"
+ },
+ Roles: [
+ "Creator",
+ "Contact",
+ "Artwork",
+ "Knowledge",
+ "Editor",
+ "Developer",
+ "Maintainer",
+ "Owner",
+ "Producer",
+ "Provider",
+ "Publisher",
+ "Reviewer",
+ "Funder",
+ "Sponsor"
+ ],
+ }
+ }],
+};
+
+
+
+
+export function Get_Base_URL(): string {
+ try {
+ // Read angular.json file
+ const filepath = join(process.cwd(), 'angular.json');
+ const file_content = fs.readFileSync(filepath, 'utf-8');
+
+ // Parse JSON safely
+ const json = JSON.parse(file_content);
+
+ // Get first project key if project name not specified
+ const keys = Object.keys(json.projects || {});
+ if (keys.length === 0) {
+ console.warn('No projects found in angular.json');
+ return '';
+ }
+ const project_key = keys[0];
+ const project = json.projects[project_key];
+
+ // Safely navigate the object structure
+ const url = project?.architect?.build?.configurations?.production?.baseHref;
+
+ // make sure the base url is the correct type and without tailing slash
+ if (typeof url === 'string') {
+ return url.replace(/\/$/, "");
+ }
+ } catch (error) {
+ console.warn('Error reading baseHref from angular.json:', error);
+ }
+
+ return '';
+}
+
+
+
+
+export function Yield_URL(path: string, base_url: string): string {
+ return base_url.replace(/\/$/, "") + '/' + path.replace(/^\//, "");
+}
diff --git a/Angular/init.no-jekyll.ts b/Angular/init.no-jekyll.ts
new file mode 100644
index 00000000..1be8d615
--- /dev/null
+++ b/Angular/init.no-jekyll.ts
@@ -0,0 +1,37 @@
+/*
+ * COPYRIGHT LICENSE NOTICE HERE
+ */
+import * as fs from 'fs';
+
+
+
+
+/* exported function for creating the .nojekyll file */
+export function Create_No_Jekyll() {
+ const dir_build = 'assets';
+ const filepath = dir_build + '/' + '.nojekyll';
+
+
+ /* bail if file exists */
+ try {
+ if (fs.existsSync(filepath)) {
+ return;
+ }
+ } catch {
+ ;
+ }
+
+
+ /* create directory */
+ if (!fs.existsSync(dir_build)) {
+ fs.mkdirSync(dir_build, { recursive: true });
+ }
+
+
+ /* create new file */
+ fs.writeFileSync(filepath, 'No Jekyll');
+
+
+ /* report status */
+ console.log(`✓ ${filepath} generated successfully.`);
+}
diff --git a/Angular/init.pwa.ts b/Angular/init.pwa.ts
new file mode 100644
index 00000000..853abec8
--- /dev/null
+++ b/Angular/init.pwa.ts
@@ -0,0 +1,267 @@
+/*
+ * COPYRIGHT LICENSE NOTICE HERE
+ */
+import { Get_Base_URL, METADATA_SITE, Yield_URL } from './init.metadata';
+import * as fs from 'fs';
+
+
+
+
+/* generate manifest.webmanifest with site data */
+function generate_web_manifest(): any {
+ const base = Get_Base_URL();
+
+
+ /* create default settings */
+ var manifest = {
+ name: "TITLE",
+ short_name: "BRAND",
+ lang: "en",
+ description: "DESCRIPTION",
+ categories: [
+ "website",
+ "webapp",
+ "app",
+ ],
+ id: "/",
+ start_url: "/",
+ scope: "/",
+ display: "standalone",
+ display_override: [
+ "standalone",
+ "minimal-ui",
+ "browser"
+ ],
+ orientation: "any",
+ theme_color: "#0000FF",
+ background_color: "#021B79",
+ protocol_handlers: [
+ { protocol: "web+brand", url: "/?query=%s" },
+ ],
+ prefer_related_applications: false,
+ related_applications: [{
+ id: "/",
+ platform: "webapp",
+ url: "/"
+ }],
+ screenshots: [{
+ label: "Welcome",
+ form_factor: "wide",
+ sizes: "1200x630",
+ src: Yield_URL("/screenshots/screenshot-welcome_1200x630.png", base),
+ type: "image/png"
+ }, {
+ label: "Welcome",
+ form_factor: "narrow",
+ sizes: "630x1200",
+ src: Yield_URL("/screenshots/screenshot-welcome_630x1200.png", base),
+ type: "image/png"
+ }, {
+ label: "Welcome",
+ sizes: "1200x1200",
+ src: Yield_URL("/screenshots/screenshot-welcome_1200x1200.png", base),
+ type: "image/png"
+ }],
+ shortcuts: [{
+ description: "Dashboard",
+ icons: [{
+ purpose: "any",
+ sizes: "1200x1200",
+ src: Yield_URL("/logos/icon_1200x1200.png", base),
+ type: "image/png"
+ }],
+ name: "Dashboard",
+ short_name: "Dashboard",
+ url: "/"
+ }],
+ icons: [{
+ src: Yield_URL("/logos/icon_57x57.png", base),
+ sizes: "57x57",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_60x60.png", base),
+ sizes: "60x60",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_70x70.png", base),
+ sizes: "70x70",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_72x72.png", base),
+ sizes: "72x72",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_76x76.png", base),
+ sizes: "76x76",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_96x96.png", base),
+ sizes: "96x96",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_114x114.png", base),
+ sizes: "114x114",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_120x120.png", base),
+ sizes: "120x120",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_128x128.png", base),
+ sizes: "128x128",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_144x144.png", base),
+ sizes: "144x144",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_150x150.png", base),
+ sizes: "150x150",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_152x152.png", base),
+ sizes: "152x152",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_180x180.png", base),
+ sizes: "180x180",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_192x192.png", base),
+ sizes: "192x192",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_310x310.png", base),
+ sizes: "310x310",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_384x384.png", base),
+ sizes: "384x384",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_480x480.png", base),
+ sizes: "480x480",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_512x512.png", base),
+ sizes: "512x512",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_1024x1024.png", base),
+ sizes: "1024x1024",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_1200x1200.svg", base),
+ sizes: "1200x1200",
+ type: "image/svg+xml",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon_1200x1200.png", base),
+ sizes: "1200x1200",
+ type: "image/png",
+ purpose: "any"
+ }, {
+ src: Yield_URL("/logos/icon-monochrome_1200x1200.svg", base),
+ sizes: "1200x1200",
+ type: "image/svg+xml",
+ purpose: "maskable"
+ }]
+ }
+
+
+ /* check and overrides */
+ if (!METADATA_SITE) {
+ return manifest;
+ }
+
+ if (METADATA_SITE.Name) {
+ if (METADATA_SITE.Name.en) {
+ manifest.name = METADATA_SITE.Name.en;
+ }
+ }
+
+ if (METADATA_SITE.SKU) {
+ manifest.short_name = METADATA_SITE.SKU;
+ }
+
+ if (METADATA_SITE.Description) {
+ if (METADATA_SITE.Description.en) {
+ manifest.description = METADATA_SITE.Description.en;
+ }
+ }
+
+ if (METADATA_SITE.Keywords) {
+ if (METADATA_SITE.Keywords.en) {
+ manifest.categories = METADATA_SITE.Keywords.en;
+ }
+ }
+
+ if (METADATA_SITE.Color_Theme_Foreground) {
+ manifest.theme_color = METADATA_SITE.Color_Theme_Foreground;
+ }
+
+ if (METADATA_SITE.Color_Theme_Background) {
+ manifest.background_color = METADATA_SITE.Color_Theme_Background;
+ }
+
+ if (METADATA_SITE.ID) {
+ manifest.id = METADATA_SITE.ID;
+ }
+
+
+ /* return output */
+ return manifest;
+}
+
+
+
+
+/* exported function for creating the web manifest file */
+export function Create_Web_Manifest() {
+ const dir_build = 'assets';
+ const filepath = dir_build + '/' + 'manifest.webmanifest';
+
+
+ /* bail if file exists */
+ try {
+ if (fs.existsSync(filepath)) {
+ return;
+ }
+ } catch {
+ ;
+ }
+
+
+ /* create directory */
+ if (!fs.existsSync(dir_build)) {
+ fs.mkdirSync(dir_build, { recursive: true });
+ }
+
+
+ /* create new file */
+ const data = generate_web_manifest();
+ fs.writeFileSync(filepath, JSON.stringify(data, null, 2));
+
+
+ /* report status */
+ console.log(`✓ ${filepath} generated successfully.`);
+}
diff --git a/Angular/init.seo.ts b/Angular/init.seo.ts
new file mode 100644
index 00000000..f91bb154
--- /dev/null
+++ b/Angular/init.seo.ts
@@ -0,0 +1,304 @@
+/*
+ * COPYRIGHT LICENSE NOTICE HERE
+ */
+import { Get_Base_URL, Yield_URL } from './init.metadata';
+import * as fs from 'fs';
+import * as path from 'path';
+
+
+
+
+// add your url here
+const url_add: string[] = [
+];
+
+// remove your url here
+const url_remove: string[] = [
+ '/404',
+];
+
+// robots.txt policy here
+// NOTICE: DO NOT add 'Sitemap:'. It will be added automatically when available.
+const robots_policy = `
+User-agent: *
+Allow: /
+`
+
+
+
+function time_pad(n: number) {
+ return n < 10 ? '0' + n : n;
+}
+
+
+
+
+function time_timezone_offset(offset: number) {
+ if (offset === 0) {
+ return 'Z';
+}
+
+ const sign = offset > 0 ? '-' : '+';
+ offset = Math.abs(offset);
+
+ return sign + time_pad(Math.floor(offset / 60)) + ':' + time_pad(offset % 60);
+}
+
+
+
+
+function time_get_current_RFC3339(date: Date): string {
+ return (
+ date.getFullYear() +
+ '-' +
+ time_pad(date.getMonth() + 1) +
+ '-' +
+ time_pad(date.getDate()) +
+ 'T' +
+ time_pad(date.getHours()) +
+ ':' +
+ time_pad(date.getMinutes()) +
+ ':' +
+ time_pad(date.getSeconds()) +
+ time_timezone_offset(date.getTimezoneOffset())
+ );
+}
+
+
+
+
+const sitemap_capacity_limit = 50000;
+var time_updated = time_get_current_RFC3339(new Date());
+
+
+
+function create_sitemaps_page(directory: string, url_base: string, list: string[]): string[] {
+ // filename: sitemap-page-%d.xml
+ const filename = 'sitemap-page-';
+ var count_sitemap = 0;
+ const extension = '.xml';
+
+ var count_url = sitemap_capacity_limit; // note: to spin immediately
+ var url_path = '';
+ var filepath = '';
+ var list_sitemaps: string[] = [];
+
+ const header = `
+
+`;
+ const seal = `\n`
+
+
+ // validate before start
+ if (list.length <= 0) {
+ return list_sitemaps;
+ }
+
+
+ // loop through urls
+ for (var i = 0; i < list.length; i++) {
+ if (count_url >= sitemap_capacity_limit) {
+ // seal the existing sitemap
+ if (count_sitemap > 0) {
+ fs.appendFileSync(filepath, seal);
+ }
+
+
+ // spin a new sitemap
+ count_sitemap++;
+ count_url = 0;
+ filepath = filename + String(count_sitemap) + extension;
+ url_path = Yield_URL(filepath, url_base);
+ filepath = path.join(directory, filepath);
+
+
+ // write the header
+ fs.appendFileSync(filepath, header);
+
+
+ // register into sitemaps list
+ list_sitemaps.push(url_path);
+ }
+
+
+ // append url entry
+ fs.appendFileSync(filepath,
+`
+ ${list[i]}
+ ${time_updated}
+
+`);
+ }
+
+ // seal the last sitemap
+ fs.appendFileSync(filepath, seal);
+
+
+ // report status
+ return list_sitemaps;
+}
+
+
+
+
+function create_sitemaps_index(filepath: string, list: string[]) {
+ const header = `
+
+`;
+ const seal = `\n`
+
+
+ // validate before start
+ if (list.length <= 0) {
+ return;
+ }
+
+
+ // write the header
+ fs.appendFileSync(filepath, header);
+
+
+ // loop through urls
+ for (var i = 0; i < list.length; i++) {
+ fs.appendFileSync(filepath,
+`
+ ${list[i]}
+ ${time_updated}
+
+`);
+ }
+
+
+ // seal the last sitemap
+ fs.appendFileSync(filepath, seal);
+}
+
+
+
+
+function create_robots(filepath: string, sitemap_url: string) {
+ // write sitemap if available
+ if (sitemap_url) {
+ fs.appendFileSync(filepath, `Sitemap: ${sitemap_url}`);
+ }
+
+ // append the policy
+ fs.appendFileSync(filepath, robots_policy);
+}
+
+
+
+
+/* exported function for creating the seo configuration files */
+export function Create_SEO() {
+ const source_file = 'prerender-routes.txt';
+ const filename_sitemap = 'sitemap.xml';
+ const filename_robots = 'robots.txt';
+
+ const dir_sitemaps = 'sitemaps';
+ const dir_sitemaps_build = `assets/${dir_sitemaps}`;
+
+ const filepath_sitemap = `assets/${filename_sitemap}`;
+ const filepath_robots = `assets/${filename_robots}`;
+
+
+ /* bail if source file is missing */
+ try {
+ if (!fs.existsSync(source_file)) {
+ return;
+ }
+ } catch {
+ ;
+ }
+
+
+ /* bail if file exists */
+ try {
+ if (fs.existsSync(dir_sitemaps_build)) {
+ return;
+ }
+
+ if (fs.existsSync(filepath_sitemap)) {
+ return;
+ }
+
+ if (fs.existsSync(filepath_robots)) {
+ return;
+ }
+ } catch {
+ ;
+ }
+
+
+ /* parse urls from prerender-routes.txt */
+ var base = Get_Base_URL();
+ var sources = fs.readFileSync(source_file).toString().split("\n");
+ var list: string[] = [];
+ for (var i = 0; i < sources.length; i++) {
+ if (!sources[i]) {
+ continue
+ }
+
+ list[i] = Yield_URL(sources[i], base);
+ }
+
+
+ /* add urls from url_add */
+ for (var i = 0; i < url_add.length; i++) {
+ if (!url_add[i]) {
+ continue
+ }
+
+ list.push(Yield_URL(sources[i], base));
+ }
+
+
+ /* remove duplicated urls */
+ list.filter((x, i, a) => a.indexOf(x) == i);
+
+
+ /* remove urls from url_remove */
+ for (var i = 0; i < url_remove.length; i++) {
+ if (!url_remove[i]) {
+ continue
+ }
+
+ let target = Yield_URL(url_remove[i], base);
+ list = list.filter((sample) => sample != target);
+ }
+
+
+ /* validate list before proceeding */
+ if (list.length <= 0) {
+ create_robots(filepath_robots, '');
+ return; /* no url - bail */
+ }
+
+
+ /* update sitemap baseline url */
+ let url_sitemap = Yield_URL(filename_sitemap, base);
+ base = Yield_URL(`/${dir_sitemaps}`, base);
+
+
+ /* create directory */
+ if (!fs.existsSync(dir_sitemaps_build)) {
+ fs.mkdirSync(dir_sitemaps_build, { recursive: true });
+ }
+
+
+ /* create page sitemaps */
+ var sitemaps = create_sitemaps_page(dir_sitemaps_build, base, list);
+
+
+ /* create index sitemaps */
+ create_sitemaps_index(filepath_sitemap, sitemaps);
+
+
+ /* create robots.txt */
+ create_robots(filepath_robots, url_sitemap);
+
+
+ /* report status */
+ console.log(`✓ ${filepath_sitemap} generated successfully.`);
+ console.log(`✓ ${filepath_robots} generated successfully.`);
+}
diff --git a/Angular/init.sh.ps1 b/Angular/init.sh.ps1
new file mode 100644
index 00000000..635e89a0
--- /dev/null
+++ b/Angular/init.sh.ps1
@@ -0,0 +1,76 @@
+echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#"
+@ECHO OFF
+REM LICENSE CLAUSES HERE
+REM ----------------------------------------------------------------------------
+
+
+
+
+REM ############################################################################
+REM # Windows BATCH Codes #
+REM ############################################################################
+echo "[ ERROR ] --> powershell.exe !!!"
+exit /b 1
+REM ############################################################################
+REM # Windows BATCH Codes #
+REM ############################################################################
+RUN_AS_BATCH
+#> | Out-Null
+
+
+
+
+echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null
+################################################################################
+# Windows POWERSHELL Codes #
+################################################################################
+# execute
+$null = Write-Host "clean-ing up existing configuration files..."
+$null = Remove-Item -Force ".\assets\manifest.webmanifest" -ErrorAction SilentlyContinue
+$null = Remove-Item -Force ".\assets\CNAME" -ErrorAction SilentlyContinue
+$null = Remove-Item -Recursive -Force ".\assets\sitemaps" -ErrorAction SilentlyContinue
+$null = Remove-Item -Force ".\assets\sitemap.xml" -ErrorAction SilentlyContinue
+$null = Remove-Item -Force ".\assets\robots.txt" -ErrorAction SilentlyContinue
+$null = Remove-Item -Force ".\assets\browserconfig.xml" -ErrorAction SilentlyContinue
+$null = Remove-Item -Force ".\assets\.nojekyll" -ErrorAction SilentlyContinue
+
+
+$null = Write-Host "initializing the repository..."
+$null = ng build --aot --configuration production | Out-Null
+$null = Remove-Item -Recurse -Force ".\dist" -ErrorAction SilentlyContinue
+$null = [System.IO.File]::FlushAll()
+return
+################################################################################
+# Windows POWERSHELL Codes #
+################################################################################
+exit
+<#
+RUN_AS_POWERSHELL
+
+
+
+
+################################################################################
+# Unix Main Codes #
+################################################################################
+# execute
+1>&2 printf -- "%s\n" "clean-ing up existing configuration files..."
+rm "./assets/manifest.webmanifest" &> /dev/null
+rm "./assets/CNAME" &> /dev/null
+rm -r "./assets/sitemaps/" &> /dev/null
+rm "./assets/sitemap.xml" &> /dev/null
+rm "./assets/robots.txt" &> /dev/null
+rm "./assets/browserconfig.xml" &> /dev/null
+rm "./assets/.nojekyll" &> /dev/null
+
+
+1>&2 printf -- "%s\n" "initializing the repository..."
+ng build --aot --configuration production --server main.server.ts &> /dev/null
+rm -rf "./dist/" &> /dev/null
+sync
+return 0
+################################################################################
+# Unix Main Codes #
+################################################################################
+exit $?
+#>
diff --git a/Angular/main.server.ts b/Angular/main.server.ts
index 2d9c2a45..d6d345e0 100644
--- a/Angular/main.server.ts
+++ b/Angular/main.server.ts
@@ -4,13 +4,25 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { config } from './app.config.server';
import { App } from './app';
+import { Create_Web_Manifest } from './init.pwa';
+import { Create_CNAME } from './init.cname';
+import { Create_SEO } from './init.seo';
+import { Create_Browser_Config_XML } from './init.browserconfig-xml';
+import { Create_No_Jekyll } from './init.no-jekyll';
-const bootstrap = () => bootstrapApplication(App, config);
+/* initializing project's dynamic configurations */
+Create_CNAME();
+Create_Web_Manifest();
+Create_SEO();
+Create_Browser_Config_XML();
+Create_No_Jekyll();
+/* main code */
+const bootstrap = () => bootstrapApplication(App, config);
export default bootstrap;
diff --git a/Angular/main.ts b/Angular/main.ts
index 7ea9e48d..1658f6f3 100644
--- a/Angular/main.ts
+++ b/Angular/main.ts
@@ -8,5 +8,6 @@ import { App } from './app';
+/* main code */
bootstrapApplication(App, appConfig)
.catch((err) => console.error(err));
diff --git a/Angular/ngsw-config.json b/Angular/ngsw-config.json
index 4d80eea7..60176243 100644
--- a/Angular/ngsw-config.json
+++ b/Angular/ngsw-config.json
@@ -7,9 +7,13 @@
"installMode": "prefetch",
"resources": {
"files": [
- "/favicon.ico",
"/index.html",
"/manifest.webmanifest",
+ "/logos/**",
+ "/css/**",
+ "/js/**",
+ "/thumbnails/**",
+ "/screenshots/**",
"/*.css",
"/*.js"
]
@@ -21,8 +25,7 @@
"updateMode": "prefetch",
"resources": {
"files": [
- "/assets/**",
- "/media/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
+ "/**"
]
}
}
diff --git a/Angular/package.json b/Angular/package.json
index c92a0195..d715d46a 100644
--- a/Angular/package.json
+++ b/Angular/package.json
@@ -3,10 +3,10 @@
"version": "0.0.0",
"scripts": {
"ng": "ng",
- "start": "clear && ng serve",
- "build": "clear && ng build",
- "watch": "clear && ng build --watch --configuration development",
- "test": "clear && ng test --no-watch --code-coverage --browsers ChromeHeadless",
+ "build": "./build.sh.ps1",
+ "start": "./serve.sh.ps1",
+ "test": "./test.sh.ps1",
+ "watch": "./watch.sh.ps1",
"serve:ssr:app": "node dist/app/server/server.mjs"
},
"private": true,
diff --git a/Angular/serve.sh.ps1 b/Angular/serve.sh.ps1
new file mode 100755
index 00000000..2e816926
--- /dev/null
+++ b/Angular/serve.sh.ps1
@@ -0,0 +1,52 @@
+echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#"
+@ECHO OFF
+REM LICENSE CLAUSES HERE
+REM ----------------------------------------------------------------------------
+
+
+
+
+REM ############################################################################
+REM # Windows BATCH Codes #
+REM ############################################################################
+echo "[ ERROR ] --> powershell.exe !!!"
+exit /b 1
+REM ############################################################################
+REM # Windows BATCH Codes #
+REM ############################################################################
+RUN_AS_BATCH
+#> | Out-Null
+
+
+
+
+echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null
+################################################################################
+# Windows POWERSHELL Codes #
+################################################################################
+# execute
+$null = . ".\init.sh.ps1"
+$null = Clear-Host
+$null = ng serve --configuration production
+################################################################################
+# Windows POWERSHELL Codes #
+################################################################################
+exit
+<#
+RUN_AS_POWERSHELL
+
+
+
+
+################################################################################
+# Unix Main Codes #
+################################################################################
+# execute
+. "./init.sh.ps1"
+clear
+ng serve --configuration production
+################################################################################
+# Unix Main Codes #
+################################################################################
+exit $?
+#>
diff --git a/Angular/test.sh.ps1 b/Angular/test.sh.ps1
new file mode 100755
index 00000000..47642757
--- /dev/null
+++ b/Angular/test.sh.ps1
@@ -0,0 +1,52 @@
+echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#"
+@ECHO OFF
+REM LICENSE CLAUSES HERE
+REM ----------------------------------------------------------------------------
+
+
+
+
+REM ############################################################################
+REM # Windows BATCH Codes #
+REM ############################################################################
+echo "[ ERROR ] --> powershell.exe !!!"
+exit /b 1
+REM ############################################################################
+REM # Windows BATCH Codes #
+REM ############################################################################
+RUN_AS_BATCH
+#> | Out-Null
+
+
+
+
+echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null
+################################################################################
+# Windows POWERSHELL Codes #
+################################################################################
+# execute
+$null = . ".\init.sh.ps1"
+$null = Clear-Host
+$null = ng test --no-watch --code-coverage --browsers ChromeHeadless
+################################################################################
+# Windows POWERSHELL Codes #
+################################################################################
+exit
+<#
+RUN_AS_POWERSHELL
+
+
+
+
+################################################################################
+# Unix Main Codes #
+################################################################################
+# execute
+. "./init.sh.ps1"
+clear
+ng test --no-watch --code-coverage --browsers ChromeHeadless
+################################################################################
+# Unix Main Codes #
+################################################################################
+exit $?
+#>
diff --git a/Angular/watch.sh.ps1 b/Angular/watch.sh.ps1
new file mode 100755
index 00000000..64a43606
--- /dev/null
+++ b/Angular/watch.sh.ps1
@@ -0,0 +1,52 @@
+echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#"
+@ECHO OFF
+REM LICENSE CLAUSES HERE
+REM ----------------------------------------------------------------------------
+
+
+
+
+REM ############################################################################
+REM # Windows BATCH Codes #
+REM ############################################################################
+echo "[ ERROR ] --> powershell.exe !!!"
+exit /b 1
+REM ############################################################################
+REM # Windows BATCH Codes #
+REM ############################################################################
+RUN_AS_BATCH
+#> | Out-Null
+
+
+
+
+echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null
+################################################################################
+# Windows POWERSHELL Codes #
+################################################################################
+# execute
+$null = . ".\init.sh.ps1"
+$null = Clear-Host
+$null = ng build --watch --configuration development
+################################################################################
+# Windows POWERSHELL Codes #
+################################################################################
+exit
+<#
+RUN_AS_POWERSHELL
+
+
+
+
+################################################################################
+# Unix Main Codes #
+################################################################################
+# execute
+. "./init.sh.ps1"
+clear
+ng build --watch --configuration development
+################################################################################
+# Unix Main Codes #
+################################################################################
+exit $?
+#>