Curtains and roman blinds and fabric calculator

Made to Measure Calculators

:root {
–ink: #252126;
–muted: #6b6269;
–line: #ded6dd;
–soft: #f8f5f7;
–accent: #77566d;
–accent-dark: #55384e;
–white: #fff;
}
body {
margin: 0;
padding: 24px;
color: var(–ink);
background: #f2f0f2;
font-family: Arial, Helvetica, sans-serif;
}
.mtm-calcs {
max-width: 1040px;
margin: 0 auto;
background: var(–white);
border: 1px solid var(–line);
border-radius: 8px;
overflow: hidden;
}
.curtain-hero {
min-height: 180px;
background: #f6f0f3;
border-bottom: 1px solid var(–line);
}
.curtain-hero svg {
display: block;
width: 100%;
height: auto;
}
.tabs {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
border-bottom: 1px solid var(–line);
background: var(–soft);
}
.tabs button {
min-height: 52px;
padding: 10px;
border: 0;
border-right: 1px solid var(–line);
color: var(–ink);
background: transparent;
font-weight: 700;
cursor: pointer;
}
.tabs button:last-child { border-right: 0; }
.tabs button.active {
color: #fff;
background: var(–accent);
}
.panel {
display: none;
padding: 24px;
}
.panel.active { display: block; }
h2 {
margin: 0 0 18px;
font-size: 24px;
line-height: 1.25;
}
.grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}
.field {
display: grid;
gap: 6px;
}
.field label {
font-size: 14px;
font-weight: 700;
}
input, select {
min-height: 44px;
width: 100%;
box-sizing: border-box;
padding: 10px 12px;
border: 1px solid var(–line);
border-radius: 6px;
background: #fff;
color: var(–ink);
font-size: 16px;
}
.result {
margin-top: 28px;
}
.price {
color: var(–accent-dark);
font-size: 30px;
font-weight: 800;
}
.note {
margin: 0;
color: var(–muted);
font-size: 13px;
line-height: 1.45;
}
.quote {
display: inline-flex;
align-items: center;
justify-content: center;
margin-top: 14px;
min-height: 42px;
padding: 0 16px;
border-radius: 6px;
color: #fff;
background: var(–accent);
text-decoration: none;
font-weight: 700;
}
.ll-section-title {
display: flex;
align-items: center;
gap: 12px;
margin: 18px 0 8px;
color: #171217;
font-size: 15px;
letter-spacing: .02em;
text-transform: uppercase;
}
.ll-section-title::after {
content: “”;
height: 1px;
flex: 1;
background: #cfc9ce;
}
.ll-table {
width: 100%;
border-collapse: collapse;
background: #eee;
margin-bottom: 18px;
font-size: 13px;
}
.ll-table th,
.ll-table td {
padding: 11px 16px;
text-align: left;
vertical-align: top;
}
.ll-table th {
width: 48%;
font-weight: 800;
text-transform: uppercase;
}
.ll-email-row {
display: grid;
grid-template-columns: minmax(0, 1fr) 140px;
gap: 16px;
margin-bottom: 18px;
}
.ll-email-row input {
border-radius: 0;
background: #fff;
}
.ll-email-row button {
border: 0;
background: #f7c72c;
color: #000;
font-weight: 800;
cursor: pointer;
}
.making-up-copy {
margin: 0 0 14px;
font-size: 13px;
line-height: 1.5;
}
.text-link {
display: inline-block;
color: #000;
border-bottom: 2px solid #f7c72c;
text-decoration: none;
font-weight: 800;
text-transform: uppercase;
font-size: 13px;
padding-bottom: 4px;
}
@media (max-width: 760px) {
body { padding: 12px; }
.tabs { grid-template-columns: 1fr 1fr; }
.panel { padding: 18px; }
.grid { grid-template-columns: 1fr; }
.ll-email-row { grid-template-columns: 1fr; }
}




Curtain Making Service

Fabric width (cm)
Pattern repeat (cm)
Width (cm)
Drop (cm)
Pair or singlePairSingle
Pole or trackPoleTrack
HeadingPencil pleatDouble pleatEyeletWave heading
LiningNo liningStandardExtra thick thermalLined and interlined
BlackoutNoYes

Roman Blind Making Service

Fabric width (cm)
Pattern repeat (cm)
Width (cm)
Drop (cm)
Installation height (cm)
LiningNo liningStandardExtra thick thermalLined and interlined
BlackoutNoYes
Chain positionLeftRight

Curtain Fabric Calculator

Fabric name
Fabric width (cm)
Pattern repeat (cm)
Price per metre
Pole or trackPoleTrack
Width (cm)
Total drop (cm)
Pair or singlePairSingle
HeadingPencil pleatDouble pleatEyeletWave heading
InterlinedNoYes

Blind Fabric Calculator

Blind typeRoman blindRoller blind
Fabric name
Fabric width (cm)
Pattern repeat (cm)
Price per metre
Width (cm)
Drop (cm)

(function () {
const money = (n) => “GBP ” + Math.max(0, n).toFixed(2);
const metres = (cm) => (Math.ceil(cm / 10) / 100).toFixed(2).replace(/\.00$/, “”) + ” m”;
const num = (panel, name) => Number(panel.querySelector(‘[data-field=”‘ + name + ‘”]’).value) || 0;
const val = (panel, name) => panel.querySelector(‘[data-field=”‘ + name + ‘”]’).value;
const fullness = { pencil: 2, double: 2.5, eyelet: 2, wave: 2.3 };
const emailAddress = “charmshape@gmail.com”;
const curtainWidthBands = [36, 105, 173, 242, 310, 379, 447, 516, 584, 653, 721, 790, 858, 927, 995, 1064, 1132, 1201];
const curtainBaseAt100 = [123, 185, 248, 310, 372, 435, 497, 559, 622, 684, 746, 809, 871, 933, 996, 1058, 1120, 1183];
const romanWidths = [50, 100, 150, 200, 250];
const romanDrops = [50, 100, 150, 200, 250, 300];
const romanStandard = [
[155, 180, 216, 252, 292, 333],
[178, 212, 259, 316, 370, 416],
[235, 276, 348, 419, 511, 601],
[267, 330, 420, 510, 590, 716],
[298, 369, 471, 627, 777, 804]
];

function repeatLength(length, repeat) {
return repeat > 0 ? Math.ceil(length / repeat) * repeat : length;
}

function fieldText(panel, name) {
const field = panel.querySelector(‘[data-field=”‘ + name + ‘”]’);
return field && field.selectedOptions ? field.selectedOptions[0].textContent : field.value;
}

function rows(items) {
return items.map((item) => “

” + item[0] + “ ” + item[1] + “

“).join(“”);
}

function renderResult(panel, calculationRows, specificationRows, subject, body, quoteLabel) {
const mail = makeMailto(subject, body);
panel.querySelector(‘[data-output=”result”]’).innerHTML =

Calculation Results

‘ +

‘ + rows(calculationRows) + ‘

‘ +

Specification

‘ +

‘ + rows(specificationRows) + ‘

‘ +

Email these results

‘ +
” +
” +
‘ +
” +

Making up service

‘ +

Want to use your own fabric? Not a problem. Our making up service is quick, simple and our prices are competitive.

‘ +
‘ + (quoteLabel || “Get a quote”) + ‘‘;
}

function curtainFabric(panel) {
const width = num(panel, “width”);
const drop = num(panel, “drop”);
const fabricWidth = Math.max(1, num(panel, “fabricWidth”));
const repeat = num(panel, “repeat”);
const pair = val(panel, “pair”) === “pair” ? 2 : 1;
const f = fullness[val(panel, “heading”)];
const widths = Math.max(pair, Math.ceil((width * f) / fabricWidth));
const cutDrop = repeatLength(drop + 25, repeat);
const requiredCm = widths * cutDrop;
const cost = requiredCm / 100 * num(panel, “ppm”);
const body = “Curtain fabric required: ” + metres(requiredCm) + “\nFabric cost: ” + money(cost);
renderResult(panel, [
[“Fabric required”, metres(requiredCm)],
[“Fabric cost”, money(cost)],
[“Lining required”, val(panel, “interlined”) === “yes” ? metres(requiredCm) : “Not selected”]
], [
[“Fabric width”, fabricWidth + ” cm”],
[“Pattern repeat”, repeat + ” cm”],
[“Price per metre”, money(num(panel, “ppm”))],
[“Width”, width + ” cm”],
[“Drop”, drop + ” cm”],
[“Pole or track”, fieldText(panel, “fixture”)],
[“Heading type”, fieldText(panel, “heading”)],
[“Style”, fieldText(panel, “pair”)],
[“Fullness”, f.toFixed(2)]
], “Curtain fabric result”, body, “Get a quote”);
}

function blindFabric(panel) {
const width = num(panel, “width”);
const drop = num(panel, “drop”);
const fabricWidth = Math.max(1, num(panel, “fabricWidth”));
const repeat = num(panel, “repeat”);
const type = val(panel, “type”);
const allowance = type === “roman” ? 20 : 30;
const widths = Math.max(1, Math.ceil(width / fabricWidth));
const cutDrop = repeatLength(drop + allowance, repeat);
const requiredCm = widths * cutDrop;
const cost = requiredCm / 100 * num(panel, “ppm”);
const body = “Blind fabric required: ” + metres(requiredCm) + “\nFabric cost: ” + money(cost);
renderResult(panel, [
[“Fabric required”, metres(requiredCm)],
[“Fabric cost”, money(cost)],
[“Lining required”, type === “roman” ? metres(requiredCm) : “Not required”],
[“Interlining required”, type === “roman” ? metres(requiredCm) : “Not required”]
], [
[“Blind type”, fieldText(panel, “type”)],
[“Fabric width”, fabricWidth + ” cm”],
[“Pattern repeat”, repeat + ” cm”],
[“Price per metre”, money(num(panel, “ppm”))],
[“Width”, width + ” cm”],
[“Drop”, drop + ” cm”]
], “Blind fabric result”, body, “Get a quote”);
}

function lookupIndex(maxes, value) {
const idx = maxes.findIndex((max) => value x y {
button.addEventListener(“click”, () => {
document.querySelectorAll(“.tabs button”).forEach((b) => b.classList.remove(“active”));
document.querySelectorAll(“.panel”).forEach((panel) => panel.classList.remove(“active”));
button.classList.add(“active”);
document.getElementById(button.dataset.tab).classList.add(“active”);
});
});

Object.keys(calculators).forEach((id) => {
const panel = document.getElementById(id);
panel.querySelectorAll(“input, select”).forEach((field) => {
field.addEventListener(“input”, () => calculators[id](panel));
field.addEventListener(“change”, () => calculators[id](panel));
});
calculators[id](panel);
});
})();