@tollerud/footer 1.1.3 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
- import { CSSProperties, ReactElement } from 'react';
1
+ import * as react from 'react';
2
+ import { CSSProperties, ReactElement, SVGAttributes } from 'react';
2
3
 
3
4
  type FooterLabels = {
4
- /** Text for the tollerud.no link (e.g. A Tollerud Project). */
5
+ /** Text for the tollerud.no link (e.g. "A Tollerud Project"). */
5
6
  tollerudProject: string;
6
7
  /**
7
8
  * Optional middle segment after the link, before the rights line.
8
- * Example for [dispatch.tollerud.dev](https://dispatch.tollerud.dev/): `"for Advania Norge AS."`
9
+ * Example for Advania: `"for Advania Norge AS."`
9
10
  */
10
11
  attribution?: string;
11
12
  allRightsReserved: string;
@@ -14,20 +15,38 @@ type FooterProps = {
14
15
  labels?: Partial<FooterLabels>;
15
16
  /** Layout behavior: responsive keeps mobile-first stacking, row forces horizontal layout. */
16
17
  layout?: 'responsive' | 'row';
17
- /** Merged onto `<footer>`. Use for layout, surface, e.g. `border-t border-white/10 bg-black/50 backdrop-blur-sm`. */
18
+ /** Merged onto <footer>. Use for extra layout, padding, etc. */
18
19
  className?: string;
19
- /** Merged onto `<footer>` (wins over conflicting `backgroundColor` from classes when needed). */
20
+ /** Merged onto <footer> (wins over conflicting backgroundColor from classes when needed). */
20
21
  style?: CSSProperties;
21
22
  /**
22
- * When true, skips default border/background/dark surface so `className` / `style` fully control the bar
23
- * (avoids fighting `bg-gray-50` / `dark:bg-gray-900`).
23
+ * When true, skips all default surface styling so className/style fully control the bar
24
+ * (avoids fighting default background/border).
24
25
  */
25
26
  unstyled?: boolean;
27
+ /** When true, uses accent (yellow) surface instead of neutral dark. */
28
+ accent?: boolean;
26
29
  classNameInner?: string;
27
30
  classNameLogo?: string;
28
31
  classNameText?: string;
29
32
  classNameLink?: string;
30
33
  };
31
- declare function Footer({ labels, layout, className, style, unstyled, classNameInner, classNameLogo, classNameText, classNameLink, }: FooterProps): ReactElement;
34
+ declare function Footer({ labels, layout, className, style, unstyled, accent, classNameInner, classNameLogo, classNameText, classNameLink, }: FooterProps): ReactElement;
32
35
 
33
- export { Footer, type FooterLabels, type FooterProps };
36
+ type MonogramColor = 'yellow' | 'black' | 'white';
37
+ interface MonogramProps extends SVGAttributes<SVGSVGElement> {
38
+ /**
39
+ * Fill color via `currentColor`.
40
+ * - `yellow` — default on dark surfaces (#FFFF00)
41
+ * - `black` — light-mode surfaces (#0A0A0A)
42
+ * - `white` — on tinted or photographic backgrounds
43
+ */
44
+ color?: MonogramColor;
45
+ /** Height in px; width scales from the 130×143 viewBox. */
46
+ size?: number;
47
+ /** Accessible name — rendered as `<title>` and `aria-label`. */
48
+ title?: string;
49
+ }
50
+ declare const Monogram: react.ForwardRefExoticComponent<MonogramProps & react.RefAttributes<SVGSVGElement>>;
51
+
52
+ export { Footer, type FooterLabels, type FooterProps, Monogram, type MonogramColor, type MonogramProps };
package/dist/index.js CHANGED
@@ -1,9 +1,54 @@
1
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
1
+ // src/utils.ts
2
+ import { clsx } from "clsx";
3
+ import { twMerge } from "tailwind-merge";
4
+ function cn(...inputs) {
5
+ return twMerge(clsx(inputs));
6
+ }
7
+
8
+ // src/Monogram.tsx
9
+ import { forwardRef } from "react";
10
+
11
+ // src/monogram-geometry.ts
12
+ var MONOGRAM_VIEW_BOX = "0 0 130 143";
13
+ var MONOGRAM_PATH = "M82.4839273,140.272626 L95.1738252,140.272626 L95.1738252,143 L34.8114657,143 L34.8114657,140.272626 L47.5013636,140.272626 L47.5013636,28.2924381 C40.1277806,26.4177752 32.9252955,25.2241422 26.4088393,25.2241422 C12.1757856,25.2241422 4.11617359,34.5982703 4.11617359,39.8821508 C4.11617359,40.9049161 4.63028596,41.5867596 5.65932936,41.5867596 C7.20248513,41.5867596 7.37440169,40.3931266 8.06043062,38.8593855 C10.4615319,33.575505 15.6059302,31.5307881 20.4073141,31.5307881 C29.152955,31.5307881 35.1552988,38.5184637 35.1552988,47.2107482 C35.1552988,56.2447681 28.8107592,62.8907084 18.0070315,62.8907084 C7.5454996,62.891522 0,53.6882617 0,43.8023442 C0,30.8497582 11.3178401,21.986606 26.5799372,21.986606 C51.1026062,21.986606 84.1989996,39.2011209 104.948509,39.2011209 C118.495534,39.2011209 126.384048,31.7016558 126.384048,19.4300996 C126.384048,10.3968933 118.667451,4.60203698 115.580321,4.60203698 C114.552096,4.60203698 113.69415,5.1130128 113.69415,6.13577809 C113.69415,7.49946515 114.552096,7.6695192 115.409223,8.01044097 C115.752237,8.18049502 122.268693,10.5669474 122.268693,19.2592319 C122.268693,28.2924381 115.238125,34.0872945 107.177694,34.0872945 C97.7460244,34.0872945 91.0584702,26.4177752 91.0584702,17.8955448 C91.0584702,6.64675391 99.9760277,0 109.749893,0 C122.268693,0 129.642276,9.88510384 129.642276,19.6001536 C129.642276,34.2581622 119.181563,42.4386572 104.947691,42.4386572 C98.0890388,42.4386572 90.5443579,40.9049161 82.4839273,38.6901451 L82.4839273,140.272626 Z";
14
+
15
+ // src/Monogram.tsx
16
+ import { jsx, jsxs } from "react/jsx-runtime";
17
+ var colorClasses = {
18
+ yellow: "text-tollerud-yellow",
19
+ black: "text-tollerud-noir-950",
20
+ white: "text-white"
21
+ };
22
+ var Monogram = forwardRef(
23
+ ({ color = "yellow", size, className, title = "Tollerud", style, ...props }, ref) => {
24
+ return /* @__PURE__ */ jsxs(
25
+ "svg",
26
+ {
27
+ ref,
28
+ viewBox: MONOGRAM_VIEW_BOX,
29
+ xmlns: "http://www.w3.org/2000/svg",
30
+ role: "img",
31
+ "aria-label": title,
32
+ className: cn(
33
+ "inline-block shrink-0",
34
+ colorClasses[color],
35
+ !size && "h-5 w-auto",
36
+ className
37
+ ),
38
+ style: size ? { height: size, width: "auto", ...style } : style,
39
+ ...props,
40
+ children: [
41
+ /* @__PURE__ */ jsx("title", { children: title }),
42
+ /* @__PURE__ */ jsx("g", { fill: "currentColor", fillRule: "evenodd", children: /* @__PURE__ */ jsx("g", { transform: "translate(-86.000000, -109.000000)", children: /* @__PURE__ */ jsx("g", { transform: "translate(32.000000, 55.000000)", children: /* @__PURE__ */ jsx("g", { transform: "translate(54.000000, 54.000000)", children: /* @__PURE__ */ jsx("path", { d: MONOGRAM_PATH }) }) }) }) })
43
+ ]
44
+ }
45
+ );
46
+ }
47
+ );
48
+ Monogram.displayName = "Monogram";
2
49
 
3
50
  // src/Footer.tsx
4
- function cn(...parts) {
5
- return parts.filter(Boolean).join(" ");
6
- }
51
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7
52
  var defaultLabels = {
8
53
  tollerudProject: "A Tollerud Project",
9
54
  allRightsReserved: "All rights reserved."
@@ -14,6 +59,7 @@ function Footer({
14
59
  className,
15
60
  style,
16
61
  unstyled = false,
62
+ accent = false,
17
63
  classNameInner,
18
64
  classNameLogo,
19
65
  classNameText,
@@ -21,82 +67,43 @@ function Footer({
21
67
  }) {
22
68
  const t = { ...defaultLabels, ...labels };
23
69
  const attribution = t.attribution?.trim();
24
- const footerSurface = unstyled ? "" : "border-t border-gray-200 bg-gray-50 dark:border-gray-800 dark:bg-gray-900";
70
+ const footerSurface = unstyled ? "" : accent ? "border-t border-tollerud-yellow/20 bg-tollerud-yellow/5" : "border-t border-tollerud-border bg-tollerud-noir-900/80";
25
71
  const innerLayoutClasses = layout === "row" ? "max-w-7xl mx-auto px-8 flex flex-row items-center justify-between gap-4" : "max-w-7xl mx-auto px-8 flex flex-col md:flex-row items-center justify-center md:justify-between gap-4 md:gap-0";
26
72
  const textWrapperClasses = layout === "row" ? "flex-1 text-right ml-4" : "flex-1 text-center md:text-right md:ml-4";
27
- const textLayoutClasses = layout === "row" ? "text-sm text-gray-600 dark:text-gray-400 inline-flex flex-row items-center justify-end text-right gap-0" : "text-sm text-gray-600 dark:text-gray-400 flex flex-col md:flex-row md:inline gap-0";
28
- return /* @__PURE__ */ jsx("footer", { className: cn("w-full pt-4 pb-4", footerSurface, className), style, children: /* @__PURE__ */ jsxs(
29
- "div",
30
- {
31
- className: cn(
32
- innerLayoutClasses,
33
- classNameInner
34
- ),
35
- children: [
36
- /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 md:flex-shrink-0", children: /* @__PURE__ */ jsxs(
37
- "svg",
38
- {
39
- width: "24",
40
- height: "24",
41
- viewBox: "0 0 130 143",
42
- version: "1.1",
43
- xmlns: "http://www.w3.org/2000/svg",
44
- xmlnsXlink: "http://www.w3.org/1999/xlink",
45
- className: cn("h-5 w-5 text-black dark:text-[#ffff00]", classNameLogo),
46
- role: "img",
47
- children: [
48
- /* @__PURE__ */ jsx("title", { children: "Tollerud Logo" }),
49
- /* @__PURE__ */ jsx("g", { id: "Page-1", stroke: "none", strokeWidth: "1", fill: "none", fillRule: "evenodd", children: /* @__PURE__ */ jsx("g", { id: "Tollerud Monogram", transform: "translate(-86.000000, -109.000000)", fill: "currentColor", children: /* @__PURE__ */ jsx("g", { id: "Group-2", transform: "translate(32.000000, 55.000000)", children: /* @__PURE__ */ jsx("g", { id: "Group", transform: "translate(54.000000, 54.000000)", children: /* @__PURE__ */ jsx(
50
- "path",
51
- {
52
- d: "M82.4839273,140.272626 L95.1738252,140.272626 L95.1738252,143 L34.8114657,143 L34.8114657,140.272626 L47.5013636,140.272626 L47.5013636,28.2924381 C40.1277806,26.4177752 32.9252955,25.2241422 26.4088393,25.2241422 C12.1757856,25.2241422 4.11617359,34.5982703 4.11617359,39.8821508 C4.11617359,40.9049161 4.63028596,41.5867596 5.65932936,41.5867596 C7.20248513,41.5867596 7.37440169,40.3931266 8.06043062,38.8593855 C10.4615319,33.575505 15.6059302,31.5307881 20.4073141,31.5307881 C29.152955,31.5307881 35.1552988,38.5184637 35.1552988,47.2107482 C35.1552988,56.2447681 28.8107592,62.8907084 18.0070315,62.8907084 C7.5454996,62.891522 0,53.6882617 0,43.8023442 C0,30.8497582 11.3178401,21.986606 26.5799372,21.986606 C51.1026062,21.986606 84.1989996,39.2011209 104.948509,39.2011209 C118.495534,39.2011209 126.384048,31.7016558 126.384048,19.4300996 C126.384048,10.3968933 118.667451,4.60203698 115.580321,4.60203698 C114.552096,4.60203698 113.69415,5.1130128 113.69415,6.13577809 C113.69415,7.49946515 114.552096,7.6695192 115.409223,8.01044097 C115.752237,8.18049502 122.268693,10.5669474 122.268693,19.2592319 C122.268693,28.2924381 115.238125,34.0872945 107.177694,34.0872945 C97.7460244,34.0872945 91.0584702,26.4177752 91.0584702,17.8955448 C91.0584702,6.64675391 99.9760277,0 109.749893,0 C122.268693,0 129.642276,9.88510384 129.642276,19.6001536 C129.642276,34.2581622 119.181563,42.4386572 104.947691,42.4386572 C98.0890388,42.4386572 90.5443579,40.9049161 82.4839273,38.6901451 L82.4839273,140.272626 Z",
53
- id: "Monogram"
54
- }
55
- ) }) }) }) })
56
- ]
57
- }
58
- ) }),
59
- /* @__PURE__ */ jsx("div", { className: textWrapperClasses, children: /* @__PURE__ */ jsxs(
60
- "p",
73
+ const textLayoutClasses = layout === "row" ? "text-sm text-tollerud-text-secondary inline-flex flex-row items-center justify-end text-right gap-0" : "text-sm text-tollerud-text-secondary flex flex-col md:flex-row md:inline gap-0";
74
+ return /* @__PURE__ */ jsx2("footer", { className: cn("w-full pt-4 pb-4", footerSurface, className), style, children: /* @__PURE__ */ jsxs2("div", { className: cn(innerLayoutClasses, classNameInner), children: [
75
+ /* @__PURE__ */ jsx2("div", { className: "flex-shrink-0 md:flex-shrink-0", children: /* @__PURE__ */ jsx2(Monogram, { color: "yellow", className: cn("h-5 w-auto", classNameLogo) }) }),
76
+ /* @__PURE__ */ jsx2("div", { className: textWrapperClasses, children: /* @__PURE__ */ jsxs2("p", { className: cn(textLayoutClasses, classNameText), children: [
77
+ /* @__PURE__ */ jsxs2("span", { children: [
78
+ /* @__PURE__ */ jsx2(
79
+ "a",
61
80
  {
81
+ href: "https://tollerud.no",
82
+ target: "_blank",
83
+ rel: "noopener noreferrer",
62
84
  className: cn(
63
- textLayoutClasses,
64
- classNameText
85
+ "underline decoration-tollerud-yellow decoration-[3px] underline-offset-[4px] hover:opacity-80 transition-opacity",
86
+ classNameLink
65
87
  ),
66
- children: [
67
- /* @__PURE__ */ jsxs("span", { children: [
68
- /* @__PURE__ */ jsx(
69
- "a",
70
- {
71
- href: "https://tollerud.no",
72
- target: "_blank",
73
- rel: "noopener noreferrer",
74
- className: cn(
75
- "underline decoration-[#ffff00] decoration-[3px] underline-offset-[4px] hover:opacity-80 transition-opacity",
76
- classNameLink
77
- ),
78
- style: {
79
- textDecorationThickness: "3px",
80
- textUnderlineOffset: "4px"
81
- },
82
- children: t.tollerudProject
83
- }
84
- ),
85
- attribution ? /* @__PURE__ */ jsxs(Fragment, { children: [
86
- " ",
87
- /* @__PURE__ */ jsx("span", { children: attribution })
88
- ] }) : null,
89
- " "
90
- ] }),
91
- /* @__PURE__ */ jsx("span", { className: layout === "row" ? "ml-1" : "md:ml-1", children: t.allRightsReserved })
92
- ]
88
+ style: {
89
+ textDecorationThickness: "3px",
90
+ textUnderlineOffset: "4px"
91
+ },
92
+ children: t.tollerudProject
93
93
  }
94
- ) })
95
- ]
96
- }
97
- ) });
94
+ ),
95
+ attribution ? /* @__PURE__ */ jsxs2(Fragment, { children: [
96
+ " ",
97
+ /* @__PURE__ */ jsx2("span", { children: attribution })
98
+ ] }) : null,
99
+ " "
100
+ ] }),
101
+ /* @__PURE__ */ jsx2("span", { className: layout === "row" ? "ml-1" : "md:ml-1", children: t.allRightsReserved })
102
+ ] }) })
103
+ ] }) });
98
104
  }
99
-
100
- export { Footer };
101
- //# sourceMappingURL=index.js.map
105
+ export {
106
+ Footer,
107
+ Monogram
108
+ };
102
109
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Footer.tsx"],"names":[],"mappings":";;;AAIA,SAAS,MAAM,KAAA,EAAsD;AACnE,EAAA,OAAO,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AACvC;AAaA,IAAM,aAAA,GAA8B;AAAA,EAClC,eAAA,EAAiB,oBAAA;AAAA,EACjB,iBAAA,EAAmB;AACrB,CAAA;AAqBO,SAAS,MAAA,CAAO;AAAA,EACrB,MAAA;AAAA,EACA,MAAA,GAAS,YAAA;AAAA,EACT,SAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA;AACF,CAAA,EAA8B;AAC5B,EAAA,MAAM,CAAA,GAAI,EAAE,GAAG,aAAA,EAAe,GAAG,MAAA,EAAO;AACxC,EAAA,MAAM,WAAA,GAAc,CAAA,CAAE,WAAA,EAAa,IAAA,EAAK;AAExC,EAAA,MAAM,aAAA,GAAgB,WAClB,EAAA,GACA,2EAAA;AAEJ,EAAA,MAAM,kBAAA,GACJ,MAAA,KAAW,KAAA,GACP,yEAAA,GACA,gHAAA;AAEN,EAAA,MAAM,kBAAA,GACJ,MAAA,KAAW,KAAA,GAAQ,wBAAA,GAA2B,0CAAA;AAEhD,EAAA,MAAM,iBAAA,GACJ,MAAA,KAAW,KAAA,GACP,yGAAA,GACA,oFAAA;AAEN,EAAA,uBACE,GAAA,CAAC,YAAO,SAAA,EAAW,EAAA,CAAG,oBAAoB,aAAA,EAAe,SAAS,GAAG,KAAA,EACnE,QAAA,kBAAA,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,kBAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,gCAAA,EACb,QAAA,kBAAA,IAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,IAAA;AAAA,YACN,MAAA,EAAO,IAAA;AAAA,YACP,OAAA,EAAQ,aAAA;AAAA,YACR,OAAA,EAAQ,KAAA;AAAA,YACR,KAAA,EAAM,4BAAA;AAAA,YACN,UAAA,EAAW,8BAAA;AAAA,YACX,SAAA,EAAW,EAAA,CAAG,wCAAA,EAA0C,aAAa,CAAA;AAAA,YACrE,IAAA,EAAK,KAAA;AAAA,YAEL,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,WAAM,QAAA,EAAA,eAAA,EAAa,CAAA;AAAA,8BACpB,GAAA,CAAC,GAAA,EAAA,EAAE,EAAA,EAAG,QAAA,EAAS,MAAA,EAAO,MAAA,EAAO,WAAA,EAAY,GAAA,EAAI,IAAA,EAAK,MAAA,EAAO,QAAA,EAAS,SAAA,EAChE,8BAAC,GAAA,EAAA,EAAE,EAAA,EAAG,mBAAA,EAAoB,SAAA,EAAU,oCAAA,EAAqC,IAAA,EAAK,cAAA,EAC5E,QAAA,kBAAA,GAAA,CAAC,OAAE,EAAA,EAAG,SAAA,EAAU,SAAA,EAAU,iCAAA,EACxB,QAAA,kBAAA,GAAA,CAAC,GAAA,EAAA,EAAE,EAAA,EAAG,OAAA,EAAQ,WAAU,iCAAA,EACtB,QAAA,kBAAA,GAAA;AAAA,gBAAC,MAAA;AAAA,gBAAA;AAAA,kBACC,CAAA,EAAE,0+CAAA;AAAA,kBACF,EAAA,EAAG;AAAA;AAAA,eACL,EACF,CAAA,EACF,CAAA,EACF,CAAA,EACF;AAAA;AAAA;AAAA,SACF,EACF,CAAA;AAAA,wBAEA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,kBAAA,EACd,QAAA,kBAAA,IAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,EAAA;AAAA,cACT,iBAAA;AAAA,cACA;AAAA,aACF;AAAA,YAEA,QAAA,EAAA;AAAA,8BAAA,IAAA,CAAC,MAAA,EAAA,EACC,QAAA,EAAA;AAAA,gCAAA,GAAA;AAAA,kBAAC,GAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,qBAAA;AAAA,oBACL,MAAA,EAAO,QAAA;AAAA,oBACP,GAAA,EAAI,qBAAA;AAAA,oBACJ,SAAA,EAAW,EAAA;AAAA,sBACT,4GAAA;AAAA,sBACA;AAAA,qBACF;AAAA,oBACA,KAAA,EAAO;AAAA,sBACL,uBAAA,EAAyB,KAAA;AAAA,sBACzB,mBAAA,EAAqB;AAAA,qBACvB;AAAA,oBAEC,QAAA,EAAA,CAAA,CAAE;AAAA;AAAA,iBACL;AAAA,gBACC,8BACC,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,kBAAA,GAAA;AAAA,kCACD,GAAA,CAAC,UAAM,QAAA,EAAA,WAAA,EAAY;AAAA,iBAAA,EACrB,CAAA,GACE,IAAA;AAAA,gBAAM;AAAA,eAAA,EACZ,CAAA;AAAA,8BACA,GAAA,CAAC,UAAK,SAAA,EAAW,MAAA,KAAW,QAAQ,MAAA,GAAS,SAAA,EAAY,YAAE,iBAAA,EAAkB;AAAA;AAAA;AAAA,SAC/E,EACF;AAAA;AAAA;AAAA,GACF,EACF,CAAA;AAEJ","file":"index.js","sourcesContent":["'use client'\n\nimport type { CSSProperties, ReactElement } from 'react'\n\nfunction cn(...parts: (string | undefined | null | false)[]): string {\n return parts.filter(Boolean).join(' ')\n}\n\nexport type FooterLabels = {\n /** Text for the tollerud.no link (e.g. A Tollerud Project). */\n tollerudProject: string\n /**\n * Optional middle segment after the link, before the rights line.\n * Example for [dispatch.tollerud.dev](https://dispatch.tollerud.dev/): `\"for Advania Norge AS.\"`\n */\n attribution?: string\n allRightsReserved: string\n}\n\nconst defaultLabels: FooterLabels = {\n tollerudProject: 'A Tollerud Project',\n allRightsReserved: 'All rights reserved.',\n}\n\nexport type FooterProps = {\n labels?: Partial<FooterLabels>\n /** Layout behavior: responsive keeps mobile-first stacking, row forces horizontal layout. */\n layout?: 'responsive' | 'row'\n /** Merged onto `<footer>`. Use for layout, surface, e.g. `border-t border-white/10 bg-black/50 backdrop-blur-sm`. */\n className?: string\n /** Merged onto `<footer>` (wins over conflicting `backgroundColor` from classes when needed). */\n style?: CSSProperties\n /**\n * When true, skips default border/background/dark surface so `className` / `style` fully control the bar\n * (avoids fighting `bg-gray-50` / `dark:bg-gray-900`).\n */\n unstyled?: boolean\n classNameInner?: string\n classNameLogo?: string\n classNameText?: string\n classNameLink?: string\n}\n\nexport function Footer({\n labels,\n layout = 'responsive',\n className,\n style,\n unstyled = false,\n classNameInner,\n classNameLogo,\n classNameText,\n classNameLink,\n}: FooterProps): ReactElement {\n const t = { ...defaultLabels, ...labels }\n const attribution = t.attribution?.trim()\n\n const footerSurface = unstyled\n ? ''\n : 'border-t border-gray-200 bg-gray-50 dark:border-gray-800 dark:bg-gray-900'\n\n const innerLayoutClasses =\n layout === 'row'\n ? 'max-w-7xl mx-auto px-8 flex flex-row items-center justify-between gap-4'\n : 'max-w-7xl mx-auto px-8 flex flex-col md:flex-row items-center justify-center md:justify-between gap-4 md:gap-0'\n\n const textWrapperClasses =\n layout === 'row' ? 'flex-1 text-right ml-4' : 'flex-1 text-center md:text-right md:ml-4'\n\n const textLayoutClasses =\n layout === 'row'\n ? 'text-sm text-gray-600 dark:text-gray-400 inline-flex flex-row items-center justify-end text-right gap-0'\n : 'text-sm text-gray-600 dark:text-gray-400 flex flex-col md:flex-row md:inline gap-0'\n\n return (\n <footer className={cn('w-full pt-4 pb-4', footerSurface, className)} style={style}>\n <div\n className={cn(\n innerLayoutClasses,\n classNameInner,\n )}\n >\n <div className=\"flex-shrink-0 md:flex-shrink-0\">\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 130 143\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlnsXlink=\"http://www.w3.org/1999/xlink\"\n className={cn('h-5 w-5 text-black dark:text-[#ffff00]', classNameLogo)}\n role=\"img\"\n >\n <title>Tollerud Logo</title>\n <g id=\"Page-1\" stroke=\"none\" strokeWidth=\"1\" fill=\"none\" fillRule=\"evenodd\">\n <g id=\"Tollerud Monogram\" transform=\"translate(-86.000000, -109.000000)\" fill=\"currentColor\">\n <g id=\"Group-2\" transform=\"translate(32.000000, 55.000000)\">\n <g id=\"Group\" transform=\"translate(54.000000, 54.000000)\">\n <path\n d=\"M82.4839273,140.272626 L95.1738252,140.272626 L95.1738252,143 L34.8114657,143 L34.8114657,140.272626 L47.5013636,140.272626 L47.5013636,28.2924381 C40.1277806,26.4177752 32.9252955,25.2241422 26.4088393,25.2241422 C12.1757856,25.2241422 4.11617359,34.5982703 4.11617359,39.8821508 C4.11617359,40.9049161 4.63028596,41.5867596 5.65932936,41.5867596 C7.20248513,41.5867596 7.37440169,40.3931266 8.06043062,38.8593855 C10.4615319,33.575505 15.6059302,31.5307881 20.4073141,31.5307881 C29.152955,31.5307881 35.1552988,38.5184637 35.1552988,47.2107482 C35.1552988,56.2447681 28.8107592,62.8907084 18.0070315,62.8907084 C7.5454996,62.891522 0,53.6882617 0,43.8023442 C0,30.8497582 11.3178401,21.986606 26.5799372,21.986606 C51.1026062,21.986606 84.1989996,39.2011209 104.948509,39.2011209 C118.495534,39.2011209 126.384048,31.7016558 126.384048,19.4300996 C126.384048,10.3968933 118.667451,4.60203698 115.580321,4.60203698 C114.552096,4.60203698 113.69415,5.1130128 113.69415,6.13577809 C113.69415,7.49946515 114.552096,7.6695192 115.409223,8.01044097 C115.752237,8.18049502 122.268693,10.5669474 122.268693,19.2592319 C122.268693,28.2924381 115.238125,34.0872945 107.177694,34.0872945 C97.7460244,34.0872945 91.0584702,26.4177752 91.0584702,17.8955448 C91.0584702,6.64675391 99.9760277,0 109.749893,0 C122.268693,0 129.642276,9.88510384 129.642276,19.6001536 C129.642276,34.2581622 119.181563,42.4386572 104.947691,42.4386572 C98.0890388,42.4386572 90.5443579,40.9049161 82.4839273,38.6901451 L82.4839273,140.272626 Z\"\n id=\"Monogram\"\n />\n </g>\n </g>\n </g>\n </g>\n </svg>\n </div>\n\n <div className={textWrapperClasses}>\n <p\n className={cn(\n textLayoutClasses,\n classNameText,\n )}\n >\n <span>\n <a\n href=\"https://tollerud.no\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n 'underline decoration-[#ffff00] decoration-[3px] underline-offset-[4px] hover:opacity-80 transition-opacity',\n classNameLink,\n )}\n style={{\n textDecorationThickness: '3px',\n textUnderlineOffset: '4px',\n }}\n >\n {t.tollerudProject}\n </a>\n {attribution ? (\n <>\n {' '}\n <span>{attribution}</span>\n </>\n ) : null}{' '}\n </span>\n <span className={layout === 'row' ? 'ml-1' : 'md:ml-1'}>{t.allRightsReserved}</span>\n </p>\n </div>\n </div>\n </footer>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/utils.ts","../src/Monogram.tsx","../src/monogram-geometry.ts","../src/Footer.tsx"],"sourcesContent":["import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import { forwardRef, type SVGAttributes } from 'react'\nimport { cn } from './utils'\nimport { MONOGRAM_PATH, MONOGRAM_VIEW_BOX } from './monogram-geometry'\n\nexport type MonogramColor = 'yellow' | 'black' | 'white'\n\nconst colorClasses: Record<MonogramColor, string> = {\n yellow: 'text-tollerud-yellow',\n black: 'text-tollerud-noir-950',\n white: 'text-white',\n}\n\nexport interface MonogramProps extends SVGAttributes<SVGSVGElement> {\n /**\n * Fill color via `currentColor`.\n * - `yellow` — default on dark surfaces (#FFFF00)\n * - `black` — light-mode surfaces (#0A0A0A)\n * - `white` — on tinted or photographic backgrounds\n */\n color?: MonogramColor\n /** Height in px; width scales from the 130×143 viewBox. */\n size?: number\n /** Accessible name — rendered as `<title>` and `aria-label`. */\n title?: string\n}\n\nconst Monogram = forwardRef<SVGSVGElement, MonogramProps>(\n ({ color = 'yellow', size, className, title = 'Tollerud', style, ...props }, ref) => {\n return (\n <svg\n ref={ref}\n viewBox={MONOGRAM_VIEW_BOX}\n xmlns=\"http://www.w3.org/2000/svg\"\n role=\"img\"\n aria-label={title}\n className={cn(\n 'inline-block shrink-0',\n colorClasses[color],\n !size && 'h-5 w-auto',\n className\n )}\n style={size ? { height: size, width: 'auto', ...style } : style}\n {...props}\n >\n <title>{title}</title>\n <g fill=\"currentColor\" fillRule=\"evenodd\">\n <g transform=\"translate(-86.000000, -109.000000)\">\n <g transform=\"translate(32.000000, 55.000000)\">\n <g transform=\"translate(54.000000, 54.000000)\">\n <path d={MONOGRAM_PATH} />\n </g>\n </g>\n </g>\n </g>\n </svg>\n )\n }\n)\nMonogram.displayName = 'Monogram'\n\nexport { Monogram }\n","/** Shared Tollerud monogram geometry — single continuous T path. */\nexport const MONOGRAM_VIEW_BOX = '0 0 130 143'\n\nexport const MONOGRAM_PATH =\n 'M82.4839273,140.272626 L95.1738252,140.272626 L95.1738252,143 L34.8114657,143 L34.8114657,140.272626 L47.5013636,140.272626 L47.5013636,28.2924381 C40.1277806,26.4177752 32.9252955,25.2241422 26.4088393,25.2241422 C12.1757856,25.2241422 4.11617359,34.5982703 4.11617359,39.8821508 C4.11617359,40.9049161 4.63028596,41.5867596 5.65932936,41.5867596 C7.20248513,41.5867596 7.37440169,40.3931266 8.06043062,38.8593855 C10.4615319,33.575505 15.6059302,31.5307881 20.4073141,31.5307881 C29.152955,31.5307881 35.1552988,38.5184637 35.1552988,47.2107482 C35.1552988,56.2447681 28.8107592,62.8907084 18.0070315,62.8907084 C7.5454996,62.891522 0,53.6882617 0,43.8023442 C0,30.8497582 11.3178401,21.986606 26.5799372,21.986606 C51.1026062,21.986606 84.1989996,39.2011209 104.948509,39.2011209 C118.495534,39.2011209 126.384048,31.7016558 126.384048,19.4300996 C126.384048,10.3968933 118.667451,4.60203698 115.580321,4.60203698 C114.552096,4.60203698 113.69415,5.1130128 113.69415,6.13577809 C113.69415,7.49946515 114.552096,7.6695192 115.409223,8.01044097 C115.752237,8.18049502 122.268693,10.5669474 122.268693,19.2592319 C122.268693,28.2924381 115.238125,34.0872945 107.177694,34.0872945 C97.7460244,34.0872945 91.0584702,26.4177752 91.0584702,17.8955448 C91.0584702,6.64675391 99.9760277,0 109.749893,0 C122.268693,0 129.642276,9.88510384 129.642276,19.6001536 C129.642276,34.2581622 119.181563,42.4386572 104.947691,42.4386572 C98.0890388,42.4386572 90.5443579,40.9049161 82.4839273,38.6901451 L82.4839273,140.272626 Z'\n","'use client'\n\nimport type { CSSProperties, ReactElement } from 'react'\nimport { cn } from './utils'\nimport { Monogram } from './Monogram'\n\nexport type FooterLabels = {\n /** Text for the tollerud.no link (e.g. \"A Tollerud Project\"). */\n tollerudProject: string\n /**\n * Optional middle segment after the link, before the rights line.\n * Example for Advania: `\"for Advania Norge AS.\"`\n */\n attribution?: string\n allRightsReserved: string\n}\n\nconst defaultLabels: FooterLabels = {\n tollerudProject: 'A Tollerud Project',\n allRightsReserved: 'All rights reserved.',\n}\n\nexport type FooterProps = {\n labels?: Partial<FooterLabels>\n /** Layout behavior: responsive keeps mobile-first stacking, row forces horizontal layout. */\n layout?: 'responsive' | 'row'\n /** Merged onto <footer>. Use for extra layout, padding, etc. */\n className?: string\n /** Merged onto <footer> (wins over conflicting backgroundColor from classes when needed). */\n style?: CSSProperties\n /**\n * When true, skips all default surface styling so className/style fully control the bar\n * (avoids fighting default background/border).\n */\n unstyled?: boolean\n /** When true, uses accent (yellow) surface instead of neutral dark. */\n accent?: boolean\n classNameInner?: string\n classNameLogo?: string\n classNameText?: string\n classNameLink?: string\n}\n\nexport function Footer({\n labels,\n layout = 'responsive',\n className,\n style,\n unstyled = false,\n accent = false,\n classNameInner,\n classNameLogo,\n classNameText,\n classNameLink,\n}: FooterProps): ReactElement {\n const t = { ...defaultLabels, ...labels }\n const attribution = t.attribution?.trim()\n\n const footerSurface = unstyled\n ? ''\n : accent\n ? 'border-t border-tollerud-yellow/20 bg-tollerud-yellow/5'\n : 'border-t border-tollerud-border bg-tollerud-noir-900/80'\n\n const innerLayoutClasses =\n layout === 'row'\n ? 'max-w-7xl mx-auto px-8 flex flex-row items-center justify-between gap-4'\n : 'max-w-7xl mx-auto px-8 flex flex-col md:flex-row items-center justify-center md:justify-between gap-4 md:gap-0'\n\n const textWrapperClasses =\n layout === 'row' ? 'flex-1 text-right ml-4' : 'flex-1 text-center md:text-right md:ml-4'\n\n const textLayoutClasses =\n layout === 'row'\n ? 'text-sm text-tollerud-text-secondary inline-flex flex-row items-center justify-end text-right gap-0'\n : 'text-sm text-tollerud-text-secondary flex flex-col md:flex-row md:inline gap-0'\n\n return (\n <footer className={cn('w-full pt-4 pb-4', footerSurface, className)} style={style}>\n <div className={cn(innerLayoutClasses, classNameInner)}>\n <div className=\"flex-shrink-0 md:flex-shrink-0\">\n <Monogram color=\"yellow\" className={cn('h-5 w-auto', classNameLogo)} />\n </div>\n\n <div className={textWrapperClasses}>\n <p className={cn(textLayoutClasses, classNameText)}>\n <span>\n <a\n href=\"https://tollerud.no\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n 'underline decoration-tollerud-yellow decoration-[3px] underline-offset-[4px] hover:opacity-80 transition-opacity',\n classNameLink,\n )}\n style={{\n textDecorationThickness: '3px',\n textUnderlineOffset: '4px',\n }}\n >\n {t.tollerudProject}\n </a>\n {attribution ? (\n <>\n {' '}\n <span>{attribution}</span>\n </>\n ) : null}{' '}\n </span>\n <span className={layout === 'row' ? 'ml-1' : 'md:ml-1'}>{t.allRightsReserved}</span>\n </p>\n </div>\n </div>\n </footer>\n )\n}"],"mappings":";AAAA,SAA0B,YAAY;AACtC,SAAS,eAAe;AAEjB,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;ACLA,SAAS,kBAAsC;;;ACCxC,IAAM,oBAAoB;AAE1B,IAAM,gBACX;;;ADyBI,SAeE,KAfF;AAvBN,IAAM,eAA8C;AAAA,EAClD,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AACT;AAgBA,IAAM,WAAW;AAAA,EACf,CAAC,EAAE,QAAQ,UAAU,MAAM,WAAW,QAAQ,YAAY,OAAO,GAAG,MAAM,GAAG,QAAQ;AACnF,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,SAAS;AAAA,QACT,OAAM;AAAA,QACN,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,WAAW;AAAA,UACT;AAAA,UACA,aAAa,KAAK;AAAA,UAClB,CAAC,QAAQ;AAAA,UACT;AAAA,QACF;AAAA,QACA,OAAO,OAAO,EAAE,QAAQ,MAAM,OAAO,QAAQ,GAAG,MAAM,IAAI;AAAA,QACzD,GAAG;AAAA,QAEJ;AAAA,8BAAC,WAAO,iBAAM;AAAA,UACd,oBAAC,OAAE,MAAK,gBAAe,UAAS,WAC9B,8BAAC,OAAE,WAAU,sCACX,8BAAC,OAAE,WAAU,mCACX,8BAAC,OAAE,WAAU,mCACX,8BAAC,UAAK,GAAG,eAAe,GAC1B,GACF,GACF,GACF;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;AACA,SAAS,cAAc;;;AEuBb,SAsBM,UAtBN,OAAAA,MAsBM,QAAAC,aAtBN;AAhEV,IAAM,gBAA8B;AAAA,EAClC,iBAAiB;AAAA,EACjB,mBAAmB;AACrB;AAuBO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA8B;AAC5B,QAAM,IAAI,EAAE,GAAG,eAAe,GAAG,OAAO;AACxC,QAAM,cAAc,EAAE,aAAa,KAAK;AAExC,QAAM,gBAAgB,WAClB,KACA,SACE,4DACA;AAEN,QAAM,qBACJ,WAAW,QACP,4EACA;AAEN,QAAM,qBACJ,WAAW,QAAQ,2BAA2B;AAEhD,QAAM,oBACJ,WAAW,QACP,wGACA;AAEN,SACE,gBAAAD,KAAC,YAAO,WAAW,GAAG,oBAAoB,eAAe,SAAS,GAAG,OACnE,0BAAAC,MAAC,SAAI,WAAW,GAAG,oBAAoB,cAAc,GACnD;AAAA,oBAAAD,KAAC,SAAI,WAAU,kCACb,0BAAAA,KAAC,YAAS,OAAM,UAAS,WAAW,GAAG,cAAc,aAAa,GAAG,GACvE;AAAA,IAEA,gBAAAA,KAAC,SAAI,WAAW,oBACd,0BAAAC,MAAC,OAAE,WAAW,GAAG,mBAAmB,aAAa,GAC/C;AAAA,sBAAAA,MAAC,UACC;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,QAAO;AAAA,YACP,KAAI;AAAA,YACJ,WAAW;AAAA,cACT;AAAA,cACA;AAAA,YACF;AAAA,YACA,OAAO;AAAA,cACL,yBAAyB;AAAA,cACzB,qBAAqB;AAAA,YACvB;AAAA,YAEC,YAAE;AAAA;AAAA,QACL;AAAA,QACC,cACC,gBAAAC,MAAA,YACG;AAAA;AAAA,UACD,gBAAAD,KAAC,UAAM,uBAAY;AAAA,WACrB,IACE;AAAA,QAAM;AAAA,SACZ;AAAA,MACA,gBAAAA,KAAC,UAAK,WAAW,WAAW,QAAQ,SAAS,WAAY,YAAE,mBAAkB;AAAA,OAC/E,GACF;AAAA,KACF,GACF;AAEJ;","names":["jsx","jsxs"]}
package/package.json CHANGED
@@ -1,21 +1,19 @@
1
1
  {
2
2
  "name": "@tollerud/footer",
3
- "version": "1.1.3",
4
- "description": "Default site footer with Tollerud monogram and branding link",
5
- "license": "MIT",
6
- "author": "",
3
+ "version": "4.0.3",
4
+ "description": "Tollerud branded footer synced from @tollerud/ui Footer export",
5
+ "private": false,
6
+ "type": "module",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/tollerud/tollerud-footer.git"
9
+ "url": "git+https://github.com/Tollerud/ui.git",
10
+ "directory": "packages/footer"
10
11
  },
11
- "keywords": [
12
- "footer",
13
- "react",
14
- "tollerud",
15
- "nextjs"
16
- ],
17
- "type": "module",
18
- "main": "./dist/index.cjs",
12
+ "homepage": "https://design.tollerud.dev/",
13
+ "license": "MIT",
14
+ "author": "Mathias Tollerud <mathias@tollerud.no>",
15
+ "sideEffects": false,
16
+ "main": "./dist/index.js",
19
17
  "module": "./dist/index.js",
20
18
  "types": "./dist/index.d.ts",
21
19
  "exports": {
@@ -23,28 +21,28 @@
23
21
  "import": {
24
22
  "types": "./dist/index.d.ts",
25
23
  "default": "./dist/index.js"
26
- },
27
- "require": {
28
- "types": "./dist/index.d.ts",
29
- "default": "./dist/index.cjs"
30
24
  }
31
25
  }
32
26
  },
33
27
  "files": [
34
28
  "dist"
35
29
  ],
36
- "sideEffects": false,
37
30
  "scripts": {
38
- "build": "tsup",
39
- "prepublishOnly": "npm run build"
31
+ "build": "tsup src/index.ts --format esm --dts --clean",
32
+ "typecheck": "tsc --noEmit"
40
33
  },
41
34
  "peerDependencies": {
42
- "react": "^18.0.0 || ^19.0.0"
35
+ "react": ">=18",
36
+ "react-dom": ">=18"
37
+ },
38
+ "dependencies": {
39
+ "clsx": "^2.1.1",
40
+ "tailwind-merge": "^3.0.0"
43
41
  },
44
42
  "devDependencies": {
45
- "@types/react": "^19.0.0",
46
43
  "react": "^19.0.0",
47
- "tsup": "^8.3.5",
48
- "typescript": "^5.7.2"
44
+ "react-dom": "^19.0.0",
45
+ "tsup": "^8.5.0",
46
+ "typescript": "^5.8.0"
49
47
  }
50
48
  }
package/README.md DELETED
@@ -1,144 +0,0 @@
1
- # @tollerud/footer
2
-
3
- React footer with the Tollerud monogram, link to [tollerud.no](https://tollerud.no), optional attribution (e.g. client name), and composable Tailwind-friendly classes. Matches copy used on [dispatch.tollerud.dev](https://dispatch.tollerud.dev/) adds an extra “for …” segment.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install @tollerud/footer
9
- ```
10
-
11
- Peer dependency: `react` ^18 or ^19.
12
-
13
- ## Tailwind
14
-
15
- So Tailwind can see classes inside this package, add it to `content` in `tailwind.config`:
16
-
17
- ```js
18
- content: [
19
- './app/**/*.{js,ts,jsx,tsx,mdx}',
20
- './node_modules/@tollerud/footer/dist/**/*.{js,mjs,cjs}',
21
- ],
22
- ```
23
-
24
- (Adjust paths to match your app; including `src` is fine if you use that layout.)
25
-
26
- ## Usage
27
-
28
- ```tsx
29
- import { Footer } from '@tollerud/footer'
30
-
31
- export default function Layout({ children }: { children: React.ReactNode }) {
32
- return (
33
- <>
34
- {children}
35
- <Footer />
36
- </>
37
- )
38
- }
39
- ```
40
-
41
- ### With your `useLanguage` / i18n
42
-
43
- Pass strings from your app; the package does not depend on `@/contexts`:
44
-
45
- ```tsx
46
- 'use client'
47
-
48
- import { Footer } from '@tollerud/footer'
49
- import { useLanguage } from '@/contexts/LanguageContext'
50
-
51
- export function SiteFooter() {
52
- const { t } = useLanguage()
53
- return (
54
- <Footer
55
- labels={{
56
- tollerudProject: t.footer.tollerudProject,
57
- allRightsReserved: t.footer.allRightsReserved,
58
- }}
59
- />
60
- )
61
- }
62
- ```
63
-
64
- Default English copy matches the public sites: **“A Tollerud Project”** and **“All rights reserved.”** Omit keys you do not need to override.
65
-
66
- ### Attribution (Dispatch-style)
67
-
68
- ```tsx
69
- <Footer
70
- labels={{
71
- attribution: 'for Advania Norge AS.',
72
- }}
73
- />
74
- ```
75
-
76
- Renders: **A Tollerud Project** (linked) **for Advania Norge AS.** All rights reserved.
77
-
78
- ### Force horizontal layout
79
-
80
- By default, the component uses a responsive/mobile-first layout:
81
- - stacked on small screens
82
- - row layout from `md` and up
83
-
84
- If a host app needs always-horizontal layout (logo left, text right), use `layout="row"`:
85
-
86
- ```tsx
87
- <Footer
88
- layout="row"
89
- classNameLogo="h-5 w-5 text-black dark:text-[#ffff00]"
90
- classNameLink="underline decoration-[#ffff00] decoration-[3px] underline-offset-[4px] hover:opacity-80 transition-opacity"
91
- />
92
- ```
93
-
94
- `layout` options:
95
- - `responsive` (default): `flex-col md:flex-row` behavior
96
- - `row`: always horizontal `flex-row` behavior
97
-
98
- ### Custom surface (any background)
99
-
100
- Default footer applies `bg-gray-50` / `dark:bg-gray-900` and a top border. For overlays (e.g. **50% black** on top of imagery or video), use **`unstyled`** and pass your own surface classes or inline styles so you are not fighting those defaults:
101
-
102
- ```tsx
103
- <Footer
104
- unstyled
105
- className="border-t border-white/10 bg-black/50 backdrop-blur-sm"
106
- classNameText="text-sm text-white/90"
107
- classNameLogo="h-5 w-5 text-[#ffff00]"
108
- classNameLink="decoration-[#ffff00] text-white/95"
109
- />
110
- ```
111
-
112
- Same idea with inline style:
113
-
114
- ```tsx
115
- <Footer
116
- unstyled
117
- className="border-t border-white/10 backdrop-blur-sm"
118
- style={{ backgroundColor: 'rgba(0, 0, 0, 0.5)' }}
119
- classNameText="text-sm text-white/90"
120
- classNameLogo="h-5 w-5 text-[#ffff00]"
121
- />
122
- ```
123
-
124
- Props: `layout`, `className` / `style` on `<footer>`, `classNameInner` on the inner max-width row, `classNameLogo`, `classNameText`, `classNameLink`. Tailwind’s build must still scan this package (see above).
125
-
126
- ## Develop and publish
127
-
128
- ```bash
129
- npm install
130
- npm run build
131
- npm pack # optional: inspect tarball
132
- ```
133
-
134
- 1. [Create an npm account](https://www.npmjs.com/signup) and log in: `npm login`.
135
- 2. For a scoped name (`@tollerud/footer`), either publish as public the first time:
136
-
137
- ```bash
138
- npm publish --access public
139
- ```
140
-
141
- or create the `@tollerud` org on npm and add your user.
142
- 3. Update `repository`, `author`, and `name` in `package.json` if your scope or repo differs.
143
-
144
- After publish, bump version with `npm version patch|minor|major` and `npm publish --access public` again for updates.
package/dist/index.cjs DELETED
@@ -1,104 +0,0 @@
1
- 'use strict';
2
-
3
- var jsxRuntime = require('react/jsx-runtime');
4
-
5
- // src/Footer.tsx
6
- function cn(...parts) {
7
- return parts.filter(Boolean).join(" ");
8
- }
9
- var defaultLabels = {
10
- tollerudProject: "A Tollerud Project",
11
- allRightsReserved: "All rights reserved."
12
- };
13
- function Footer({
14
- labels,
15
- layout = "responsive",
16
- className,
17
- style,
18
- unstyled = false,
19
- classNameInner,
20
- classNameLogo,
21
- classNameText,
22
- classNameLink
23
- }) {
24
- const t = { ...defaultLabels, ...labels };
25
- const attribution = t.attribution?.trim();
26
- const footerSurface = unstyled ? "" : "border-t border-gray-200 bg-gray-50 dark:border-gray-800 dark:bg-gray-900";
27
- const innerLayoutClasses = layout === "row" ? "max-w-7xl mx-auto px-8 flex flex-row items-center justify-between gap-4" : "max-w-7xl mx-auto px-8 flex flex-col md:flex-row items-center justify-center md:justify-between gap-4 md:gap-0";
28
- const textWrapperClasses = layout === "row" ? "flex-1 text-right ml-4" : "flex-1 text-center md:text-right md:ml-4";
29
- const textLayoutClasses = layout === "row" ? "text-sm text-gray-600 dark:text-gray-400 inline-flex flex-row items-center justify-end text-right gap-0" : "text-sm text-gray-600 dark:text-gray-400 flex flex-col md:flex-row md:inline gap-0";
30
- return /* @__PURE__ */ jsxRuntime.jsx("footer", { className: cn("w-full pt-4 pb-4", footerSurface, className), style, children: /* @__PURE__ */ jsxRuntime.jsxs(
31
- "div",
32
- {
33
- className: cn(
34
- innerLayoutClasses,
35
- classNameInner
36
- ),
37
- children: [
38
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 md:flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
39
- "svg",
40
- {
41
- width: "24",
42
- height: "24",
43
- viewBox: "0 0 130 143",
44
- version: "1.1",
45
- xmlns: "http://www.w3.org/2000/svg",
46
- xmlnsXlink: "http://www.w3.org/1999/xlink",
47
- className: cn("h-5 w-5 text-black dark:text-[#ffff00]", classNameLogo),
48
- role: "img",
49
- children: [
50
- /* @__PURE__ */ jsxRuntime.jsx("title", { children: "Tollerud Logo" }),
51
- /* @__PURE__ */ jsxRuntime.jsx("g", { id: "Page-1", stroke: "none", strokeWidth: "1", fill: "none", fillRule: "evenodd", children: /* @__PURE__ */ jsxRuntime.jsx("g", { id: "Tollerud Monogram", transform: "translate(-86.000000, -109.000000)", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("g", { id: "Group-2", transform: "translate(32.000000, 55.000000)", children: /* @__PURE__ */ jsxRuntime.jsx("g", { id: "Group", transform: "translate(54.000000, 54.000000)", children: /* @__PURE__ */ jsxRuntime.jsx(
52
- "path",
53
- {
54
- d: "M82.4839273,140.272626 L95.1738252,140.272626 L95.1738252,143 L34.8114657,143 L34.8114657,140.272626 L47.5013636,140.272626 L47.5013636,28.2924381 C40.1277806,26.4177752 32.9252955,25.2241422 26.4088393,25.2241422 C12.1757856,25.2241422 4.11617359,34.5982703 4.11617359,39.8821508 C4.11617359,40.9049161 4.63028596,41.5867596 5.65932936,41.5867596 C7.20248513,41.5867596 7.37440169,40.3931266 8.06043062,38.8593855 C10.4615319,33.575505 15.6059302,31.5307881 20.4073141,31.5307881 C29.152955,31.5307881 35.1552988,38.5184637 35.1552988,47.2107482 C35.1552988,56.2447681 28.8107592,62.8907084 18.0070315,62.8907084 C7.5454996,62.891522 0,53.6882617 0,43.8023442 C0,30.8497582 11.3178401,21.986606 26.5799372,21.986606 C51.1026062,21.986606 84.1989996,39.2011209 104.948509,39.2011209 C118.495534,39.2011209 126.384048,31.7016558 126.384048,19.4300996 C126.384048,10.3968933 118.667451,4.60203698 115.580321,4.60203698 C114.552096,4.60203698 113.69415,5.1130128 113.69415,6.13577809 C113.69415,7.49946515 114.552096,7.6695192 115.409223,8.01044097 C115.752237,8.18049502 122.268693,10.5669474 122.268693,19.2592319 C122.268693,28.2924381 115.238125,34.0872945 107.177694,34.0872945 C97.7460244,34.0872945 91.0584702,26.4177752 91.0584702,17.8955448 C91.0584702,6.64675391 99.9760277,0 109.749893,0 C122.268693,0 129.642276,9.88510384 129.642276,19.6001536 C129.642276,34.2581622 119.181563,42.4386572 104.947691,42.4386572 C98.0890388,42.4386572 90.5443579,40.9049161 82.4839273,38.6901451 L82.4839273,140.272626 Z",
55
- id: "Monogram"
56
- }
57
- ) }) }) }) })
58
- ]
59
- }
60
- ) }),
61
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: textWrapperClasses, children: /* @__PURE__ */ jsxRuntime.jsxs(
62
- "p",
63
- {
64
- className: cn(
65
- textLayoutClasses,
66
- classNameText
67
- ),
68
- children: [
69
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
70
- /* @__PURE__ */ jsxRuntime.jsx(
71
- "a",
72
- {
73
- href: "https://tollerud.no",
74
- target: "_blank",
75
- rel: "noopener noreferrer",
76
- className: cn(
77
- "underline decoration-[#ffff00] decoration-[3px] underline-offset-[4px] hover:opacity-80 transition-opacity",
78
- classNameLink
79
- ),
80
- style: {
81
- textDecorationThickness: "3px",
82
- textUnderlineOffset: "4px"
83
- },
84
- children: t.tollerudProject
85
- }
86
- ),
87
- attribution ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
88
- " ",
89
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: attribution })
90
- ] }) : null,
91
- " "
92
- ] }),
93
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: layout === "row" ? "ml-1" : "md:ml-1", children: t.allRightsReserved })
94
- ]
95
- }
96
- ) })
97
- ]
98
- }
99
- ) });
100
- }
101
-
102
- exports.Footer = Footer;
103
- //# sourceMappingURL=index.cjs.map
104
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/Footer.tsx"],"names":["jsx","jsxs","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["'use client'\n\nimport type { CSSProperties, ReactElement } from 'react'\n\nfunction cn(...parts: (string | undefined | null | false)[]): string {\n return parts.filter(Boolean).join(' ')\n}\n\nexport type FooterLabels = {\n /** Text for the tollerud.no link (e.g. “A Tollerud Project”). */\n tollerudProject: string\n /**\n * Optional middle segment after the link, before the rights line.\n * Example for [dispatch.tollerud.dev](https://dispatch.tollerud.dev/): `\"for Advania Norge AS.\"`\n */\n attribution?: string\n allRightsReserved: string\n}\n\nconst defaultLabels: FooterLabels = {\n tollerudProject: 'A Tollerud Project',\n allRightsReserved: 'All rights reserved.',\n}\n\nexport type FooterProps = {\n labels?: Partial<FooterLabels>\n /** Layout behavior: responsive keeps mobile-first stacking, row forces horizontal layout. */\n layout?: 'responsive' | 'row'\n /** Merged onto `<footer>`. Use for layout, surface, e.g. `border-t border-white/10 bg-black/50 backdrop-blur-sm`. */\n className?: string\n /** Merged onto `<footer>` (wins over conflicting `backgroundColor` from classes when needed). */\n style?: CSSProperties\n /**\n * When true, skips default border/background/dark surface so `className` / `style` fully control the bar\n * (avoids fighting `bg-gray-50` / `dark:bg-gray-900`).\n */\n unstyled?: boolean\n classNameInner?: string\n classNameLogo?: string\n classNameText?: string\n classNameLink?: string\n}\n\nexport function Footer({\n labels,\n layout = 'responsive',\n className,\n style,\n unstyled = false,\n classNameInner,\n classNameLogo,\n classNameText,\n classNameLink,\n}: FooterProps): ReactElement {\n const t = { ...defaultLabels, ...labels }\n const attribution = t.attribution?.trim()\n\n const footerSurface = unstyled\n ? ''\n : 'border-t border-gray-200 bg-gray-50 dark:border-gray-800 dark:bg-gray-900'\n\n const innerLayoutClasses =\n layout === 'row'\n ? 'max-w-7xl mx-auto px-8 flex flex-row items-center justify-between gap-4'\n : 'max-w-7xl mx-auto px-8 flex flex-col md:flex-row items-center justify-center md:justify-between gap-4 md:gap-0'\n\n const textWrapperClasses =\n layout === 'row' ? 'flex-1 text-right ml-4' : 'flex-1 text-center md:text-right md:ml-4'\n\n const textLayoutClasses =\n layout === 'row'\n ? 'text-sm text-gray-600 dark:text-gray-400 inline-flex flex-row items-center justify-end text-right gap-0'\n : 'text-sm text-gray-600 dark:text-gray-400 flex flex-col md:flex-row md:inline gap-0'\n\n return (\n <footer className={cn('w-full pt-4 pb-4', footerSurface, className)} style={style}>\n <div\n className={cn(\n innerLayoutClasses,\n classNameInner,\n )}\n >\n <div className=\"flex-shrink-0 md:flex-shrink-0\">\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 130 143\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlnsXlink=\"http://www.w3.org/1999/xlink\"\n className={cn('h-5 w-5 text-black dark:text-[#ffff00]', classNameLogo)}\n role=\"img\"\n >\n <title>Tollerud Logo</title>\n <g id=\"Page-1\" stroke=\"none\" strokeWidth=\"1\" fill=\"none\" fillRule=\"evenodd\">\n <g id=\"Tollerud Monogram\" transform=\"translate(-86.000000, -109.000000)\" fill=\"currentColor\">\n <g id=\"Group-2\" transform=\"translate(32.000000, 55.000000)\">\n <g id=\"Group\" transform=\"translate(54.000000, 54.000000)\">\n <path\n d=\"M82.4839273,140.272626 L95.1738252,140.272626 L95.1738252,143 L34.8114657,143 L34.8114657,140.272626 L47.5013636,140.272626 L47.5013636,28.2924381 C40.1277806,26.4177752 32.9252955,25.2241422 26.4088393,25.2241422 C12.1757856,25.2241422 4.11617359,34.5982703 4.11617359,39.8821508 C4.11617359,40.9049161 4.63028596,41.5867596 5.65932936,41.5867596 C7.20248513,41.5867596 7.37440169,40.3931266 8.06043062,38.8593855 C10.4615319,33.575505 15.6059302,31.5307881 20.4073141,31.5307881 C29.152955,31.5307881 35.1552988,38.5184637 35.1552988,47.2107482 C35.1552988,56.2447681 28.8107592,62.8907084 18.0070315,62.8907084 C7.5454996,62.891522 0,53.6882617 0,43.8023442 C0,30.8497582 11.3178401,21.986606 26.5799372,21.986606 C51.1026062,21.986606 84.1989996,39.2011209 104.948509,39.2011209 C118.495534,39.2011209 126.384048,31.7016558 126.384048,19.4300996 C126.384048,10.3968933 118.667451,4.60203698 115.580321,4.60203698 C114.552096,4.60203698 113.69415,5.1130128 113.69415,6.13577809 C113.69415,7.49946515 114.552096,7.6695192 115.409223,8.01044097 C115.752237,8.18049502 122.268693,10.5669474 122.268693,19.2592319 C122.268693,28.2924381 115.238125,34.0872945 107.177694,34.0872945 C97.7460244,34.0872945 91.0584702,26.4177752 91.0584702,17.8955448 C91.0584702,6.64675391 99.9760277,0 109.749893,0 C122.268693,0 129.642276,9.88510384 129.642276,19.6001536 C129.642276,34.2581622 119.181563,42.4386572 104.947691,42.4386572 C98.0890388,42.4386572 90.5443579,40.9049161 82.4839273,38.6901451 L82.4839273,140.272626 Z\"\n id=\"Monogram\"\n />\n </g>\n </g>\n </g>\n </g>\n </svg>\n </div>\n\n <div className={textWrapperClasses}>\n <p\n className={cn(\n textLayoutClasses,\n classNameText,\n )}\n >\n <span>\n <a\n href=\"https://tollerud.no\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n 'underline decoration-[#ffff00] decoration-[3px] underline-offset-[4px] hover:opacity-80 transition-opacity',\n classNameLink,\n )}\n style={{\n textDecorationThickness: '3px',\n textUnderlineOffset: '4px',\n }}\n >\n {t.tollerudProject}\n </a>\n {attribution ? (\n <>\n {' '}\n <span>{attribution}</span>\n </>\n ) : null}{' '}\n </span>\n <span className={layout === 'row' ? 'ml-1' : 'md:ml-1'}>{t.allRightsReserved}</span>\n </p>\n </div>\n </div>\n </footer>\n )\n}\n"]}
package/dist/index.d.cts DELETED
@@ -1,33 +0,0 @@
1
- import { CSSProperties, ReactElement } from 'react';
2
-
3
- type FooterLabels = {
4
- /** Text for the tollerud.no link (e.g. “A Tollerud Project”). */
5
- tollerudProject: string;
6
- /**
7
- * Optional middle segment after the link, before the rights line.
8
- * Example for [dispatch.tollerud.dev](https://dispatch.tollerud.dev/): `"for Advania Norge AS."`
9
- */
10
- attribution?: string;
11
- allRightsReserved: string;
12
- };
13
- type FooterProps = {
14
- labels?: Partial<FooterLabels>;
15
- /** Layout behavior: responsive keeps mobile-first stacking, row forces horizontal layout. */
16
- layout?: 'responsive' | 'row';
17
- /** Merged onto `<footer>`. Use for layout, surface, e.g. `border-t border-white/10 bg-black/50 backdrop-blur-sm`. */
18
- className?: string;
19
- /** Merged onto `<footer>` (wins over conflicting `backgroundColor` from classes when needed). */
20
- style?: CSSProperties;
21
- /**
22
- * When true, skips default border/background/dark surface so `className` / `style` fully control the bar
23
- * (avoids fighting `bg-gray-50` / `dark:bg-gray-900`).
24
- */
25
- unstyled?: boolean;
26
- classNameInner?: string;
27
- classNameLogo?: string;
28
- classNameText?: string;
29
- classNameLink?: string;
30
- };
31
- declare function Footer({ labels, layout, className, style, unstyled, classNameInner, classNameLogo, classNameText, classNameLink, }: FooterProps): ReactElement;
32
-
33
- export { Footer, type FooterLabels, type FooterProps };