Compare commits

...

22 Commits

Author SHA1 Message Date
a9f8183309 Merge pull request 'Purely documentation and typing, let's try' (#2) from dev into master
All checks were successful
Terraform validate and apply / terraform (ubuntu-latest) (push) Successful in 2m13s
Reviewed-on: #2
2025-09-18 16:23:41 +00:00
1381635467 Merge branch 'master' into dev
All checks were successful
Terraform validate and apply / terraform (ubuntu-latest) (pull_request) Successful in 3m16s
2025-09-18 11:19:50 -05:00
d831f89ad8 doc: add notes to readme
All checks were successful
Terraform validate and apply / terraform (ubuntu-latest) (pull_request) Successful in 2m36s
2025-09-18 11:17:46 -05:00
579c73b128 todo: mark some done 2025-09-18 10:50:46 -05:00
f2b9fd4c11 fmt: add type to domains 2025-09-18 10:50:04 -05:00
64c297a905 Merge pull request 'modularise?' (#1) from module into master
All checks were successful
Terraform validate and apply / terraform (ubuntu-latest) (push) Successful in 7m30s
Reviewed-on: #1
2025-09-18 15:48:39 +00:00
39c02779a9 fix: set env var for multiple domains
All checks were successful
Terraform validate and apply / terraform (ubuntu-latest) (pull_request) Successful in 1m45s
2025-09-18 10:34:45 -05:00
daf180c210 fmt: formatting update
Some checks failed
Terraform validate and apply / terraform (ubuntu-latest) (pull_request) Failing after 1m42s
2025-09-18 10:28:01 -05:00
ba2e1e4655 also run plan for PRs
Some checks failed
Terraform validate and apply / terraform (ubuntu-latest) (pull_request) Failing after 5m27s
2025-09-18 10:03:48 -05:00
615fc2a24f modules? 2025-09-18 09:59:37 -05:00
6e106657ea modularise? 2025-09-18 01:10:57 -05:00
4e913599cb doc: change example vars
All checks were successful
Terraform validate and apply / nix (ubuntu-latest) (push) Successful in 3m7s
2025-09-17 15:58:44 -05:00
043c379647 adding some refactor and example values 2025-09-17 15:58:11 -05:00
269545596a doc: todo updates for future
All checks were successful
Terraform validate and apply / nix (ubuntu-latest) (push) Successful in 2m34s
2025-09-10 13:21:47 -05:00
a25e9f6214 list more retrigger again
All checks were successful
Terraform validate and apply / nix (ubuntu-latest) (push) Successful in 2m16s
2025-09-10 13:17:47 -05:00
9bd7003589 test a change for workflow
All checks were successful
Terraform validate and apply / nix (ubuntu-latest) (push) Successful in 6m57s
2025-09-10 13:10:19 -05:00
f9a22a11e1 try caching terraform
All checks were successful
Terraform validate and apply / nix (ubuntu-latest) (push) Successful in 2m49s
2025-09-10 13:06:13 -05:00
344723abde adding workflow
All checks were successful
Terraform validate and apply / nix (ubuntu-latest) (push) Successful in 6m50s
2025-09-10 12:00:15 -05:00
806dd67110 fmt 2025-09-09 21:27:37 -05:00
c1d3af7ab0 doc: doc update 2025-09-09 19:14:49 -05:00
d3b0c13dad got it going 2025-09-09 18:41:49 -05:00
82c7eed868 fmt: better formatting 2025-09-09 15:27:42 -05:00
20 changed files with 1262 additions and 8 deletions

View File

@@ -0,0 +1,60 @@
name: Terraform validate and apply
run-name: ${{ gitea.actor }} applying terraform
on:
push:
branches:
- master
pull_request:
branches:
- master
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
TF_VAR_aws_region: ${{ vars.TF_VAR_aws_region }}
TF_VAR_site_domain: ${{ vars.TF_VAR_site_domain }}
TF_VAR_site_domains: ${{ vars.TF_VAR_site_domains }}
TF_VAR_project_name: ${{ vars.TF_VAR_project_name }}
TF_VAR_environment: ${{ vars.TF_VAR_environment }}
TF_VAR_tuffas_applier_role_arn: ${{ vars.TF_VAR_tuffas_applier_role_arn }}
TF_VAR_tfstate_backend_role_arn: ${{ vars.TF_VAR_tfstate_backend_role_arn }}
TF_PLUGIN_CACHE_DIR: ${{ github.workspace }}/.terraform.d/plugin-cache
jobs:
terraform:
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Check out repository code
uses: actions/checkout@v4
- run: ls -alh
name: List files
- name: Set up terraform
uses: hashicorp/setup-terraform@v3
- name: Set up and configure Terraform plugin cache
run: |
mkdir --parents $TF_PLUGIN_CACHE_DIR
- name: Cache terraform
uses: actions/cache@v4
with:
path: ${{ env.TF_PLUGIN_CACHE_DIR }}
key: ${{ runner.os }}-terraform-${{hashFiles('**.terraform.lock.hcl') }}
restore-keys: ${{ runner.os }}-terraform-
- name: Init
id: init
run: terraform init
- name: Check formatting
id: fmt
run: terraform fmt -check
- name: Validate
id: validate
run: terraform validate
- name: Plan
id: plan
run: terraform plan -no-color -input=false
- name: Apply
id: apply
run: terraform apply -auto-approve -no-color -input=false
if: github.ref == 'refs/heads/master' && github.event_name == 'push'

4
.gitignore vendored
View File

@@ -8,7 +8,11 @@ result
# Local .terraform directories
.terraform/
# cache directories
.terraform.d/
# .tfstate files
*.tfstate
*.tfstate.*
terraform.tfvars

20
.terraform.lock.hcl generated
View File

@@ -1,6 +1,26 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/cloudflare/cloudflare" {
version = "2.19.2"
constraints = "~> 2.19.2"
hashes = [
"h1:gcgDf0Ltyopd5j30oCcnjceCyRpJmSBhTTwldOFnJEc=",
"zh:35a4d37c7601b537e156a032730e2987f137017e38c9a1a383f75cfeccb1975e",
"zh:3bdb1544aef7469813a699ba8d322248c96ffa05573c2bb990e1297aa95473d0",
"zh:41a322d3eeeb0dde185ea7a9cafe952c445a683a6a372089f8d003d8d2f4b722",
"zh:447ec6386879ff56cd3a97fc5d20b428451a445f8846a0127f5788de9e213b3c",
"zh:4a1fa7c6c9e28916009fe3c7a9f7f944e8b4e307ab3d97a34d81ba66769160f6",
"zh:5a2cb0e8ddc725c78ba09a817105136f564c7f4fe0173633d82bc3f8005dc15a",
"zh:83c0edc0ddd6ad8e3c140dcecafccad69edd199d2526cc9be10d857316f3859e",
"zh:a5a1917943a9e8486dc3d0eb315bc899944fe67888e38b35999b6a79907ec762",
"zh:a5cfcd8ec0fd3d0c80de8c519ee07b1e899b8f86d5f6f5800bc959190df9eb93",
"zh:be3a37ef3f0991989a4e51e5fe16d9cf71571cb1ecb7a41b31d91c2ae2a3313d",
"zh:ef1155fd12e3528f686b6a59fc732e35265f8d08450bc27baf8ccebbcd4cff0c",
"zh:f3a2293a7ccb14fa16472c7948498d5a19cb5f26e3aeb1b59756c7f9045c277b",
]
}
provider "registry.terraform.io/hashicorp/aws" {
version = "5.100.0"
constraints = "~> 5.92"

View File

@@ -1,8 +1,34 @@
# Testaform
# tuffas
Testing terraform out
hosting hruday.me via terraform
---
Add `dotenv` to .envrc after other nix stuff, and store keys in .env, which is fine for a testing project.
~~Add `dotenv` to .envrc after other nix stuff, and store keys in .env, which is fine for a testing project.~~
Don't add dotenv.
Workflow is to just use the `dev` branch or anything else, then only actually deploy via PR to `master`.
PR to master is a great deployment strategy, no notes.
Currently manages hruday.me and deepakmallubhotla.com, creating buckets which match the domain names.
The content of the sites are managed externally, in their own repos which deploy by uploading to the S3 bucket created here.
## adding a domain
Not an ideal process, so we should improve.
1. Acquire domain name, manually atm.
2. let Cloudflare manage DNS by setting nameservers (following the wizard in cf works with no DNS records required before we get here!) etc., also manual
3. Add domain name to relevant Gitea variable, should be easy.
4. Bucket will be created, empty. If you want an easy start you can manually upload to the bucket.
5. Deploy with whatever method you want, can include a build process or anything else. Follow hruday.me as a guide maybe
## Todos
- [x] better secrets management
- [x] ci
- [x] test ci permissions with a real terraform apply (not in ci)
- [ ] can we make a lower-weight runner? ubuntu-latest is heavy and still requires ~1m for providers
- [ ] For new domain should provide a default set of content in the bucket? or does that cost more for the extra creates, for a local project we may not care

View File

@@ -22,4 +22,3 @@ fmt:
set -euxo pipefail
nix fmt
# shouldn't actually be that hard to put into nix fmt but lazyyy
terraform fmt

19
main.tf Normal file
View File

@@ -0,0 +1,19 @@
provider "aws" {
region = var.aws_region
assume_role {
role_arn = var.tuffas_applier_role_arn
}
}
provider "cloudflare" {
}
module "static_website" {
source = "./modules/static-website"
# toset to dedupe
for_each = toset(var.site_domains)
site_domain = each.key
project_name = var.project_name
environment = var.environment
}

View File

@@ -0,0 +1,141 @@
locals {
common_tags = {
Project = var.project_name
Environment = var.environment
ManagedBy = "terraform"
Domain = var.site_domain
}
}
resource "aws_s3_bucket" "site" {
bucket = var.site_domain
tags = local.common_tags
}
resource "aws_s3_bucket_public_access_block" "site" {
bucket = aws_s3_bucket.site.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
resource "aws_s3_bucket_website_configuration" "site" {
bucket = aws_s3_bucket.site.id
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
}
resource "aws_s3_bucket_ownership_controls" "site" {
bucket = aws_s3_bucket.site.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}
resource "aws_s3_bucket_acl" "site" {
bucket = aws_s3_bucket.site.id
acl = "public-read"
depends_on = [
aws_s3_bucket_ownership_controls.site,
aws_s3_bucket_public_access_block.site
]
}
resource "aws_s3_bucket_policy" "site" {
bucket = aws_s3_bucket.site.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "PublicReadGetObject"
Effect = "Allow"
Principal = "*"
Action = "s3:GetObject"
Resource = "${aws_s3_bucket.site.arn}/*"
},
]
})
depends_on = [
aws_s3_bucket_public_access_block.site
]
}
data "cloudflare_zones" "domain" {
filter {
name = var.site_domain
}
}
resource "cloudflare_record" "site_cname" {
zone_id = data.cloudflare_zones.domain.zones[0].id
name = var.site_domain
value = aws_s3_bucket_website_configuration.site.website_endpoint
type = "CNAME"
ttl = 1
proxied = true
}
resource "cloudflare_record" "www" {
zone_id = data.cloudflare_zones.domain.zones[0].id
name = "www"
value = var.site_domain
type = "CNAME"
ttl = 1
proxied = true
}
resource "aws_s3_bucket_versioning" "site" {
bucket = aws_s3_bucket.site.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_lifecycle_configuration" "site" {
bucket = aws_s3_bucket.site.id
rule {
id = "cleanup_old_versions"
status = "Enabled"
noncurrent_version_expiration {
noncurrent_days = 90
}
filter {
prefix = ""
}
}
rule {
id = "cleanup_incomplete_uploads"
status = "Enabled"
abort_incomplete_multipart_upload {
days_after_initiation = 7
}
filter {
prefix = ""
}
}
}
resource "cloudflare_page_rule" "https" {
zone_id = data.cloudflare_zones.domain.zones[0].id
target = "*.${var.site_domain}/*"
actions {
always_use_https = true
}
}

View File

@@ -0,0 +1,14 @@
output "website_bucket_name" {
description = "Name (id) of the bucket"
value = aws_s3_bucket.site.id
}
output "bucket_endpoint" {
description = "Bucket endpoint"
value = aws_s3_bucket_website_configuration.site.website_endpoint
}
output "domain_name" {
description = "Website endpoint"
value = var.site_domain
}

View File

@@ -0,0 +1,20 @@
variable "site_domain" {
type = string
description = "The domain name of the site"
}
variable "project_name" {
type = string
description = "Name of the project for resource tagging"
default = "tuffas"
}
variable "environment" {
type = string
description = "Environment name (e.g., dev, staging, prod)"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be one of: dev, staging, prod."
}
}

View File

@@ -0,0 +1,14 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.92"
}
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 2.19.2"
}
}
required_version = ">= 1.2"
}

60
moved.tf Normal file
View File

@@ -0,0 +1,60 @@
moved {
from = aws_s3_bucket.site
to = module.static_website.aws_s3_bucket.site
}
moved {
from = aws_s3_bucket_acl.site
to = module.static_website.aws_s3_bucket_acl.site
}
moved {
from = aws_s3_bucket_lifecycle_configuration.site
to = module.static_website.aws_s3_bucket_lifecycle_configuration.site
}
moved {
from = aws_s3_bucket_ownership_controls.site
to = module.static_website.aws_s3_bucket_ownership_controls.site
}
moved {
from = aws_s3_bucket_policy.site
to = module.static_website.aws_s3_bucket_policy.site
}
moved {
from = aws_s3_bucket_public_access_block.site
to = module.static_website.aws_s3_bucket_public_access_block.site
}
moved {
from = aws_s3_bucket_versioning.site
to = module.static_website.aws_s3_bucket_versioning.site
}
moved {
from = aws_s3_bucket_website_configuration.site
to = module.static_website.aws_s3_bucket_website_configuration.site
}
moved {
from = cloudflare_record.www
to = module.static_website.cloudflare_record.www
}
moved {
from = cloudflare_record.site_cname
to = module.static_website.cloudflare_record.site_cname
}
moved {
from = cloudflare_page_rule.https
to = module.static_website.cloudflare_page_rule.https
}
moved {
from = module.static_website
to = module.static_website["hruday.me"]
}

14
outputs.tf Normal file
View File

@@ -0,0 +1,14 @@
output "website_bucket_names" {
description = "Names (ids) of the buckets by domain"
value = { for k, v in module.static_website : k => v.website_bucket_name }
}
output "bucket_endpoints" {
description = "Bucket endpoints by domain"
value = { for k, v in module.static_website : k => v.bucket_endpoint }
}
output "domain_names" {
description = "Website endpoints by domain"
value = { for k, v in module.static_website : k => v.domain_name }
}

View File

@@ -4,14 +4,18 @@ terraform {
source = "hashicorp/aws"
version = "~> 5.92"
}
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 2.19.2"
}
}
backend "s3" {
region = "us-east-2"
bucket = "hrudayme-test-tfstate"
key = "tuffas-tf"
region = "us-east-2"
bucket = "hrudayme-test-tfstate"
key = "tuffas-tf"
use_lockfile = true
assume_role = { role_arn = "arn:aws:iam::677425296084:role/tfstate_backend_role" }
assume_role = { role_arn = "arn:aws:iam::677425296084:role/tfstate_backend_role" }
}
required_version = ">= 1.2"

17
terraform.tfvars.example Normal file
View File

@@ -0,0 +1,17 @@
# Example Terraform variables file
# Copy this file to terraform.tfvars and update with your actual values
# AWS region where resources will be created
aws_region = "us-east-2"
# Your domain name (must be managed by Cloudflare)
site_domain = "example.com"
# Project name for resource tagging
project_name = "tuffas"
# Environment (dev, staging, prod)
environment = "prod"
# IAM role ARNs (update with your actual role ARNs)
tuffas_applier_role_arn = "arn:aws:iam::YOUR-ACCOUNT-ID:role/ROLE_NAME"

View File

@@ -17,5 +17,6 @@
programs.shfmt.enable = true;
programs.yamlfmt.enable = true;
programs.just.enable = true;
programs.terraform.enable = true;
}

31
variables.tf Normal file
View File

@@ -0,0 +1,31 @@
variable "aws_region" {
type = string
description = "The AWS region of these sites"
}
variable "site_domains" {
type = list(string)
description = "The domain name of these sites, which will be mapped over"
}
variable "tuffas_applier_role_arn" {
type = string
description = "IAM role ARN for Terraform to assume when applying changes"
}
variable "project_name" {
type = string
description = "Name of the project for resource tagging"
default = "tuffas"
}
# future proofing
variable "environment" {
type = string
description = "Environment name (e.g., dev, staging, prod)"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be one of: dev, staging, prod."
}
}

3
website/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Custom Start page
Based on https://github.com/jeroenpardon/sui

View File

@@ -0,0 +1,558 @@
html{
box-sizing: border-box;
moz-box-sizing: border-box;
webkit-box-sizing: border-box;
webkit-text-size-adjust: none;
}
html,
body{
background-color: var(--color-background);
color: var(--color-text-pri);
font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif;
font-size: 14px;
font-weight: 400;
height: auto;
letter-spacing: -.012em;
margin: 0;
padding: 0;
webkit-font-smoothing: antialiased;
width: 100vw;
}
*,
*:before,
*:after{
box-sizing: inherit;
moz-box-sizing: inherit;
webkit-box-sizing: inherit;
}
:root{
module-spacing: 3vh;
}
/* TEXT STYLES */
h1, h2{
font-weight: 300;
margin: 0;
padding: 0;
text-align: left;
}
h2, h3, h4{
text-transform: uppercase;
}
h1{
font-size: 4em;
font-weight: 700;
margin-bottom: 0.5em;
}
h2{
font-size: 16px;
height: 30px;
}
h3{
font-size: 20px;
font-weight: 900;
height: 10px;
}
h4{
font-size: 1.1em;
font-weight: 400;
height: 10px;
}
a{
color: var(--color-text-pri);
text-decoration: none;
}
a:hover{
text-decoration: underline;
webkit-text-decoration-color: var(--color-text-acc);
webkit-text-decoration-skip: true;
}
.icon{
font-size: 2.5em;
}
/* FORMS */
input{
background-color: transparent;
border: 0;
border-bottom: thin solid var(--color-text-acc);
color: var(--color-text-pri);
font-size: 0.8em;
height: 3.5em;
transition: all 0.4s ease;
width: 100%;
}
input:focus{
color-border: var(--color-text-pri);
outline: none;
}
input:focus{
opacity: 1;
}
/* TABLES */
table{
border: thin solid #e4e4e4;
border-collapse: collapse;
border-spacing: 0;
font-size: 1em;
text-align: left;
width: 100%;
}
table td:nth-of-type(2){
padding-right: 5em;
}
table td{
border: thin solid #e4e4e4;
color: #333333;
font-size: 1em;
overflow: hidden;
padding: 10px 5px;
word-break: normal;
}
table th{
border: thin solid #e4e4e4;
color: #333333;
font-weight: bold;
padding: 10px 5px;
}
table a{
color: #333333;
}
/* ANIMATION */
.fade{
opacity: 0;
}
@keyframes fadeseq{
100% {
opacity: 1;
}
}
.fade{
opacity: 0;
}
.fade{
animation: fadeseq .3s forwards;
}
.fade:nth-child(2){
animation-delay: .4s;
}
/* LAYOUT */
#container{
align-items: stretch;
display: grid;
grid-column-gap: 20px;
grid-row-gap: 3vh;
grid-template-columns: 1fr;
grid-template-rows: 12vh 4vh auto;
justify-items: stretch;
margin-left: auto;
margin-right: auto;
margin-top: 5vh;
width: 60%;
}
/* SECTIONS */
#header{
border-bottom: 0px solid var(--color-text-acc);
z-index: 1;
}
#apps_loop{
border-bottom: 0px solid var(--color-text-acc);
display: grid;
grid-column-gap: 0px;
grid-row-gap: 0px;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 64px;
padding-bottom: var(--module-spacing);
}
.apps_icon{
height: 64px;
margin-right: 1em;
padding-top: 15px;
}
.apps_icon span{
font-size: 2.5em;
line-height: 3rem;
}
.apps_item{
display: flex;
flex-direction: row;
flex-wrap: wrap;
height: 64px;
margin: 0;
}
.apps_text{
display: flex;
flex-direction: column;
justify-content: center;
flex: 1;
overflow: hidden;
}
.apps_text a{
font-size: 1em;
font-weight: 500;
text-transform: uppercase;
}
.apps_text span{
color: var(--color-text-acc);
font-size: 0.8em;
text-transform: uppercase;
}
#links_loop{
display: grid;
flex-wrap: nowrap;
grid-column-gap: 20px;
grid-row-gap: 0px;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: auto;
}
#links_item{
line-height: 1.5rem;
margin-bottom: 2em;
webkit-font-smoothing: antialiased;
}
#links_item h4{
color: var(--color-text-acc);
}
#links_item a{
display: block;
line-height: 2;
}
/* MODAL */
#modal{
overflow-y: auto;
bottom: 0;
left: 0;
opacity: 0;
pointer-events: none;
position: fixed;
right: 0;
top: 0;
transition: all 0.3s;
z-index: 20;
}
#modal:target{
opacity: 1;
pointer-events: auto;
}
#modal>div{
background-color: #ffffff;
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.30), 0 15px 12px rgba(0, 0, 0, 0.25);
margin-left: auto;
margin-right: auto;
padding: 2em;
margin-top: 5vh;
width: 50%;
display: flex;
flex-direction: column;
}
#modal h1{
color: #333333;
font-size: 2em;
}
#modal h2{
margin-top:1.5em;
}
#modal-header{
display:flex;
justify-content: space-between;
}
#modal-footer{
display:flex;
font-size:2em;
justify-content: flex-start;
}
#modal-footer a{
margin-right:0.25em;
}
.modal-close{
color: #000000;
font-size: 1.5em;
text-align: center;
text-decoration: none;
}
.modal-close:hover{
color: #000;
}
#modal_init a{
bottom: 1vh;
color: var(--color-text-acc);
left: 1vw;
position: fixed;
}
#modal_init a:hover{
color: var(--color-text-pri);
}
#modal-theme{
border-bottom: 0px solid var(--color-text-acc);
display: flex;
flex-wrap: wrap;
margin-bottom: 2em;
}
#providers{
margin-bottom: 2em;
}
/* THEMING */
.theme-button{
font-size: 0.8em;
margin: 2px;
width:128px;
line-height: 3em;
text-align: center;
text-transform: uppercase;
}
.theme-blackboard{
background-color: #000000;
border: 4px solid #5c5c5c;
color: #FFFDEA;
}
.theme-gazette{
background-color: #F2F7FF;
border: 4px solid #5c5c5c;
color: #000000;
}
.theme-espresso{
background-color: #21211F;
border: 4px solid #4E4E4E;
color: #D1B59A;
}
.theme-cab{
background-color: #FEED01;
border: 4px solid #424242;
color: #1F1F1F;
}
.theme-cloud{
background-color: #f1f2f0;
border: 4px solid #35342f;
color: #37bbe4;
}
.theme-lime{
background-color: #263238;
border: 4px solid #AABBC3;
color: #aeea00;
}
.theme-passion{
background-color: #f5f5f5;
border: 4px solid #8e24aa;
color: #12005e;
}
.theme-blues{
background-color: #2B2C56;
border: 4px solid #6677EB;
color: #EFF1FC;
}
.theme-chalk{
background-color: #263238;
border: 4px solid #FF869A;
color: #AABBC3;
}
.theme-tron{
background-color: #242B33;
border: 4px solid #6EE2FF;
color: #EFFBFF;
}
.theme-paper{
background-color: #F8F6F1;
border: 4px solid #F5E1A4;
color: #4C432E;
}
/* MEDIA QUERIES */
@media screen and (max-width: 1260px)
{
#container
{
align-items: stretch;
display: grid;
grid-column-gap: 10px;
grid-row-gap: 0px;
grid-template-columns: 1fr;
grid-template-rows: 80px auto;
justify-items: stretch;
margin-bottom: 1vh;
margin-left: auto;
margin-right: auto;
width: 90%;
}
#apps_loop{
grid-template-columns: 1fr 1fr 1fr;
width: 100vw;
}
#links_loop {
grid-template-columns: 1fr 1fr 1fr;
}
#modal>div{
margin-left: auto;
margin-right: auto;
margin-top: 5vh;
width: 90%;
}
}
@media screen and (max-width: 667px)
{
html{
font-size: calc(16px + 6 * ((100vw - 320px) / 680));
}
#container{
align-items: stretch;
display: grid;
grid-column-gap: 20px;
grid-row-gap: 0px;
grid-template-columns: 1fr;
grid-template-rows: 80px auto;
justify-items: stretch;
margin-bottom: 1vh;
width: 90%;
}
h1{
font-size: 4em;
height: auto;
margin-bottom: 0em;
}
h2{
font-size: 1em;
height: auto;
margin-bottom: 0em;
}
h3{
font-size: 1em;
}
#apps_loop{
grid-column-gap: 0px;
grid-row-gap: 0px;
grid-template-columns: 1fr 1fr;
width: 100vw;
}
.apps_icon{
height: 64px;
margin-right: 0.8em;
padding-top: 14px;
}
.apps_icon span{
font-size: 2em;
line-height: 2.5rem;
}
#links_loop{
display: grid;
flex-wrap: nowrap;
grid-column-gap: 20px;
grid-row-gap: 0px;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto;
}
}
/* Small Screens */
@media only screen and (max-width: 400px) {
#app-address {
display: none;
}
}

220
website/assets/js/script.js Normal file
View File

@@ -0,0 +1,220 @@
function date() {
let currentDate = new Date();
let dateOptions = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
};
let date = currentDate.toLocaleDateString("en-GB", dateOptions);
document.getElementById("header_date").innerHTML = date;
}
function greet() {
let currentTime = new Date();
let greet = Math.floor(currentTime.getHours() / 6);
switch (greet) {
case 0:
document.getElementById("header_greet").innerHTML = "Good night!";
break;
case 1:
document.getElementById("header_greet").innerHTML = "Good morning!";
break;
case 2:
document.getElementById("header_greet").innerHTML = "Good afternoon!";
break;
case 3:
document.getElementById("header_greet").innerHTML = "Good evening!";
break;
}
}
const strategies = [
"(Organic) machinery",
"A line has two sides",
"A very small object Its center",
"Abandon desire",
"Abandon normal instructions",
"Abandon normal instruments",
"Accept advice",
"Accretion",
"Adding on",
"Allow an easement (an easement is the abandonment of a stricture)",
"Always first steps",
"Always give yourself credit for having more than personality",
"Are there sections? Consider transitions",
"Ask people to work against their better judgement",
"Ask your body",
"Assemble some of the elements in a group and treat the group",
"Balance the consistency principle with the inconsistency principle",
"Be dirty",
"Be extravagant",
"Be less critical",
"Breathe more deeply",
"Bridges -build -burn",
"Cascades",
"Change ambiguities to specifics",
"Change instrument roles",
"Change nothing and continue with immaculate consistency",
"Change specifics to ambiguities",
"Children -speaking -singing",
"Cluster analysis",
"Consider different fading systems",
"Consider transitions",
"Consult other sources -promising -unpromising",
"Convert a melodic element into a rhythmic element",
"Courage!",
"Cut a vital connection",
"Decorate, decorate",
"Define an area as 'safe' and use it as an anchor",
"Destroy -nothing -the most important thing",
"Discard an axiom",
"Disciplined self-indulgence",
"Disconnect from desire",
"Discover the recipes you are using and abandon them",
"Display your talent",
"Distorting time",
"Do nothing for as long as possible",
"Do something boring",
"Do something sudden, destructive and unpredictable",
"Do the last thing first",
"Do the washing up",
"Do the words need changing?",
"Do we need holes?",
"Don't avoid what is easy",
"Don't be frightened of cliches",
"Don't break the silence",
"Don't stress one thing more than another",
"Don't be afraid of things because they're easy to do",
"Don't be frightened to display your talents",
"Emphasize differences",
"Emphasize repetitions",
"Emphasize the flaws",
"Faced with a choice, do both",
"Feed the recording back out of the medium",
"Fill every beat with something",
"Find a safe part and use it as an anchor",
"Get your neck massaged",
"Ghost echoes",
"Give the game away",
"Give the name away",
"Give way to your worst impulse",
"Go outside. Shut the door.",
"Go slowly all the way round the outside",
"Go to an extreme, come part way back",
"Honor thy error as a hidden intention",
"How would someone else do it?",
"How would you have done it?",
"Humanize something free of error",
"Idiot glee (?)",
"Imagine the piece as a set of disconnected events",
"In total darkness, or in a very large room, very quietly",
"Infinitesimal gradations",
"Intentions -nobility of -humility of -credibility of",
"Into the impossible",
"Is it finished?",
"Is something missing?",
"Is the information correct?",
"Is the style right?",
"It is quite possible (after all)",
"It is simply a matter of work",
"Just carry on",
"Left channel, right channel, center channel",
"Listen to the quiet voice",
"Look at the order in which you do things",
"Look closely at the most embarrassing details & amplify them",
"Lost in useless territory",
"Lowest common denominator",
"Magnify the most difficult details",
"Make a blank valuable by putting it in an exquisite frame",
"Make a sudden, destructive unpredictable action; incorporate",
"Make an exhaustive list of everything you might do \n& do the last thing on the list",
"Make it more sensual",
"Make what's perfect more human",
"Mechanicalize something idiosyncratic",
"Move towards the unimportant",
"Mute and continue",
"Not building a wall but making a brick",
"Once the search has begun, something will be found",
"Only a part, not the whole",
"Only one element of each kind",
"Overtly resist change",
"Put in earplugs",
"Question the heroic approach",
"Reevaluation (a warm feeling)",
"Remember those quiet evenings",
"Remove a restriction",
"Remove ambiguities and convert to specifics",
"Remove specifics and convert to ambiguities",
"Repetition is a form of change",
"Retrace your steps",
"Reverse",
"Short circuit \n(example: a man eating peas with the idea that they will improve his virility \nshovels them straight into his lap)",
"Simple subtraction",
"Simply a matter of work",
"Slow preparation, fast execution",
"Spectrum analysis",
"State the problem in words as clearly as possible",
"Take a break",
"Take away the elements in order of apparent non-importance",
"Take away the important parts",
"Tape your mouth",
"The inconsistency principle",
"The most important thing is the thing most easily forgotten",
"The tape is now the music",
"Think - inside the work -outside the work",
"Think of the radio",
"Tidy up",
"Towards the insignificant",
"Trust in the you of now",
"Try faking it",
"Turn it upside down",
"Twist the spine",
"Use 'unqualified' people",
"Use an old idea",
"Use an unacceptable color",
"Use cliches",
"Use fewer notes",
"Use filters",
"Use something nearby as a model",
"Use your own ideas",
"Voice your suspicions",
"Water",
"What are the sections sections of? Imagine a caterpillar moving",
"What are you really thinking about just now?",
"What context would look right?",
"What is the reality of the situation?",
"What is the simplest solution?",
"What mistakes did you make last time?",
"What to increase? What to reduce? What to maintain?",
"What would your closest friend do?",
"What wouldn't you do?",
"When is it for?",
"Where is the edge?",
"Which parts can be grouped?",
"Work at a different speed",
"Would anyone want it?",
"You are an engineer",
"You can only make one dot at a time",
"You don't have to be ashamed of using your own ideas",
"[blank white card]"
];
const pickStrategy = () => {
let strategyNumber = Math.floor(Math.random() * strategies.length);
return strategies[strategyNumber];
};
const strategize = () => {
let strat = pickStrategy();
document.getElementById("header_strategy").innerHTML = strat;
}
function loadFunctions() {
date();
greet();
strategize();
}

29
website/index.html Normal file
View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>deepak.science</title>
<meta charset="utf-8">
<meta http-equiv="Default-Style" content="">
<meta content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport" />
<link type="text/css" rel="stylesheet" href="./assets/css/styles.css" media="screen,projection"/>
<link href="https://fonts.googleapis.com/css?family=Roboto:400,500,700,900" rel="stylesheet">
</head>
<body onload="loadFunctions()">
<main id="container" class="fade">
<section id="header">
<h2 id="header_date"></h2>
<h1 id="header_greet"></h1>
</section>
<section id="strategies">
<h2 id="header_strategy"></h2>
</section>
</main>
<script src="./assets/js/script.js" type="text/javascript"></script>
</body>
</html>