Compare commits
6 Commits
v2026.2.8-
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 199bb7e525 | |||
| 5daaf71ae7 | |||
| 0aeec47996 | |||
| 3d67b8f2d9 | |||
| dd9a190fd9 | |||
| f5e5019ea8 |
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,6 +1,27 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
## v2026.2.9-0 (2026-04-23)
|
||||
|
||||
### New
|
||||
|
||||
* Add tracking code for the app #10. [Lang]
|
||||
|
||||
|
||||
## v2026.2.8-3 (2026-04-22)
|
||||
|
||||
### Fix
|
||||
|
||||
* The error message cannot be seen during avatar changing #10. [Lang]
|
||||
|
||||
|
||||
## v2026.2.8-2 (2026-04-21)
|
||||
|
||||
### Changes
|
||||
|
||||
* Increase the 2 MB avatar maximum file size to 10 MB #10. [Lang]
|
||||
|
||||
|
||||
## v2026.2.8-1 (2026-04-21)
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -28,6 +28,21 @@
|
||||
box-shadow: 0 8px 48px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
#profile-avatar-root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.profile-avatar__error {
|
||||
font-size: 11px;
|
||||
color: #e57373;
|
||||
text-align: center;
|
||||
max-width: 120px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.profile-avatar {
|
||||
position: relative;
|
||||
width: 80px;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
import React, { useMemo, useRef } from 'react';
|
||||
import React, { Fragment, useMemo, useRef } from 'react';
|
||||
import { string } from 'prop-types';
|
||||
import { useProfileDataProvider } from '@mine-hooks/useGameDataProvider';
|
||||
|
||||
@@ -16,6 +16,8 @@ export const AvatarUpload = ({ uploadUrl, initialThumbUrl, initials }) => {
|
||||
const [thumbUrl, setThumbUrl] = React.useState(initialThumbUrl || null);
|
||||
const { uploadAvatarMutation: { isPending, error, mutate } } = useProfileDataProvider();
|
||||
|
||||
const errorMessage = useMemo(() => error?.message ?? null, [error]);
|
||||
|
||||
const handleChange = e => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) return;
|
||||
@@ -40,32 +42,32 @@ export const AvatarUpload = ({ uploadUrl, initialThumbUrl, initials }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const errorMessage = useMemo(() => error?.message ?? null, [error]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`profile-avatar${isPending ? ' profile-avatar--loading' : ''}`}
|
||||
title="Click to change profile picture"
|
||||
onClick={() => inputRef.current?.click()}
|
||||
>
|
||||
{thumbUrl
|
||||
? <img src={thumbUrl} alt={initials} className="profile-avatar__img" />
|
||||
: <span className="profile-avatar__initials">{initials}</span>
|
||||
}
|
||||
<div className="profile-avatar__overlay">
|
||||
<i className="fa fa-camera" />
|
||||
<Fragment>
|
||||
<div
|
||||
className={`profile-avatar${isPending ? ' profile-avatar--loading' : ''}`}
|
||||
title="Click to change profile picture"
|
||||
onClick={() => inputRef.current?.click()}
|
||||
>
|
||||
{thumbUrl
|
||||
? <img src={thumbUrl} alt={initials} className="profile-avatar__img" />
|
||||
: <span className="profile-avatar__initials">{initials}</span>
|
||||
}
|
||||
<div className="profile-avatar__overlay">
|
||||
<i className="fa fa-camera" />
|
||||
</div>
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
accept="image/jpeg,image/png,image/gif,image/webp"
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
accept="image/jpeg,image/png,image/gif,image/webp"
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
{errorMessage && <div className="profile-avatar__error">{errorMessage}</div>}
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
AvatarUpload.propTypes = {
|
||||
uploadUrl: string.isRequired,
|
||||
|
||||
@@ -212,7 +212,7 @@ const useServerCommunication = (gameAssoc, gameInherited, opponentName, isEnvDev
|
||||
*/
|
||||
if (!endRef.current && (!isTrueRestoredRef.current || 0 !== opponentLastSeenRef.current)) {
|
||||
hideOverlay();
|
||||
sounds.current.starting.play();
|
||||
sounds.current.starting.play();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,25 @@
|
||||
|
||||
MineSeeker-specific testing setup and workflows. For general PHPUnit/Symfony testing, see [Symfony Testing Docs](https://symfony.com/doc/current/testing.html).
|
||||
|
||||
## Example of the current tests
|
||||
|
||||
```shell
|
||||
$ bin/phpunit (master->origin/master|✚1…2⚑1)
|
||||
PHPUnit 13.1.7 by Sebastian Bergmann and contributors.
|
||||
|
||||
Runtime: PHP 8.5.5
|
||||
Configuration: /var/www/splendid/Mine/phpunit.dist.xml
|
||||
|
||||
................................................................. 65 / 71 ( 91%)
|
||||
...... 71 / 71 (100%)
|
||||
|
||||
Time: 00:07.319, Memory: 86.50 MB
|
||||
|
||||
OK (71 tests, 227 assertions)
|
||||
|
||||
Faker seed used: 918823
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
@@ -143,9 +162,9 @@ class MyControllerTest extends WebTestCase
|
||||
{
|
||||
$user = UserFactory::createOne();
|
||||
$client = static::createClient();
|
||||
|
||||
|
||||
$client->request('GET', '/profile');
|
||||
|
||||
|
||||
self::assertResponseRedirects('/login');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,20 @@
|
||||
<link rel="icon" href="{{ asset('/images/favicon/favicon.ico') }}" type="image/x-icon">
|
||||
{% block metas %}{% endblock %}
|
||||
<title>MineSeeker{% block title %}{% endblock %}</title>
|
||||
<script
|
||||
defer src="https://umami.splendidbear.org/script.js"
|
||||
data-website-id="825e02a9-d675-4cbd-9e68-72b98de2e4e9"
|
||||
>
|
||||
</script>
|
||||
<script
|
||||
defer
|
||||
src="https://umami.splendidbear.org/recorder.js"
|
||||
data-website-id="825e02a9-d675-4cbd-9e68-72b98de2e4e9"
|
||||
data-sample-rate="0.15"
|
||||
data-mask-level="moderate"
|
||||
data-max-duration="300000"
|
||||
>
|
||||
</script>
|
||||
{% block stylesheets %}{% endblock %}
|
||||
</head>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user