diff --git a/.github/workflows/deploy-frontend-dev.yml b/.github/workflows/deploy-frontend-dev.yml index fce6e86f5..682acd5bd 100644 --- a/.github/workflows/deploy-frontend-dev.yml +++ b/.github/workflows/deploy-frontend-dev.yml @@ -1,4 +1,4 @@ -name: DeployFrontendDev +name: DeployFrontendServerlessDev on: workflow_run: @@ -28,13 +28,29 @@ jobs: role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/github-actions-frontend-access aws-region: ap-south-1 - - name: Build frontend and copy to S3 + - name: Build frontend and copy zip to S3 run: | cd nuxt-frontend sed -i "s|VITE_RECAPTCHA_SITE_KEY_VALUE|${{ secrets.RECAPTCHA_SITE_KEY }}|g" config.js sed -i "s|RESOURCES_URL|${{ secrets.RESOURCES_URL }}|g" config.js + sed -i "s|CLOUDFRONT_URL_VALUE|${{ secrets.CLOUDFRONT_URL_VALUE_DEV }}|g" config.js sh ./../deploy/generate-sitemap.sh https://dev-stack.canopas.com https://dev-stack-api.canopas.com - yarn install --frozen-lockfile && yarn generate - aws s3 sync ./.output/public s3://dev-stack.canopas.com --exclude "*.js" - aws s3 sync ./.output/public s3://dev-stack.canopas.com --include "*.js" --content-type "application/javascript" - aws cloudfront create-invalidation --distribution-id ${{ secrets.DEV_CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*" \ No newline at end of file + yarn install --frozen-lockfile && yarn build + aws s3 rm s3://canopas-website-ssr-dev --recursive + cd .output/server && zip canopas_website_SSR_dev_${{ github.sha }}-${{ github.run_attempt }}.zip -r . && aws s3 cp canopas_website_SSR_dev_${{ github.sha }}-${{ github.run_attempt }}.zip s3://canopas-lambda-handlers && cd ../.. + aws s3 sync --cache-control 'max-age=604800' --exclude *.html ./.output/public s3://canopas-website-ssr-dev + aws s3 sync ./.output/public s3://canopas-website-ssr-dev + + - name: Deploy cloudformation stack + id: canopas-website-dev-lambda-stack-frontend + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: canopas-website-dev-lambda-stack-frontend + template: infrastructure/frontend.yml + capabilities: CAPABILITY_IAM,CAPABILITY_NAMED_IAM, CAPABILITY_AUTO_EXPAND + timeout-in-minutes: "10" + no-fail-on-empty-changeset: "1" + parameter-overrides: >- + EnvName=dev, + ZipFileName=canopas_website_SSR_dev_${{ github.sha }}-${{ github.run_attempt }}.zip, + CloudfrontURL=${{ secrets.CLOUDFRONT_URL_VALUE_DEV }} diff --git a/.github/workflows/deploy-frontend-prod.yml b/.github/workflows/deploy-frontend-prod.yml index b48df7463..38c924373 100644 --- a/.github/workflows/deploy-frontend-prod.yml +++ b/.github/workflows/deploy-frontend-prod.yml @@ -1,4 +1,4 @@ -name: DeployFrontendProd +name: DeployFrontendServerlessProd on: workflow_run: @@ -28,14 +28,30 @@ jobs: role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/github-actions-frontend-access aws-region: ap-south-1 - - name: Build frontend and copy to S3 + - name: Build frontend and copy zip to S3 run: | cd nuxt-frontend sed -i "s|VITE_RECAPTCHA_SITE_KEY_VALUE|${{ secrets.RECAPTCHA_SITE_KEY }}|g" config.prod.js sed -i "s|RESOURCES_URL|${{ secrets.RESOURCES_URL }}|g" config.prod.js + sed -i "s|CLOUDFRONT_URL_VALUE|${{ secrets.CLOUDFRONT_URL_VALUE_PROD }}|g" config.prod.js mv config.prod.js config.js sh ./../deploy/generate-sitemap.sh https://canopas.com https://prod-stack-api.canopas.com - yarn install --frozen-lockfile && yarn generate - aws s3 sync ./.output/public s3://canopas.com --exclude "*.js" - aws s3 sync ./.output/public s3://canopas.com --include "*.js" --content-type "application/javascript" - aws cloudfront create-invalidation --distribution-id ${{ secrets.PROD_CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*" \ No newline at end of file + yarn install --frozen-lockfile && yarn build + aws s3 rm s3://canopas-website-ssr-prod --recursive + cd .output/server && zip canopas_website_SSR_prod_${{ github.sha }}-${{ github.run_attempt }}.zip -r . && aws s3 cp canopas_website_SSR_prod_${{ github.sha }}-${{ github.run_attempt }}.zip s3://canopas-lambda-handlers && cd ../.. + aws s3 sync --cache-control 'max-age=604800' --exclude *.html ./.output/public s3://canopas-website-ssr-prod + aws s3 sync ./.output/public s3://canopas-website-ssr-prod + + - name: Deploy cloudformation stack + id: canopas-website-prod-lambda-stack-frontend + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: canopas-website-prod-lambda-stack-frontend + template: infrastructure/frontend.yml + capabilities: CAPABILITY_IAM,CAPABILITY_NAMED_IAM, CAPABILITY_AUTO_EXPAND + timeout-in-minutes: "10" + no-fail-on-empty-changeset: "1" + parameter-overrides: >- + EnvName=prod, + ZipFileName=canopas_website_SSR_prod_${{ github.sha }}-${{ github.run_attempt }}.zip, + CloudfrontURL=${{ secrets.CLOUDFRONT_URL_VALUE_PROD }} diff --git a/infrastructure/frontend.yml b/infrastructure/frontend.yml index 523b1ab25..0b242e023 100644 --- a/infrastructure/frontend.yml +++ b/infrastructure/frontend.yml @@ -1,82 +1,111 @@ -AWSTemplateFormatVersion: 2010-09-09 -Description: An ECS with launchType EC2 frontend stack +AWSTemplateFormatVersion: "2010-09-09" +Transform: + - AWS::LanguageExtensions + - AWS::Serverless-2016-10-31 + +Description: Canopas website serverless deployment with SSR. Parameters: EnvName: Type: String - Description: Name of an environment. 'dev', 'staging', 'prod' and any name. + Description: Name of an environment. AllowedPattern: ^.*[^0-9]$ ConstraintDescription: Must end with non-numeric character. - ClusterName: - Type: String - Description: Name of ECS cluster - ImageTag: - Type: String - Description: Website Docker frontend image tag - NginxImageTag: + AllowedValues: + - dev + - prod + ZipFileName: Type: String - Description: NGINX Docker image tag - BlogImageTag: + Description: Name of the zip file. + CloudfrontURL: Type: String - Description: Blog Docker image tag + Description: Cloudfront URL. Resources: - TaskDefinition: - Type: AWS::ECS::TaskDefinition + HttpApi: + Type: AWS::Serverless::HttpApi Properties: - Family: - Fn::Sub: canopas-website-${EnvName}-full-stack-task-definition - ExecutionRoleArn: - Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/ecsTaskExecutionRole - NetworkMode: "bridge" - ContainerDefinitions: - - Name: "canopas-website-nginx" - Hostname: "canopas-website-nginx" - Memory: 128 - Cpu: 128 - Essential: true - Image: - Fn::Sub: ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/canopas-website-nginx:${NginxImageTag} - PortMappings: - - ContainerPort: 80 - HostPort: 80 - Protocol: tcp - Links: - - canopas-website-frontend - - canopas-blog - - - Name: "canopas-website-frontend" - Memory: 256 - Cpu: 256 - Essential: true - Image: - Fn::Sub: ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/canopas-website-frontend:${ImageTag} - PortMappings: - - ContainerPort: 3080 - HostPort: 3080 - Protocol: tcp - - - Name: "canopas-blog" - Memory: 256 - Cpu: 256 - Essential: true - Image: - Fn::Sub: ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/canopas-blog:${BlogImageTag} - PortMappings: - - ContainerPort: 3000 - HostPort: 3000 - Protocol: tcp + StageName: $default + Description: + Fn::Sub: Canopas Website SSR Frontend API ${EnvName} + DefinitionBody: + openapi: "3.0.1" + info: + title: + Fn::Sub: canopas-website-ssr-frontend-${EnvName} + version: "1.0" + paths: + /favicon.ico: + x-amazon-apigateway-any-method: + responses: + default: + description: "Default response for ANY /favicon.ico" + x-amazon-apigateway-integration: + payloadFormatVersion: "1.0" + type: "http_proxy" + httpMethod: "ANY" + uri: + Fn::Sub: "${CloudfrontURL}favicon.ico" + connectionType: "INTERNET" + /sitemap.xml: + x-amazon-apigateway-any-method: + responses: + default: + description: "Default response for ANY /sitemap.xml" + x-amazon-apigateway-integration: + payloadFormatVersion: "1.0" + type: "http_proxy" + httpMethod: "ANY" + uri: + Fn::Sub: "${CloudfrontURL}sitemap.xml" + connectionType: "INTERNET" + /robots.txt: + x-amazon-apigateway-any-method: + responses: + default: + description: "Default response for ANY /robots.txt" + x-amazon-apigateway-integration: + payloadFormatVersion: "1.0" + type: "http_proxy" + httpMethod: "ANY" + uri: + Fn::Sub: "${CloudfrontURL}robots.txt" + connectionType: "INTERNET" + /apple-touch-icon.png: + x-amazon-apigateway-any-method: + responses: + default: + description: "Default response for ANY /apple-touch-icon.png" + x-amazon-apigateway-integration: + payloadFormatVersion: "1.0" + type: "http_proxy" + httpMethod: "ANY" + uri: + Fn::Sub: "${CloudfrontURL}apple-touch-icon.png" + connectionType: "INTERNET" + x-amazon-apigateway-importexport-version: "1.0" - ECSService: - Type: AWS::ECS::Service + HttpApiFunction: + Type: AWS::Serverless::Function Properties: - ServiceName: "canopas-website-full-stack" - LaunchType: EC2 - Cluster: - Fn::Sub: ${ClusterName} - DesiredCount: 1 - TaskDefinition: - Ref: "TaskDefinition" - DeploymentConfiguration: - MaximumPercent: 100 - MinimumHealthyPercent: 0 + PackageType: Zip + CodeUri: + Fn::Sub: s3://canopas-lambda-handlers/${ZipFileName} + Handler: index.handler + Runtime: nodejs20.x + Architectures: + - x86_64 + MemorySize: 256 + Timeout: 30 + FunctionName: + Fn::Sub: canopas-website-ssr-frontend-${EnvName} + Description: + Fn::Sub: Canopas Website SSR Frontend Lambda ${EnvName} + Events: + ProxyResource: + Type: HttpApi + Properties: + ApiId: + Ref: HttpApi + Path: $default + Method: any diff --git a/nuxt-frontend/assets/css/app.css b/nuxt-frontend/assets/css/app.css index d78cdc6c9..25e95ad64 100644 --- a/nuxt-frontend/assets/css/app.css +++ b/nuxt-frontend/assets/css/app.css @@ -3,7 +3,7 @@ font-family: Product Sans; font-style: normal; font-weight: 400; - src: url(../fonts/ProductSans-Regular-Subset.woff2) format("woff2"); + src: url(~/assets/fonts/ProductSans-Regular-Subset.woff2) format("woff2"); } @font-face { @@ -11,7 +11,7 @@ font-family: FuturaLT-Bold; font-style: bold; font-weight: 700; - src: url(../fonts/FuturaLT-Bold-Subset.woff2); + src: url(~/assets/fonts/FuturaLT-Bold-Subset.woff2) format("woff2"); } @font-face { @@ -19,7 +19,7 @@ font-family: Inter-Bold; font-style: bold; font-weight: 700; - src: url(../fonts/Inter-Bold-Subset.woff2) format("woff2"); + src: url(~/assets/fonts/Inter-Bold-Subset.woff2) format("woff2"); } @font-face { @@ -27,7 +27,7 @@ font-family: Inter-SemiBold; font-style: normal; font-weight: 600; - src: url(../fonts/Inter-SemiBold-Subset.woff2) format("woff2"); + src: url(~/assets/fonts/Inter-SemiBold-Subset.woff2) format("woff2"); } @font-face { @@ -35,7 +35,7 @@ font-family: Inter-Medium; font-style: medium; font-weight: 500; - src: url(../fonts/Inter-Medium-Subset.woff2) format("woff2"); + src: url(~/assets/fonts/Inter-Medium-Subset.woff2) format("woff2"); } @font-face { @@ -43,7 +43,7 @@ font-family: Inter-Regular; font-style: normal; font-weight: 400; - src: url(../fonts/Inter-Regular-Subset.woff2) format("woff2"); + src: url(~/assets/fonts/Inter-Regular-Subset.woff2) format("woff2"); } @font-face { @@ -51,7 +51,7 @@ font-family: Inter-Light; font-style: normal; font-weight: 300; - src: url(../fonts/Inter-Light-Subset.woff2) format("woff2"); + src: url(~/assets/fonts/Inter-Light-Subset.woff2) format("woff2"); } @font-face { @@ -59,7 +59,7 @@ font-family: Roboto-Bold; font-style: normal; font-weight: 600; - src: url(../fonts/Roboto-Bold-Subset.woff2); + src: url(~/assets/fonts/Roboto-Bold-Subset.woff2) format("woff2"); } @font-face { @@ -67,7 +67,7 @@ font-family: Roboto-Medium; font-style: normal; font-weight: 500; - src: url(../fonts/Roboto-Medium-Subset.woff2); + src: url(~/assets/fonts/Roboto-Medium-Subset.woff2) format("woff2"); } @font-face { @@ -75,7 +75,7 @@ font-family: Opensans-Bold; font-style: bold; font-weight: 700; - src: url(../fonts/Open-Sans-Bold.woff2) format("woff2"); + src: url(~/assets/fonts/Open-Sans-Bold.woff2) format("woff2"); } @font-face { @@ -83,7 +83,71 @@ font-family: Opensans-SemiBold; font-style: normal; font-weight: 600; - src: url(../fonts/Open-Sans-SemiBold.woff2) format("woff2"); + src: url(~/assets/fonts/Open-Sans-SemiBold.woff2) format("woff2"); +} + +@font-face { + font-display: swap; + font-family: Source CodePro; + font-style: normal; + font-weight: 400; + src: url(~/assets/fonts/Source-codePro.woff2) format("woff2"); +} + +@font-face { + font-display: swap; + font-family: Poppins Regular; + font-style: normal; + font-weight: 400; + src: url(~/assets/fonts/Poppins-Regular.woff2) format("woff2"); +} + +@font-face { + font-display: swap; + font-family: Poppins Medium; + font-style: medium; + font-weight: 500; + src: url(~/assets/fonts/Poppins-Medium.woff2) format("woff2"); +} + +@font-face { + font-display: swap; + font-family: Inter-ExtraLight; + font-style: normal; + font-weight: 200; + src: url(~/assets/fonts/Inter-ExtraLight.woff2) format("woff2"); +} + +@font-face { + font-display: swap; + font-family: Comme-Light; + font-style: normal; + font-weight: 300; + src: url(~/assets/fonts/Comme-Light.woff2) format("woff2"); +} + +@font-face { + font-display: swap; + font-family: Comme-Regular; + font-style: normal; + font-weight: 400; + src: url(~/assets/fonts/Comme-Regular.woff2) format("woff2"); +} + +@font-face { + font-display: swap; + font-family: Comme-Medium; + font-style: normal; + font-weight: 500; + src: url(~/assets/fonts/Comme-Medium.woff2) format("woff2"); +} + +@font-face { + font-display: swap; + font-family: Comme-SemiBold; + font-style: normal; + font-weight: 600; + src: url(~/assets/fonts/Comme-SemiBold.woff2) format("woff2"); } @font-face { diff --git a/nuxt-frontend/assets/fonts/Open-Sans-Bold.woff2 b/nuxt-frontend/assets/fonts/Open-Sans-Bold.woff2 index 0e902e318..b1b760af7 100644 Binary files a/nuxt-frontend/assets/fonts/Open-Sans-Bold.woff2 and b/nuxt-frontend/assets/fonts/Open-Sans-Bold.woff2 differ diff --git a/nuxt-frontend/assets/fonts/Open-Sans-SemiBold.woff2 b/nuxt-frontend/assets/fonts/Open-Sans-SemiBold.woff2 index 3f4251875..8578ae08c 100644 Binary files a/nuxt-frontend/assets/fonts/Open-Sans-SemiBold.woff2 and b/nuxt-frontend/assets/fonts/Open-Sans-SemiBold.woff2 differ diff --git a/nuxt-frontend/assets/images/portfolio/new-portfolio/smile.mp4 b/nuxt-frontend/assets/images/portfolio/new-portfolio/smile.mp4 index 6334e12c0..ca95ef8b1 100644 Binary files a/nuxt-frontend/assets/images/portfolio/new-portfolio/smile.mp4 and b/nuxt-frontend/assets/images/portfolio/new-portfolio/smile.mp4 differ diff --git a/nuxt-frontend/assets/images/portfolio/new-portfolio/smile.webm b/nuxt-frontend/assets/images/portfolio/new-portfolio/smile.webm index 7f47f3219..ddd00dad3 100644 Binary files a/nuxt-frontend/assets/images/portfolio/new-portfolio/smile.webm and b/nuxt-frontend/assets/images/portfolio/new-portfolio/smile.webm differ diff --git a/nuxt-frontend/assets/images/portfolio/new-portfolio/togness.mp4 b/nuxt-frontend/assets/images/portfolio/new-portfolio/togness.mp4 index eee96be0e..fa3674424 100644 Binary files a/nuxt-frontend/assets/images/portfolio/new-portfolio/togness.mp4 and b/nuxt-frontend/assets/images/portfolio/new-portfolio/togness.mp4 differ diff --git a/nuxt-frontend/assets/images/portfolio/new-portfolio/togness.webm b/nuxt-frontend/assets/images/portfolio/new-portfolio/togness.webm index e7b70ee0d..88e2168e1 100644 Binary files a/nuxt-frontend/assets/images/portfolio/new-portfolio/togness.webm and b/nuxt-frontend/assets/images/portfolio/new-portfolio/togness.webm differ diff --git a/nuxt-frontend/components/android-app-development/CaseStudySection.vue b/nuxt-frontend/components/android-app-development/CaseStudySection.vue index 6c9ab70d6..de9cca736 100644 --- a/nuxt-frontend/components/android-app-development/CaseStudySection.vue +++ b/nuxt-frontend/components/android-app-development/CaseStudySection.vue @@ -20,7 +20,7 @@ class="mt-6 relative lg:hidden" :class="item.className" > - - +
- + >
- + />
diff --git a/nuxt-frontend/components/backend-development/CaseStudySection.vue b/nuxt-frontend/components/backend-development/CaseStudySection.vue index 86be60470..8ac7e3cf4 100644 --- a/nuxt-frontend/components/backend-development/CaseStudySection.vue +++ b/nuxt-frontend/components/backend-development/CaseStudySection.vue @@ -18,7 +18,7 @@ class="mt-6 relative lg:hidden" :class="item.className" > -

-
+ @@ -72,7 +72,7 @@
- + >

- + />
diff --git a/nuxt-frontend/components/home-new/CaseStudy.vue b/nuxt-frontend/components/home-new/CaseStudy.vue index 85c750a97..e0fccbd5f 100644 --- a/nuxt-frontend/components/home-new/CaseStudy.vue +++ b/nuxt-frontend/components/home-new/CaseStudy.vue @@ -22,7 +22,7 @@ class="container mt-4 mb-6 text-black-60 text-center sub-h1-regular lg:mobile-header-2-regular" > 1M+ users use our apps every day diff --git a/nuxt-frontend/components/home-new/ContributionSection.vue b/nuxt-frontend/components/home-new/ContributionSection.vue index d51991e8e..ff752c11f 100644 --- a/nuxt-frontend/components/home-new/ContributionSection.vue +++ b/nuxt-frontend/components/home-new/ContributionSection.vue @@ -7,20 +7,25 @@ class="mt-4 mb-8 lg:mb-[4.5rem] text-center sub-h1-regular lg:mobile-header-2-regular text-black-60" > and that starts with the site itself, - Canopas Is Open Source!canopas is open source!
-
+
{{ contribution.title }}
@@ -94,7 +99,7 @@ >
- + @@ -102,14 +107,13 @@ import config from "@/config.js"; import { Swiper, SwiperSlide } from "swiper/vue"; import { Grid } from "swiper/modules"; -import { openBlog } from "@/utils.js"; export default { data() { return { - openBlog, width: 0, modules: [Grid], + websiteOpenSourceUrl: "https://github.com/canopas/canopas-website", contributions: [ { title: "compose-intro-showcase", diff --git a/nuxt-frontend/components/home-new/HomeIndex.vue b/nuxt-frontend/components/home-new/HomeIndex.vue index 62878b54e..87d0b16aa 100644 --- a/nuxt-frontend/components/home-new/HomeIndex.vue +++ b/nuxt-frontend/components/home-new/HomeIndex.vue @@ -4,12 +4,14 @@