Coverage for ivatar / tools / templates / check.html: 97%

373 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-12-03 00:09 +0000

1{% extends 'base.html' %} 

2{% load i18n %} 

3{% load static %} 

4  

5{% block header %} 

6<style> 

7/* Base tile styles - highest specificity */ 

8.custom-select-grid .select-option, 

9.form-group .custom-select-grid .select-option, 

10div.custom-select-grid div.select-option { 

11 transition: all 0.3s ease !important; 

12 cursor: pointer !important; 

13 border: 2px solid #dee2e6 !important; 

14 background-color: #fff !important; 

15 color: #333 !important; 

16 padding: 1rem !important; 

17 border-radius: 12px !important; 

18 display: flex !important; 

19 flex-direction: column !important; 

20 align-items: center !important; 

21 gap: 0.75rem !important; 

22 min-height: 100px !important; 

23 justify-content: center !important; 

24} 

25  

26/* Hover state for non-selected tiles */ 

27.custom-select-grid .select-option:hover:not(.selected), 

28.form-group .custom-select-grid .select-option:hover:not(.selected), 

29div.custom-select-grid div.select-option:hover:not(.selected) { 

30 border-color: #335ecf !important; 

31 background-color: #e8f0ff !important; 

32 color: #335ecf !important; 

33 transform: translateY(-2px) !important; 

34} 

35  

36.custom-select-grid .select-option:hover:not(.selected) .select-option-text, 

37.form-group .custom-select-grid .select-option:hover:not(.selected) .select-option-text, 

38div.custom-select-grid div.select-option:hover:not(.selected) .select-option-text { 

39 color: #335ecf !important; 

40 font-weight: 500 !important; 

41} 

42  

43/* Selected state - always takes priority */ 

44.custom-select-grid .select-option.selected, 

45.form-group .custom-select-grid .select-option.selected, 

46div.custom-select-grid div.select-option.selected { 

47 background-color: #335ecf !important; 

48 border-color: #335ecf !important; 

49 color: #fff !important; 

50 box-shadow: 0 4px 16px rgba(51, 94, 207, 0.4) !important; 

51 transform: translateY(-1px) !important; 

52} 

53  

54.custom-select-grid .select-option.selected .select-option-text, 

55.form-group .custom-select-grid .select-option.selected .select-option-text, 

56div.custom-select-grid div.select-option.selected .select-option-text { 

57 color: #fff !important; 

58 font-weight: 600 !important; 

59} 

60  

61.custom-select-grid .select-option.selected .select-option-preview, 

62.form-group .custom-select-grid .select-option.selected .select-option-preview, 

63div.custom-select-grid div.select-option.selected .select-option-preview { 

64 border-color: rgba(255, 255, 255, 0.5) !important; 

65} 

66  

67/* Selected state hover - slightly different shade */ 

68.custom-select-grid .select-option.selected:hover, 

69.form-group .custom-select-grid .select-option.selected:hover, 

70div.custom-select-grid div.select-option.selected:hover { 

71 background-color: #2a4bb8 !important; 

72 border-color: #2a4bb8 !important; 

73 color: #fff !important; 

74 transform: translateY(-2px) !important; 

75 box-shadow: 0 6px 20px rgba(51, 94, 207, 0.5) !important; 

76} 

77  

78.custom-select-grid .select-option.selected:hover .select-option-text, 

79.form-group .custom-select-grid .select-option.selected:hover .select-option-text, 

80div.custom-select-grid div.select-option.selected:hover .select-option-text { 

81 color: #fff !important; 

82 font-weight: 600 !important; 

83} 

84  

85/* Force all child elements in selected state */ 

86.custom-select-grid .select-option.selected *, 

87.form-group .custom-select-grid .select-option.selected *, 

88div.custom-select-grid div.select-option.selected * { 

89 color: #fff !important; 

90} 

91  

92/* Ensure selected state persists even with inline styles */ 

93.select-option[data-selected="true"] { 

94 background-color: #335ecf !important; 

95 border-color: #335ecf !important; 

96 color: #fff !important; 

97 box-shadow: 0 4px 16px rgba(51, 94, 207, 0.4) !important; 

98} 

99  

100.select-option[data-selected="true"] .select-option-text { 

101 color: #fff !important; 

102 font-weight: 600 !important; 

103} 

104  

105/* Override any potential theme conflicts */ 

106body .select-option.selected, 

107html .select-option.selected { 

108 background-color: #335ecf !important; 

109 border-color: #335ecf !important; 

110 color: #fff !important; 

111} 

112</style> 

113{% endblock header %} 

114  

115{% block title %}{% trans 'Check e-mail or openid' %}{% endblock title %} 

116  

117{% block content %} 

118  

119<h1>{% trans 'Check e-mail or openid' %}</h1> 

120  

121<div class="check-layout"> 

122 <div class="check-form-section"> 

123 {% if form.errors %} 

124 {% for error in form.non_field_errors %} 

125 <div class="alert alert-danger" role="alert">{{ error|escape }}</div> 

126 {% endfor %} 

127 {% endif %} 

128  

129 <div class="form-container"> 

130 <form method="post" name="check"> 

131 {% csrf_token %} 

132 <div class="form-group"> 

133 <label for="id_mail" class="form-label">{% trans 'E-Mail' %}</label> 

134 {% if form.mail.value %} 

135 <input type="email" name="mail" maxlength="254" minlength="6" class="form-control" 

136 placeholder="{% trans 'E-Mail' %}" value="{{ form.mail.value }}" id="id_mail"> 

137 {% else %} 

138 <input type="email" name="mail" maxlength="254" minlength="6" class="form-control" 

139 placeholder="{% trans 'E-Mail' %}" id="id_mail"> 

140 {% endif %} 

141 </div> 

142 <div class="form-group"> 

143 <label for="id_openid" class="form-label">{% trans 'OpenID' %}</label> 

144 {% if form.openid.value %} 

145 <input type="text" name="openid" maxlength="255" minlength="11" class="form-control" 

146 placeholder="{% trans 'OpenID' %}" value="{{ form.openid.value }}" id="id_openid"> 

147 {% else %} 

148 <input type="text" name="openid" maxlength="255" minlength="11" class="form-control" 

149 placeholder="{% trans 'OpenID' %}" id="id_openid"> 

150 {% endif %} 

151 </div> 

152 <div class="form-group"> 

153 <label for="id_size" class="form-label">{% trans 'Size' %}</label> 

154 {% if form.size.value %} 

155 <input type="number" name="size" min="5" max="512" class="form-control" placeholder="{% trans 'Size' %}" 

156 value="{{ form.size.value }}" required id="id_size"> 

157 {% else %} 

158 <input type="number" name="size" min="5" max="512" class="form-control" placeholder="{% trans 'Size' %}" 

159 value="100" required id="id_size"> 

160 {% endif %} 

161 </div> 

162 <div class="form-group"> 

163 <label for="id_default_url" class="form-label">{% trans 'Default URL or special keyword' %}</label> 

164 {% if form.default_url.value %} 

165 <input type="text" name="default_url" class="form-control" placeholder="{% trans 'Default' %}" 

166 value="{{ form.default_url.value }}" id="id_default_url"> 

167 {% else %} 

168 <input type="text" name="default_url" class="form-control" placeholder="{% trans 'Default' %}" 

169 id="id_default_url"> 

170 {% endif %} 

171 </div> 

172 <div class="form-group"> 

173 <label class="form-label">{% trans 'Default (special keyword)' %}</label> 

174 <input type="hidden" name="default_opt" id="id_default_opt" 

175 value="{% if form.default_opt.value %}{{ form.default_opt.value }}{% endif %}"> 

176 <div class="custom-select-grid"> 

177 <div class="select-option {% if form.default_opt.value == 'retro' %}selected{% endif %}" data-value="retro"> 

178 <img src="/avatar/05b393e2a6942f3796524d634dcd8c0d?s=32&d=retro&forcedefault=y" alt="Retro preview" 

179 class="select-option-preview"> 

180 <span class="select-option-text">Retro (d=retro)</span> 

181 </div> 

182 <div class="select-option {% if form.default_opt.value == 'robohash' %}selected{% endif %}" 

183 data-value="robohash"> 

184 <img src="/avatar/05b393e2a6942f3796524d634dcd8c0d?s=32&d=robohash&forcedefault=y" alt="Roboter preview" 

185 class="select-option-preview"> 

186 <span class="select-option-text">Roboter (d=robohash)</span> 

187 </div> 

188 <div class="select-option {% if form.default_opt.value == 'wavatar' %}selected{% endif %}" 

189 data-value="wavatar"> 

190 <img src="/avatar/05b393e2a6942f3796524d634dcd8c0d?s=32&d=wavatar&forcedefault=y" alt="Wavatar preview" 

191 class="select-option-preview"> 

192 <span class="select-option-text">Wavatar (d=wavatar)</span> 

193 </div> 

194 <div class="select-option {% if form.default_opt.value == 'monsterid' %}selected{% endif %}" 

195 data-value="monsterid"> 

196 <img src="/avatar/05b393e2a6942f3796524d634dcd8c0d?s=32&d=monsterid&forcedefault=y" alt="Monster preview" 

197 class="select-option-preview"> 

198 <span class="select-option-text">Monster (d=monsterid)</span> 

199 </div> 

200 <div class="select-option {% if form.default_opt.value == 'identicon' %}selected{% endif %}" 

201 data-value="identicon"> 

202 <img src="/avatar/05b393e2a6942f3796524d634dcd8c0d?s=32&d=identicon&forcedefault=y" 

203 alt="Identicon preview" class="select-option-preview"> 

204 <span class="select-option-text">Identicon (d=identicon)</span> 

205 </div> 

206 <div class="select-option {% if form.default_opt.value == 'mm' %}selected{% endif %}" data-value="mm"> 

207 <img src="/avatar/05b393e2a6942f3796524d634dcd8c0d?s=32&d=mm&forcedefault=y" alt="Mystery man preview" 

208 class="select-option-preview"> 

209 <span class="select-option-text">Mystery man (d=mm)</span> 

210 </div> 

211 <div class="select-option {% if form.default_opt.value == 'mmng' %}selected{% endif %}" data-value="mmng"> 

212 <img src="/avatar/05b393e2a6942f3796524d634dcd8c0d?s=32&d=mmng&forcedefault=y" 

213 alt="Mystery man NG preview" class="select-option-preview"> 

214 <span class="select-option-text">Mystery man NG (d=mmng)</span> 

215 </div> 

216 <div class="select-option select-option-none {% if form.default_opt.value == 'none' %}selected{% endif %}" 

217 data-value="none"> 

218 <span class="select-option-text">None</span> 

219 </div> 

220 </div> 

221 </div> 

222  

223 <div class="button-group"> 

224 <button type="submit" class="btn btn-primary">{% trans 'Check' %}</button> 

225 </div> 

226 </form> 

227 </div> 

228 </div> 

229  

230 {% if mailurl or openidurl %} 

231 <div class="check-results-section" id="avatar-results"> 

232 <h2>{% trans 'Avatar Preview Results' %}</h2> 

233 <p class="results-description"> 

234 {% trans 'This is what the avatars will look like depending on the hash and protocol you use:' %} 

235 </p> 

236  

237 <div class="hash-info"> 

238 {% if mail_hash %} 

239 <div class="hash-display"> 

240 <strong>MD5 hash (mail):</strong> <code>{{ mail_hash }}</code> 

241 </div> 

242 <div class="hash-display"> 

243 <strong>SHA256 hash (mail):</strong> <code>{{ mail_hash256 }}</code> 

244 </div> 

245 {% endif %} 

246 {% if openid_hash %} 

247 <div class="hash-display"> 

248 <strong>SHA256 hash (OpenID):</strong> <code>{{ openid_hash }}</code> 

249 </div> 

250 {% endif %} 

251 </div> 

252  

253 <div class="avatar-results"> 

254 {% if mailurl %} 

255 <div class="avatar-panel"> 

256 <div class="panel-heading"> 

257 <h3 class="panel-title"> 

258 <span class="hash-type">MD5</span> 

259 <span class="connection-icons"> 

260 <i class="fa-solid fa-lock" title="Secure connection (https)"></i> 

261 <i class="fa-solid fa-at" title="mail: {{ form.mail.value }}"></i> 

262 </span> 

263 </h3> 

264 </div> 

265 <div class="panel-body"> 

266 <a href="{{ mailurl_secure }}" target="_blank"> 

267 <img src="{{ mailurl_secure }}" class="avatar-image" alt="MD5 Avatar"> 

268 </a> 

269 </div> 

270 </div> 

271  

272 <div class="avatar-panel"> 

273 <div class="panel-heading"> 

274 <h3 class="panel-title"> 

275 <span class="hash-type">SHA256</span> 

276 <span class="connection-icons"> 

277 <i class="fa-solid fa-lock" title="Secure connection (https)"></i> 

278 <i class="fa-solid fa-at" title="mail: {{ form.mail.value }}"></i> 

279 </span> 

280 </h3> 

281 </div> 

282 <div class="panel-body"> 

283 <a href="{{ mailurl_secure_256 }}" target="_blank"> 

284 <img src="{{ mailurl_secure_256 }}" class="avatar-image" alt="SHA256 Avatar"> 

285 </a> 

286 </div> 

287 </div> 

288 {% endif %} 

289  

290 {% if openidurl %} 

291 <div class="avatar-panel"> 

292 <div class="panel-heading"> 

293 <h3 class="panel-title"> 

294 <span class="hash-type">SHA256</span> 

295 <span class="connection-icons"> 

296 <i class="fa-solid fa-lock" title="Secure connection (https)"></i> 

297 <i class="fa-solid fa-openid" title="openid: {{ form.openid.value }}"></i> 

298 </span> 

299 </h3> 

300 </div> 

301 <div class="panel-body"> 

302 <a href="{{ openidurl_secure }}" target="_blank"> 

303 <img src="{{ openidurl_secure }}" class="avatar-image" alt="OpenID Avatar"> 

304 </a> 

305 </div> 

306 </div> 

307 {% endif %} 

308 </div> 

309 </div> 

310 {% else %} 

311 <div class="check-results-placeholder"> 

312 <div class="placeholder-content"> 

313 <h3>{% trans 'Avatar Preview' %}</h3> 

314 <p>{% trans 'Submit the form to see your avatar previews here.' %}</p> 

315 <div class="placeholder-icon"> 

316 <i class="fa-solid fa-user-circle" style="font-size: 4rem; color: #ccc;"></i> 

317 </div> 

318 </div> 

319 </div> 

320 {% endif %} 

321</div> 

322  

323{% if mailurl or openidurl %} 

324<script> 

325 // Auto-scroll to results on mobile after form submission 

326 document.addEventListener('DOMContentLoaded', function () { 

327 // Check if we're on mobile and have results 

328 if (window.innerWidth <= 768 && document.getElementById('avatar-results')) { 

329 // Small delay to ensure page is fully rendered 

330 setTimeout(function () { 

331 document.getElementById('avatar-results').scrollIntoView({ 

332 behavior: 'smooth', 

333 block: 'start' 

334 }); 

335 }, 100); 

336 } 

337 }); 

338</script> 

339{% endif %} 

340  

341<script> 

342 // Custom select box functionality 

343 document.addEventListener('DOMContentLoaded', function () { 

344 const selectOptions = document.querySelectorAll('.select-option'); 

345 const hiddenInput = document.getElementById('id_default_opt'); 

346  

347 selectOptions.forEach(function (option) { 

348 option.addEventListener('click', function () { 

349 // Remove selected class from all options 

350 selectOptions.forEach(function (opt) { 

351 opt.classList.remove('selected'); 

352 opt.removeAttribute('data-selected'); 

353  

354 // Clear any inline styles that might interfere with CSS 

355 opt.style.backgroundColor = ''; 

356 opt.style.borderColor = ''; 

357 opt.style.color = ''; 

358 opt.style.fontWeight = ''; 

359 opt.style.transform = ''; 

360 opt.style.boxShadow = ''; 

361  

362 const textElement = opt.querySelector('.select-option-text'); 

363 if (textElement) { 

364 textElement.style.color = ''; 

365 textElement.style.fontWeight = ''; 

366 } 

367 }); 

368  

369 // Add selected class to clicked option 

370 this.classList.add('selected'); 

371 this.setAttribute('data-selected', 'true'); 

372  

373 // Update hidden input value 

374 hiddenInput.value = this.getAttribute('data-value'); 

375  

376 // Force a reflow to ensure CSS is applied immediately 

377 this.offsetHeight; 

378 }); 

379 }); 

380 }); 

381</script> 

382  

383{% endblock content %}