Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ GAMMA_ROOT_URL=http://localhost:8081
ACTIVE_GROUP_TYPES="committee,society"
NEXTAUTH_SECRET=secret
NEXTAUTH_URL=http://localhost:3000/api/auth
BASE_URL="http://localhost:3000"
MEDIA_PATH="./media"
ADMIN_GROUPS="styrit"
PAGE_EDITOR_GROUPS="snit,motespresidit"
CORPORATE_RELATIONS_GROUP="armit"
BASE_URL="http://localhost:3000"
# Ensures that the dev enviroment is the same as the production enviroment. Hydration issues can be missed in dev without otherwise.
TZ=UTC

SUBSCRIBE_SLACK_URL_SV="https://"
SUBSCRIBE_SLACK_URL_EN="https://"
2 changes: 2 additions & 0 deletions src/app/[locale]/(main-content)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ContactCard from '@/components/ContactCard/ContactCard';
import Lunch from '@/components/Lunch/Lunch';
import Sponsors from '@/components/Sponsors/Sponsors';
import Calendar from '@/components/Calendar/Calendar';
import SubscribeOptions from '@/components/SubscribeOptions/SubscribeOptions';

export const revalidate = 3600;

Expand Down Expand Up @@ -34,6 +35,7 @@ export default async function Home(props: {
const LeftBar = ({ locale }: { locale: string }) => {
return (
<div className={styles.sidePanel}>
<SubscribeOptions locale={locale} />
<Lunch locale={locale} />
<Sponsors locale={locale} />
</div>
Expand Down
2 changes: 0 additions & 2 deletions src/components/NewsList/NewsClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import NewsCard from './NewsCard/NewsCard';
import styles from './NewsList.module.scss';
import clientStyles from './NewsListClient.module.scss';
import NewsPost from './NewsPost/NewsPost';
import RssFeedButton from './RssFeedButton';
import ViewToggle from './ViewToggle';

interface NewsClientProps {
Expand All @@ -34,7 +33,6 @@ const NewsClient = ({ news, canPost, locale }: NewsClientProps) => {
<div className={styles.title}>
<div className={styles.heading}>
<h1>{l.news.title}</h1>
<RssFeedButton locale={locale} />
</div>
<div className={styles.actions}>
<ViewToggle
Expand Down
53 changes: 53 additions & 0 deletions src/components/SubscribeOptions/RssButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use client';

import { useRef, useState } from 'react';
import { FaRss } from 'react-icons/fa';
import styles from './SubscribeOptions.module.scss';

interface RssButtonProps {
rssUrl: string;
label: string;
tooltipText: string;
}

export default function RssButton({
rssUrl,
label,
tooltipText
}: RssButtonProps) {
const [tooltipVisible, setTooltipVisible] = useState(false);
const tooltipTimeout = useRef<NodeJS.Timeout | null>(null);

const handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
try {
await navigator.clipboard.writeText(window.location.origin + rssUrl);
setTooltipVisible(true);
if (tooltipTimeout.current) clearTimeout(tooltipTimeout.current);
tooltipTimeout.current = setTimeout(() => setTooltipVisible(false), 1500);
} catch {
window.open(rssUrl, '_blank', 'noopener,noreferrer');
}
};

return (
<button
type="button"
className={styles.iconButton}
aria-label={label}
title={label}
onClick={handleClick}
>
<FaRss />
<span
className={
styles.tooltip + (tooltipVisible ? ' ' + styles.tooltipVisible : '')
}
role="status"
aria-live="polite"
>
{tooltipText}
</span>
</button>
);
}
67 changes: 67 additions & 0 deletions src/components/SubscribeOptions/SubscribeOptions.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
.title {
font-size: 1.35rem;
font-weight: 700;
text-align: left;
margin-bottom: 1rem;
}

.optionsContainer {
display: flex;
flex-direction: row;
gap: 0.5rem;
}

.iconButton {
display: flex;
align-items: center;
justify-content: center;
width: 2.5rem;
height: 2.5rem;
background-color: transparent;
border: 1px solid var(--subscribe-border-color, var(--text-color, #333));
border-radius: 0.5rem;
color: inherit;
cursor: pointer;
transition: all 0.2s ease;
font-size: 1.3rem;
position: relative;
padding: 0;

&:hover:not(:disabled) {
background-color: var(--subscribe-hover-bg, rgba(0, 0, 0, 0.05));
border-color: var(--subscribe-hover-border-color, var(--text-color, #333));
}

&:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}

&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}

.tooltip {
position: absolute;
top: 50%;
left: calc(100% + 8px);
transform: translateY(-50%);
background: var(--background-color, #24292f);
color: var(--news-view-toggle-selected-color, #fff);
padding: 6px 12px;
border-radius: 6px;
font-size: 0.85rem;
white-space: nowrap;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
opacity: 0;
pointer-events: none;
user-select: none;
transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
z-index: 10;
}

.tooltipVisible {
opacity: 1;
}
55 changes: 55 additions & 0 deletions src/components/SubscribeOptions/SubscribeOptions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import i18nService from '@/services/i18nService';
import Link from 'next/link';
import { MdEmail } from 'react-icons/md';
import { SiSlack } from 'react-icons/si';
import ContentPane from '../ContentPane/ContentPane';
import RssButton from './RssButton';
import styles from './SubscribeOptions.module.scss';
import getSlackSubscribeLink from '@/hooks/getSlackSubscribeLink';

interface SubscribeOptionsProps {
locale: string;
}

export default async function SubscribeOptions({
locale
}: SubscribeOptionsProps) {
const l = i18nService.getLocale(locale);
const slackSubscribeUrl = await getSlackSubscribeLink();

return (
<ContentPane>
<h2 className={styles.title}>{l.news.subscribe}</h2>
<div className={styles.optionsContainer}>
{slackSubscribeUrl && (
<Link
href={slackSubscribeUrl}
target="_blank"
rel="noopener noreferrer"
className={styles.iconButton}
title={l.news.subscribeViaSlack}
aria-label={l.news.subscribeViaSlack}
>
<SiSlack />
</Link>
)}

<button
type="button"
className={styles.iconButton}
title={l.general.comingSoon}
aria-label={l.general.comingSoon}
disabled
>
<MdEmail />
</button>

<RssButton
rssUrl={`/api/news?format=rss&locale=${locale}`}
label={l.news.subscribeViaRss}
tooltipText={l.editor.linkCopied}
/>
</div>
</ContentPane>
);
}
5 changes: 4 additions & 1 deletion src/dictionaries/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"close": "Close",
"save": "Save",
"manage": "Manage",
"add": "Add"
"add": "Add",
"comingSoon": "Comming soon"
},
"site": {
"siteTitle": "IT at Chalmers",
Expand Down Expand Up @@ -41,6 +42,8 @@
"by": "by",
"unknown": "unknown author",
"subscribe": "Subscribe to news feed",
"subscribeViaRss": "Follow us via RSS",
"subscribeViaSlack": "Join our Slack",
"confirmDelete": "Are you sure you want to delete this post? This action cannot be undone.",
"deleting": "Deleting...",
"deleted": "Deleted!",
Expand Down
5 changes: 4 additions & 1 deletion src/dictionaries/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"close": "Stäng",
"save": "Spara",
"manage": "Hantera",
"add": "Lägg till"
"add": "Lägg till",
"comingSoon": "Kommer snart"
},
"site": {
"siteTitle": "IT på Chalmers",
Expand Down Expand Up @@ -41,6 +42,8 @@
"by": "av",
"unknown": "okänd användare",
"subscribe": "Prenumerera på nyheter",
"subscribeViaRss": "Följ oss via RSS",
"subscribeViaSlack": "Gå med i vår Slack",
"confirmDelete": "Vill du radera nyheten? Detta går inte att ångra!",
"deleting": "Raderar...",
"deleted": "Raderad!",
Expand Down
10 changes: 10 additions & 0 deletions src/hooks/getSlackSubscribeLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use server';

import i18nService from '@/services/i18nService';

const { SUBSCRIBE_SLACK_URL_EN: EN, SUBSCRIBE_SLACK_URL_SV: SV } = process.env;

export default async function getSlackSubscribeLink(): Promise<string | null> {
const isEn = i18nService.getLocale().en;
return (isEn ? EN : SV) || null;
}
Loading