@ujjan/built-badge 0.1.0

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/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # Ujjan Built Badge
2
+
3
+ Reusable "Built at Ujjan.com" badge kit for adding Ujjan attribution to project footers across web codebases.
4
+
5
+ ## Rule
6
+
7
+ Place the badge inside a project's footer component or footer partial only.
8
+ If a page does not render a footer, it should not render this badge.
9
+
10
+ ## Quick Start
11
+
12
+ Copy these files into your project:
13
+
14
+ - `dist/ujjan-badge.css`
15
+ - `dist/ujjan-badge.png`
16
+
17
+ Load the CSS from the page or layout that owns the footer:
18
+
19
+ ```html
20
+ <link rel="stylesheet" href="/assets/ujjan-badge.css">
21
+ ```
22
+
23
+ Then place the badge markup inside the footer:
24
+
25
+ ```html
26
+ <a
27
+ class="ujjan-built-badge"
28
+ href="https://ujjan.com/work/promptiles"
29
+ target="_blank"
30
+ rel="noopener noreferrer"
31
+ aria-label="Built at Ujjan.com"
32
+ >
33
+ <img src="/assets/ujjan-badge.png" alt="" width="25" height="30">
34
+ <span>Built at Ujjan.com</span>
35
+ </a>
36
+ ```
37
+
38
+ Use the project case-study slug after `/work/`, for example:
39
+
40
+ ```txt
41
+ https://ujjan.com/work/promptiles
42
+ ```
43
+
44
+ If the case study is not published yet, use the homepage fallback:
45
+
46
+ ```txt
47
+ https://ujjan.com
48
+ ```
49
+
50
+ ## Plain HTML
51
+
52
+ Use [snippets/html.html](snippets/html.html) inside your footer:
53
+
54
+ ```html
55
+ <footer>
56
+ <!-- Ujjan badge goes here -->
57
+ </footer>
58
+ ```
59
+
60
+ ## PHP
61
+
62
+ Copy [snippets/php.php](snippets/php.php) into a partial, then include it only from footer templates:
63
+
64
+ ```php
65
+ <?php $ujjanCaseStudySlug = 'promptiles'; ?>
66
+ <?php include __DIR__ . '/ujjan-built-badge.php'; ?>
67
+ ```
68
+
69
+ If `$ujjanCaseStudySlug` is not set or is empty, the badge links to `https://ujjan.com`.
70
+
71
+ ## React
72
+
73
+ Copy [snippets/react.tsx](snippets/react.tsx) into your component library, import the CSS once, and render it from your footer component:
74
+
75
+ ```tsx
76
+ import "./ujjan-badge.css";
77
+ import { UjjanBuiltBadge } from "./UjjanBuiltBadge";
78
+
79
+ export function Footer() {
80
+ return (
81
+ <footer>
82
+ <UjjanBuiltBadge
83
+ caseStudySlug="promptiles"
84
+ logoSrc="/assets/ujjan-badge.png"
85
+ />
86
+ </footer>
87
+ );
88
+ }
89
+ ```
90
+
91
+ Omit `caseStudySlug` until the case study is live:
92
+
93
+ ```tsx
94
+ <UjjanBuiltBadge logoSrc="/assets/ujjan-badge.png" />
95
+ ```
96
+
97
+ ## Files
98
+
99
+ - `dist/ujjan-badge.css` - standalone badge styles.
100
+ - `dist/ujjan-badge.png` - badge logo asset.
101
+ - `snippets/html.html` - plain HTML footer snippet.
102
+ - `snippets/php.php` - PHP footer partial snippet.
103
+ - `snippets/react.tsx` - React/Next-compatible component.
104
+
105
+ ## Theme Hooks
106
+
107
+ The CSS uses custom properties so each project can tune the badge without editing this package:
108
+
109
+ ```css
110
+ :root {
111
+ --ujjan-badge-bg: #1e2126;
112
+ --ujjan-badge-border: #505050;
113
+ --ujjan-badge-text: #fff;
114
+ --ujjan-badge-shine: #fff;
115
+ }
116
+ ```
117
+
118
+ ## Accessibility
119
+
120
+ The badge is a normal link with `target="_blank"` and `rel="noopener noreferrer"`.
121
+ The logo image is decorative and uses an empty `alt` value because the link already has an accessible label.
122
+
123
+ ## Versioning
124
+
125
+ Use Git tags for stable drops, starting with `v0.1.0`.
@@ -0,0 +1,99 @@
1
+ .ujjan-built-badge {
2
+ position: relative;
3
+ display: inline-flex;
4
+ align-items: center;
5
+ gap: 6px;
6
+ min-height: 40px;
7
+ width: fit-content;
8
+ padding: 0 18px;
9
+ overflow: hidden;
10
+ border: 1.5px solid var(--ujjan-badge-border, #505050);
11
+ border-radius: var(--ujjan-badge-radius, 5px);
12
+ background: var(--ujjan-badge-bg, #1e2126);
13
+ color: var(--ujjan-badge-text, #fff);
14
+ font: 500 14px/1.2 var(--ujjan-badge-font, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
15
+ text-decoration: none;
16
+ cursor: pointer;
17
+ isolation: isolate;
18
+ transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
19
+ }
20
+
21
+ .ujjan-built-badge::before,
22
+ .ujjan-built-badge::after {
23
+ content: "";
24
+ position: absolute;
25
+ top: -100%;
26
+ height: 300%;
27
+ transform: rotate(45deg);
28
+ background: var(--ujjan-badge-shine, #fff);
29
+ pointer-events: none;
30
+ z-index: -1;
31
+ }
32
+
33
+ .ujjan-built-badge::before {
34
+ left: -150px;
35
+ width: 30%;
36
+ opacity: 0.4;
37
+ animation: ujjan-badge-shine-wide 5s ease 5s infinite;
38
+ }
39
+
40
+ .ujjan-built-badge::after {
41
+ left: -50px;
42
+ width: 10%;
43
+ opacity: 0.5;
44
+ animation: ujjan-badge-shine-narrow 5s ease 5s infinite;
45
+ }
46
+
47
+ .ujjan-built-badge:hover {
48
+ color: var(--ujjan-badge-text, #fff);
49
+ border-color: var(--ujjan-badge-hover-border, var(--ujjan-badge-border, #505050));
50
+ box-shadow: 0 0 20px 5px var(--ujjan-badge-shadow, rgba(252, 217, 184, 0.1));
51
+ transform: scale(1.04);
52
+ }
53
+
54
+ .ujjan-built-badge:focus-visible {
55
+ outline: 2px solid var(--ujjan-badge-focus, #46fea5);
56
+ outline-offset: 3px;
57
+ }
58
+
59
+ .ujjan-built-badge__logo {
60
+ display: block;
61
+ width: 25px;
62
+ height: 30px;
63
+ flex: 0 0 auto;
64
+ }
65
+
66
+ .ujjan-built-badge__text {
67
+ white-space: nowrap;
68
+ }
69
+
70
+ @keyframes ujjan-badge-shine-wide {
71
+ 0% {
72
+ left: -150px;
73
+ }
74
+
75
+ 20%,
76
+ 100% {
77
+ left: 300px;
78
+ }
79
+ }
80
+
81
+ @keyframes ujjan-badge-shine-narrow {
82
+ 0% {
83
+ left: -50px;
84
+ }
85
+
86
+ 20%,
87
+ 100% {
88
+ left: 400px;
89
+ }
90
+ }
91
+
92
+ @media (prefers-reduced-motion: reduce) {
93
+ .ujjan-built-badge,
94
+ .ujjan-built-badge::before,
95
+ .ujjan-built-badge::after {
96
+ animation: none;
97
+ transition: none;
98
+ }
99
+ }
Binary file
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@ujjan/built-badge",
3
+ "version": "0.1.0",
4
+ "description": "Reusable footer badge kit for Built at Ujjan.com attribution.",
5
+ "homepage": "https://ujjan.com",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Ujjan-com/ujjan-built-badge.git"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "snippets",
13
+ "README.md"
14
+ ],
15
+ "exports": {
16
+ "./css": "./dist/ujjan-badge.css",
17
+ "./image": "./dist/ujjan-badge.png",
18
+ "./html": "./snippets/html.html",
19
+ "./php": "./snippets/php.php",
20
+ "./react": "./snippets/react.tsx"
21
+ },
22
+ "sideEffects": [
23
+ "./dist/ujjan-badge.css"
24
+ ],
25
+ "keywords": [
26
+ "ujjan",
27
+ "badge",
28
+ "footer",
29
+ "attribution"
30
+ ],
31
+ "license": "UNLICENSED"
32
+ }
@@ -0,0 +1,12 @@
1
+ <!-- Place this inside the project's footer only. -->
2
+ <!-- Use https://ujjan.com when the project case study is not published yet. -->
3
+ <a
4
+ class="ujjan-built-badge"
5
+ href="https://ujjan.com/work/promptiles"
6
+ target="_blank"
7
+ rel="noopener noreferrer"
8
+ aria-label="Built at Ujjan.com"
9
+ >
10
+ <img class="ujjan-built-badge__logo" src="/assets/ujjan-badge.png" alt="" width="25" height="30">
11
+ <span class="ujjan-built-badge__text">Built at Ujjan.com</span>
12
+ </a>
@@ -0,0 +1,28 @@
1
+ <?php
2
+ /**
3
+ * Place this partial inside the project's footer only.
4
+ *
5
+ * Optional:
6
+ * $ujjanCaseStudySlug = 'promptiles';
7
+ *
8
+ * If no slug is provided, the badge links to https://ujjan.com.
9
+ */
10
+ $ujjanBadgeBaseUrl = 'https://ujjan.com';
11
+ $ujjanBadgeSlug = isset($ujjanCaseStudySlug) && is_string($ujjanCaseStudySlug)
12
+ ? trim($ujjanCaseStudySlug, " \t\n\r\0\x0B/")
13
+ : '';
14
+ $ujjanBadgeSlug = preg_replace('#^work/#', '', $ujjanBadgeSlug);
15
+ $ujjanBadgeHref = $ujjanBadgeSlug !== ''
16
+ ? $ujjanBadgeBaseUrl . '/work/' . rawurlencode($ujjanBadgeSlug)
17
+ : $ujjanBadgeBaseUrl;
18
+ ?>
19
+ <a
20
+ class="ujjan-built-badge"
21
+ href="<?= htmlspecialchars($ujjanBadgeHref, ENT_QUOTES, 'UTF-8') ?>"
22
+ target="_blank"
23
+ rel="noopener noreferrer"
24
+ aria-label="Built at Ujjan.com"
25
+ >
26
+ <img class="ujjan-built-badge__logo" src="/assets/ujjan-badge.png" alt="" width="25" height="30">
27
+ <span class="ujjan-built-badge__text">Built at Ujjan.com</span>
28
+ </a>
@@ -0,0 +1,44 @@
1
+ type UjjanBuiltBadgeProps = {
2
+ caseStudySlug?: string;
3
+ className?: string;
4
+ logoSrc?: string;
5
+ };
6
+
7
+ const UJJAN_BASE_URL = "https://ujjan.com";
8
+
9
+ function getUjjanBadgeHref(caseStudySlug?: string) {
10
+ const slug = caseStudySlug
11
+ ?.trim()
12
+ .replace(/^\/+|\/+$/g, "")
13
+ .replace(/^work\//, "");
14
+
15
+ return slug ? `${UJJAN_BASE_URL}/work/${encodeURIComponent(slug)}` : UJJAN_BASE_URL;
16
+ }
17
+
18
+ export function UjjanBuiltBadge({
19
+ caseStudySlug,
20
+ className = "",
21
+ logoSrc = "/assets/ujjan-badge.png",
22
+ }: UjjanBuiltBadgeProps) {
23
+ const classes = ["ujjan-built-badge", className].filter(Boolean).join(" ");
24
+ const href = getUjjanBadgeHref(caseStudySlug);
25
+
26
+ return (
27
+ <a
28
+ className={classes}
29
+ href={href}
30
+ target="_blank"
31
+ rel="noopener noreferrer"
32
+ aria-label="Built at Ujjan.com"
33
+ >
34
+ <img
35
+ className="ujjan-built-badge__logo"
36
+ src={logoSrc}
37
+ alt=""
38
+ width={25}
39
+ height={30}
40
+ />
41
+ <span className="ujjan-built-badge__text">Built at Ujjan.com</span>
42
+ </a>
43
+ );
44
+ }