Repository navigation
Expand file tree
/
Copy pathscript.js
More file actions
90 lines (84 loc) · 14.6 KB
/
Copy pathscript.js
File metadata and controls
90 lines (84 loc) · 14.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
const $=(s,p=document)=>p.querySelector(s),$$=(s,p=document)=>[...p.querySelectorAll(s)];const WA='919929562585';
const images={
warm:'https://images.pexels.com/photos/6316055/pexels-photo-6316055.jpeg?auto=compress&cs=tinysrgb&w=2200',
living:'https://images.pexels.com/photos/6588599/pexels-photo-6588599.jpeg?auto=compress&cs=tinysrgb&w=2200',
editorial:'https://images.pexels.com/photos/7173672/pexels-photo-7173672.jpeg?auto=compress&cs=tinysrgb&w=2200',
modern:'https://images.pexels.com/photos/6920437/pexels-photo-6920437.jpeg?auto=compress&cs=tinysrgb&w=2200',
luxe:'https://images.pexels.com/photos/5883721/pexels-photo-5883721.jpeg?auto=compress&cs=tinysrgb&w=2200',
tropical:'https://images.pexels.com/photos/28915352/pexels-photo-28915352.jpeg?auto=compress&cs=tinysrgb&w=2200',
city:'https://images.pexels.com/photos/29515355/pexels-photo-29515355.jpeg?auto=compress&cs=tinysrgb&w=2200',
villa:'https://images.pexels.com/photos/24807128/pexels-photo-24807128.jpeg?auto=compress&cs=tinysrgb&w=2200',
glass:'https://images.pexels.com/photos/6077368/pexels-photo-6077368.jpeg?auto=compress&cs=tinysrgb&w=2200',
facade:'https://images.pexels.com/photos/30506378/pexels-photo-30506378.jpeg?auto=compress&cs=tinysrgb&w=2200',
office:'https://images.pexels.com/photos/8103238/pexels-photo-8103238.jpeg?auto=compress&cs=tinysrgb&w=1800',
bedroom:'https://images.pexels.com/photos/1648768/pexels-photo-1648768.jpeg?auto=compress&cs=tinysrgb&w=1800',
kitchen:'https://images.pexels.com/photos/2724749/pexels-photo-2724749.jpeg?auto=compress&cs=tinysrgb&w=1800'
};
const colors=[{name:'Bronze',hex:'#b88a58'},{name:'Terracotta',hex:'#b36346'},{name:'Olive',hex:'#6f7652'},{name:'Stone',hex:'#87817a'},{name:'Burgundy',hex:'#8d4651'},{name:'Navy',hex:'#4a6077'},{name:'Forest',hex:'#3f6a58'},{name:'Champagne',hex:'#c09a64'}];
const texts=[
{name:'Considered',k:'Interior Design · Architecture · Styling',t:'Spaces That Feel Considered.',p:'Thoughtful interiors shaped around real life.'},
{name:'Home',k:'Residential Interiors',t:'A Home That Works Beautifully.',p:'Planning, materials and light designed as one system.'},
{name:'Minimal',k:'Calm · Material · Proportion',t:'Less Noise. Better Space.',p:'A quieter visual language with practical depth.'},
{name:'Hospitality',k:'Hospitality · Guest Experience',t:'Design the Stay People Remember.',p:'Atmosphere, comfort and operations brought together.'},
{name:'Renovation',k:'Renovation · Replanning',t:'Keep the Character. Change the Experience.',p:'Existing spaces reworked with clarity and restraint.'},
{name:'Commercial',k:'Workplace · Retail · Studio',t:'Spaces That Express the Business.',p:'Clear planning for teams, clients and daily operations.'},
{name:'Architecture',k:'Architecture · Site · Light',t:'Built Around Place and Purpose.',p:'Form, climate and everyday use considered together.'}
];
const heroStyles=[
{name:'Warm Minimalism',className:'hero-01',photo:images.warm,position:'center',color:'#b88a58',text:0},
{name:'Editorial Living',className:'hero-02',photo:images.living,position:'center',color:'#b36346',text:1},
{name:'City Penthouse',className:'hero-03',photo:images.city,position:'center',color:'#4a6077',text:0},
{name:'Material Study',className:'hero-04',photo:images.editorial,position:'center',color:'#87817a',text:2},
{name:'Ivory Interior',className:'hero-05',photo:images.modern,position:'center',color:'#c09a64',text:2},
{name:'Glasshouse',className:'hero-06',photo:images.glass,position:'center',color:'#3f6a58',text:6},
{name:'Tropical Residence',className:'hero-07',photo:images.tropical,position:'center',color:'#6f7652',text:1},
{name:'Luxury Lounge',className:'hero-08',photo:images.luxe,position:'center',color:'#8d4651',text:0},
{name:'Private Villa',className:'hero-09',photo:images.villa,position:'center',color:'#b88a58',text:4},
{name:'Architectural Facade',className:'hero-10',photo:images.facade,position:'center',color:'#4a6077',text:6}
];
const projects=[
{id:1,name:'Quiet City Apartment',type:'Residential',scope:'Full Interior',area:'1,850 sq.ft.',image:images.warm,desc:'A warm, storage-led apartment with calm circulation.'},
{id:2,name:'Glasshouse Residence',type:'Residential',scope:'Architecture + Interior',area:'3,400 sq.ft.',image:images.glass,desc:'Open living spaces framed by light and landscape.'},
{id:3,name:'Courtyard Villa',type:'Architecture',scope:'Villa',area:'5,200 sq.ft.',image:images.villa,desc:'A private residence organised around outdoor living.'},
{id:4,name:'City View Penthouse',type:'Residential',scope:'Luxury Interior',area:'3,100 sq.ft.',image:images.city,desc:'Layered textures and restrained furniture planning.'},
{id:5,name:'Boutique Stay',type:'Hospitality',scope:'Interior + Styling',area:'18 Keys',image:images.tropical,desc:'Guest rooms and shared spaces with local material cues.'},
{id:6,name:'Creative Workplace',type:'Commercial',scope:'Office Interior',area:'6,800 sq.ft.',image:images.office,desc:'Flexible work settings with clear acoustic zones.'},
{id:7,name:'Material House',type:'Residential',scope:'Renovation',area:'2,250 sq.ft.',image:images.editorial,desc:'A renovation built around natural finishes and daylight.'},
{id:8,name:'Modern Lounge',type:'Hospitality',scope:'Interior',area:'2,900 sq.ft.',image:images.luxe,desc:'A hospitality space with intimate seating and layered light.'},
{id:9,name:'Urban Facade Study',type:'Architecture',scope:'Facade',area:'Concept',image:images.facade,desc:'A contemporary elevation balancing shade, rhythm and privacy.'}
];
const rooms=[
{name:'Living Spaces',text:'Furniture placement, circulation, lighting and storage designed as one system.',image:images.living},
{name:'Bedrooms',text:'Restful palettes, practical wardrobes and carefully controlled light.',image:images.bedroom},
{name:'Kitchens',text:'Workflow, storage, services and durable finishes planned together.',image:images.kitchen},
{name:'Workspaces',text:'Acoustics, focus, collaboration and client experience considered from the start.',image:images.office},
{name:'Hospitality',text:'Guest comfort, operations and atmosphere aligned in one design language.',image:images.tropical}
];
let state={style:0,color:0,text:0,room:0,colorLocked:false,textLocked:false,fontLocked:false,auto:true},styleTimer,colorTimer,textTimer;
function rgb(hex){hex=hex.replace('#','');const n=parseInt(hex,16);return[(n>>16)&255,(n>>8)&255,n&255].join(',')}
function persist(){localStorage.setItem('interior-settings',JSON.stringify({style:state.style,color:state.color,text:state.text,colorLocked:state.colorLocked,textLocked:state.textLocked,font:document.documentElement.style.getPropertyValue('--font'),theme:document.documentElement.dataset.theme}))}
function setColor(hex,index=null){document.documentElement.style.setProperty('--accent',hex);document.documentElement.style.setProperty('--accent-rgb',rgb(hex));$('#colorPicker').value=hex;if(index!==null)state.color=index;persist()}
function setText(i){state.text=(i+texts.length)%texts.length;const x=texts[state.text];$('#heroKicker').textContent=x.k;$('#heroTitle').textContent=x.t;$('#heroText').textContent=x.p;$$('#textList button').forEach((b,n)=>b.classList.toggle('active',n===state.text));persist()}
function setStyle(i,user=false){state.style=(i+heroStyles.length)%heroStyles.length;const x=heroStyles[state.style];$('.hero').className=`hero ${x.className}`;$('#heroImage').style.backgroundImage=`url("${x.photo}")`;$('#heroImage').style.backgroundPosition=x.position;$('#styleName').textContent=`${String(state.style+1).padStart(2,'0')} · ${x.name}`;$$('#styleDots button').forEach((b,n)=>b.classList.toggle('active',n===state.style));$$('#styleList button').forEach((b,n)=>b.classList.toggle('active',n===state.style));if(!state.colorLocked)setColor(x.color,colors.findIndex(c=>c.hex===x.color));if(!state.textLocked)setText(x.text);persist();if(user)restartAuto()}
function restartAuto(){clearInterval(styleTimer);clearInterval(colorTimer);clearInterval(textTimer);if(!state.auto)return;styleTimer=setInterval(()=>setStyle(state.style+1),60000);colorTimer=setInterval(()=>{if(!state.colorLocked){state.color=(state.color+1)%colors.length;setColor(colors[state.color].hex,state.color)}},18000);textTimer=setInterval(()=>{if(!state.textLocked)setText(state.text+1)},24000)}
heroStyles.forEach((x,i)=>{const d=document.createElement('button');d.textContent=String(i+1).padStart(2,'0');d.onclick=()=>setStyle(i,true);$('#styleDots').appendChild(d);const b=document.createElement('button');b.textContent=x.name;b.onclick=()=>setStyle(i,true);$('#styleList').appendChild(b)});
colors.forEach((c,i)=>{const b=document.createElement('button');b.style.background=c.hex;b.title=c.name;b.onclick=()=>setColor(c.hex,i);$('#colorList').appendChild(b)});
texts.forEach((x,i)=>{const b=document.createElement('button');b.textContent=x.name;b.onclick=()=>setText(i);$('#textList').appendChild(b)});
const types=['All',...new Set(projects.map(p=>p.type))];
types.forEach((t,i)=>{const b=document.createElement('button');b.textContent=t;b.classList.toggle('active',i===0);b.onclick=()=>{renderProjects(t);$$('#projectFilter button').forEach(x=>x.classList.toggle('active',x.textContent===t))};$('#projectFilter').appendChild(b)});
function renderProjects(type='All'){const list=type==='All'?projects:projects.filter(p=>p.type===type);$('#projectGrid').innerHTML=list.map(p=>`<article class="project-card reveal visible"><div class="project-image" style="background-image:url('${p.image}')"></div><div class="project-body"><span class="eyebrow">${p.type}</span><h3>${p.name}</h3><p>${p.desc}</p><div class="project-meta"><span>${p.scope}</span><span>${p.area}</span><span>Concept Project</span></div><button data-project="${p.name}">View Project →</button></div></article>`).join('');$$('[data-project]').forEach(b=>b.onclick=()=>wa(`Interior project enquiry\nProject reference: ${b.dataset.project}\nPlease share your project location, area, scope and timeline.`))}
rooms.forEach((r,i)=>{const b=document.createElement('button');b.textContent=r.name;b.onclick=()=>setRoom(i);$('#roomTabs').appendChild(b)});
function setRoom(i){state.room=(i+rooms.length)%rooms.length;const r=rooms[state.room];$('#roomTitle').textContent=r.name;$('#roomText').textContent=r.text;$('#roomImage').style.backgroundImage=`url("${r.image}")`;$$('#roomTabs button').forEach((b,n)=>b.classList.toggle('active',n===state.room))}
$('#roomEnquiry').onclick=()=>wa(`I would like to discuss ${$('#roomTitle').textContent.toLowerCase()} for my project.`);
function formatINR(n){return new Intl.NumberFormat('en-IN',{style:'currency',currency:'INR',maximumFractionDigits:0}).format(n)}
function calculateBudget(){const rate=+$('#budgetType').value,area=Math.max(200,+$('#budgetArea').value||0),scope=+$('#budgetScope').value;$('#budgetResult').textContent=formatINR(rate*area*scope)}
$$('#budgetForm input,#budgetForm select').forEach(x=>x.oninput=calculateBudget);
function wa(message){window.open(`https://wa.me/${WA}?text=${encodeURIComponent(message)}`,'_blank')}
$$('[data-service]').forEach(b=>b.onclick=()=>wa(`Interior service enquiry\nService: ${b.dataset.service}\nPlease share the project location, area, scope and timeline.`));
$('#consultationForm').onsubmit=e=>{e.preventDefault();const f=new FormData(e.currentTarget);wa(`Interior project consultation\nName: ${f.get('name')}\nPhone: ${f.get('phone')}\nProject type: ${f.get('type')}\nLocation: ${f.get('location')}\nArea: ${f.get('area')}\nBudget: ${f.get('budget')}\nTimeline: ${f.get('timeline')}\nService: ${f.get('service')}\nNotes: ${f.get('notes')}`)};
$('#contactForm').onsubmit=e=>{e.preventDefault();const f=new FormData(e.currentTarget);wa(`Interior website enquiry\nName: ${f.get('name')}\nStudio: ${f.get('studio')}\nPhone: ${f.get('phone')}\nWebsite type: ${f.get('type')}\nRequirement: ${f.get('message')}`)};
$('#comparisonRange').oninput=e=>$('#afterWrap').style.width=`${e.target.value}%`;
$('#previousStyle').onclick=()=>setStyle(state.style-1,true);$('#nextStyle').onclick=()=>setStyle(state.style+1,true);$('#customizerToggle').onclick=()=>$('#customizerPanel').classList.toggle('open');$('#autoToggle').onclick=e=>{state.auto=!state.auto;e.target.textContent=state.auto?'Pause Auto':'Play Auto';restartAuto()};$('#colorPicker').oninput=e=>setColor(e.target.value);$('#colorSearch').onchange=e=>{const v=e.target.value.trim().toLowerCase(),found=colors.find(c=>c.name.toLowerCase().includes(v));if(found)setColor(found.hex,colors.indexOf(found));else if(/^#[0-9a-f]{6}$/i.test(v))setColor(v)};$('#lockColor').onclick=e=>{state.colorLocked=!state.colorLocked;e.target.classList.toggle('locked',state.colorLocked);e.target.textContent=state.colorLocked?'Color Locked':'Lock Color';persist()};$('#lockText').onclick=e=>{state.textLocked=!state.textLocked;e.target.classList.toggle('locked',state.textLocked);e.target.textContent=state.textLocked?'Text Locked':'Lock Text';persist()};$('#fontSelect').onchange=e=>{document.documentElement.style.setProperty('--font',e.target.value);persist()};$('#fontSearch').onchange=e=>{const v=e.target.value.trim();if(v){document.documentElement.style.setProperty('--font',`${v}, Arial, sans-serif`);persist()}};$('#lockFont').onclick=e=>{state.fontLocked=!state.fontLocked;e.target.classList.toggle('locked',state.fontLocked);e.target.textContent=state.fontLocked?'Font Locked':'Lock Font'};$('#themeToggle').onclick=e=>{const dark=document.documentElement.dataset.theme!=='dark';document.documentElement.dataset.theme=dark?'dark':'light';e.target.textContent=dark?'Light Mode':'Dark Mode';persist()};$('#menuButton').onclick=()=>{const n=$('#navLinks');n.classList.toggle('open');$('#menuButton').setAttribute('aria-expanded',n.classList.contains('open'))};$$('#navLinks a').forEach(a=>a.onclick=()=>$('#navLinks').classList.remove('open'));
function restore(){try{const s=JSON.parse(localStorage.getItem('interior-settings')||'{}');if(s.theme)document.documentElement.dataset.theme=s.theme;if(s.font)document.documentElement.style.setProperty('--font',s.font);if(Number.isInteger(s.style))state.style=s.style;if(Number.isInteger(s.color))state.color=s.color;if(Number.isInteger(s.text))state.text=s.text;state.colorLocked=!!s.colorLocked;state.textLocked=!!s.textLocked;$('#lockColor').classList.toggle('locked',state.colorLocked);$('#lockColor').textContent=state.colorLocked?'Color Locked':'Lock Color';$('#lockText').classList.toggle('locked',state.textLocked);$('#lockText').textContent=state.textLocked?'Text Locked':'Lock Text'}catch{}}
const observer=new IntersectionObserver(es=>es.forEach(x=>{if(x.isIntersecting)x.target.classList.add('visible')}),{threshold:.1});$$('.reveal').forEach(x=>observer.observe(x));
restore();renderProjects();setRoom(0);calculateBudget();setStyle(state.style);if(state.colorLocked)setColor(colors[state.color]?.hex||colors[0].hex,state.color);if(state.textLocked)setText(state.text);restartAuto();