more spotify, tts
This commit is contained in:
@@ -5,7 +5,7 @@ export const ServerRoute = createServerFileRoute("/api/files/$collection/$record
|
|||||||
GET: async ({ params, request }) => {
|
GET: async ({ params, request }) => {
|
||||||
try {
|
try {
|
||||||
const { collection, recordId, file } = params;
|
const { collection, recordId, file } = params;
|
||||||
const pocketbaseUrl = process.env.VITE_POCKETBASE_URL || 'http://127.0.0.1:8090';
|
const pocketbaseUrl = process.env.POCKETBASE_URL || 'http://127.0.0.1:8090';
|
||||||
const fileUrl = `${pocketbaseUrl}/api/files/${collection}/${recordId}/${file}`;
|
const fileUrl = `${pocketbaseUrl}/api/files/${collection}/${recordId}/${file}`;
|
||||||
|
|
||||||
logger.info('File proxy', {
|
logger.info('File proxy', {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const AdminPage = () => {
|
|||||||
label="Open Pocketbase"
|
label="Open Pocketbase"
|
||||||
Icon={DatabaseIcon}
|
Icon={DatabaseIcon}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
window.location.replace(import.meta.env.VITE_POCKETBASE_URL! + "/_/")
|
window.location.replace(process.env.POCKETBASE_URL! + "/_/")
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ListLink
|
<ListLink
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const Bracket: React.FC<BracketProps> = ({
|
|||||||
showControls,
|
showControls,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" gap={24} justify="left" p="xl">
|
<Flex direction="row" gap={24} justify="left">
|
||||||
{rounds.map((round, roundIndex) => (
|
{rounds.map((round, roundIndex) => (
|
||||||
<Flex
|
<Flex
|
||||||
key={roundIndex}
|
key={roundIndex}
|
||||||
@@ -23,6 +23,7 @@ export const Bracket: React.FC<BracketProps> = ({
|
|||||||
pos="relative"
|
pos="relative"
|
||||||
gap={24}
|
gap={24}
|
||||||
justify="space-around"
|
justify="space-around"
|
||||||
|
p={24}
|
||||||
>
|
>
|
||||||
{round
|
{round
|
||||||
.filter((match) => !match.bye)
|
.filter((match) => !match.bye)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ActionIcon, Card, Flex, Text, Stack, Indicator } from "@mantine/core";
|
import { ActionIcon, Card, Flex, Text, Stack, Indicator } from "@mantine/core";
|
||||||
import { PlayIcon, PencilIcon } from "@phosphor-icons/react";
|
import { PlayIcon, PencilIcon, SpeakerHighIcon } from "@phosphor-icons/react";
|
||||||
import React, { useCallback, useMemo } from "react";
|
import React, { useCallback, useMemo } from "react";
|
||||||
import { MatchSlot } from "./match-slot";
|
import { MatchSlot } from "./match-slot";
|
||||||
import { Match } from "@/features/matches/types";
|
import { Match } from "@/features/matches/types";
|
||||||
@@ -91,6 +91,31 @@ export const MatchCard: React.FC<MatchCardProps> = ({
|
|||||||
[match.id, editSheet]
|
[match.id, editSheet]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleSpeakerClick = useCallback(() => {
|
||||||
|
if ('speechSynthesis' in window && match.home?.name && match.away?.name) {
|
||||||
|
const utterance = new SpeechSynthesisUtterance(
|
||||||
|
`${match.home.name} vs. ${match.away.name}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const voices = window.speechSynthesis.getVoices();
|
||||||
|
|
||||||
|
const preferredVoice = voices.find(voice =>
|
||||||
|
voice.lang.startsWith('en') &&
|
||||||
|
voice.name.includes('Daniel')
|
||||||
|
) || voices.find(voice => voice.lang.startsWith('en') && voice.default);
|
||||||
|
|
||||||
|
if (preferredVoice) {
|
||||||
|
utterance.voice = preferredVoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
utterance.rate = 0.9;
|
||||||
|
utterance.volume = 0.8;
|
||||||
|
utterance.pitch = 1.0;
|
||||||
|
|
||||||
|
window.speechSynthesis.speak(utterance);
|
||||||
|
}
|
||||||
|
}, [match.home?.name, match.away?.name]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" align="center" justify="end" gap={8}>
|
<Flex direction="row" align="center" justify="end" gap={8}>
|
||||||
<Text c="dimmed" fw="bolder">
|
<Text c="dimmed" fw="bolder">
|
||||||
@@ -131,6 +156,18 @@ export const MatchCard: React.FC<MatchCardProps> = ({
|
|||||||
* If necessary
|
* If necessary
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<ActionIcon
|
||||||
|
pos="absolute"
|
||||||
|
bottom={-2}
|
||||||
|
left={-26}
|
||||||
|
size="sm"
|
||||||
|
variant="subtle"
|
||||||
|
color="gray"
|
||||||
|
onClick={handleSpeakerClick}
|
||||||
|
>
|
||||||
|
<SpeakerHighIcon size={12} />
|
||||||
|
</ActionIcon>
|
||||||
</Card>
|
</Card>
|
||||||
</Indicator>
|
</Indicator>
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const SpotifyControlsBar = () => {
|
|||||||
<Group justify="center" gap="sm">
|
<Group justify="center" gap="sm">
|
||||||
<SpotifyLogoIcon size={24} color="var(--mantine-color-green-6)" />
|
<SpotifyLogoIcon size={24} color="var(--mantine-color-green-6)" />
|
||||||
<Text size="sm" c="dimmed">
|
<Text size="sm" c="dimmed">
|
||||||
Connect Spotify to control music during tournaments
|
Connect Spotify
|
||||||
</Text>
|
</Text>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
variant="light"
|
variant="light"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class PocketBaseAdminClient {
|
|||||||
public authPromise: Promise<void>;
|
public authPromise: Promise<void>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.pb = new PocketBase(import.meta.env.VITE_POCKETBASE_URL);
|
this.pb = new PocketBase(process.env.POCKETBASE_URL);
|
||||||
|
|
||||||
this.pb.beforeSend = (url, options) => {
|
this.pb.beforeSend = (url, options) => {
|
||||||
options.cache = "no-store";
|
options.cache = "no-store";
|
||||||
@@ -38,8 +38,8 @@ class PocketBaseAdminClient {
|
|||||||
await this.pb
|
await this.pb
|
||||||
.collection("_superusers")
|
.collection("_superusers")
|
||||||
.authWithPassword(
|
.authWithPassword(
|
||||||
import.meta.env.VITE_POCKETBASE_ADMIN_EMAIL!,
|
process.env.POCKETBASE_ADMIN_EMAIL!,
|
||||||
import.meta.env.VITE_POCKETBASE_ADMIN_PASSWORD!
|
process.env.POCKETBASE_ADMIN_PASSWORD!
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const backendConfig = (): TypeInput => {
|
|||||||
framework: "custom",
|
framework: "custom",
|
||||||
supertokens: {
|
supertokens: {
|
||||||
connectionURI:
|
connectionURI:
|
||||||
import.meta.env.VITE_SUPERTOKENS_URI || "https://try.supertokens.io",
|
process.env.SUPERTOKENS_URI || "https://try.supertokens.io",
|
||||||
},
|
},
|
||||||
appInfo,
|
appInfo,
|
||||||
recipeList: [
|
recipeList: [
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import twilio from "twilio";
|
import twilio from "twilio";
|
||||||
|
|
||||||
const accountSid = import.meta.env.VITE_TWILIO_ACCOUNT_SID;
|
const accountSid = process.env.TWILIO_ACCOUNT_SID!;
|
||||||
const authToken = import.meta.env.VITE_TWILIO_AUTH_TOKEN;
|
const authToken = process.env.TWILIO_AUTH_TOKEN!;
|
||||||
const serviceSid = import.meta.env.VITE_TWILIO_SERVICE_SID;
|
const serviceSid = process.env.TWILIO_SERVICE_SID!;
|
||||||
|
|
||||||
const client = twilio(accountSid, authToken);
|
const client = twilio(accountSid, authToken);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user