mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
feat(docs): In the Wild page with YAML data and AntD components (#36386)
Co-authored-by: Catherine Qu <catherine.qu@mail.utoronto.ca> Co-authored-by: Evan Rusackas <evan@rusackas.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
165
docs/src/pages/inTheWild.tsx
Normal file
165
docs/src/pages/inTheWild.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import Layout from '@theme/Layout';
|
||||
import { Avatar, Card, Col, Collapse, Row, Typography } from 'antd';
|
||||
import BlurredSection from '../components/BlurredSection';
|
||||
import SectionHeader from '../components/SectionHeader';
|
||||
import DataSet from '../../../RESOURCES/INTHEWILD.yaml';
|
||||
|
||||
const { Text, Link } = Typography;
|
||||
|
||||
interface Organization {
|
||||
name: string;
|
||||
url: string;
|
||||
logo?: string;
|
||||
contributors?: string[];
|
||||
}
|
||||
|
||||
interface DataSetType {
|
||||
categories: Record<string, Organization[]>;
|
||||
}
|
||||
|
||||
const typedDataSet = DataSet as DataSetType;
|
||||
|
||||
const ContributorAvatars = ({ contributors }: { contributors?: string[] }) => {
|
||||
if (!contributors?.length) return null;
|
||||
return (
|
||||
<Avatar.Group size="small" max={{ count: 3 }}>
|
||||
{contributors.map((handle) => {
|
||||
const username = handle.replace('@', '');
|
||||
return (
|
||||
<a
|
||||
key={username}
|
||||
href={`https://github.com/${username}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Avatar
|
||||
src={`https://github.com/${username}.png?size=40`}
|
||||
alt={username}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
{username.charAt(0).toUpperCase()}
|
||||
</Avatar>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</Avatar.Group>
|
||||
);
|
||||
};
|
||||
|
||||
export default function InTheWild() {
|
||||
return (
|
||||
<Layout title="In the Wild" description="Organizations using Apache Superset">
|
||||
<main>
|
||||
<BlurredSection>
|
||||
<SectionHeader
|
||||
level="h2"
|
||||
title="In the Wild"
|
||||
subtitle="See who's using Superset and join our growing community"
|
||||
/>
|
||||
<div style={{ textAlign: 'center', marginTop: 10 }}>
|
||||
<Link
|
||||
href="https://github.com/apache/superset/edit/master/RESOURCES/INTHEWILD.yaml"
|
||||
target="_blank"
|
||||
>
|
||||
Add your name/org!
|
||||
</Link>
|
||||
</div>
|
||||
</BlurredSection>
|
||||
|
||||
<div style={{ maxWidth: 850, margin: '70px auto 60px', padding: '0 20px' }}>
|
||||
<Collapse
|
||||
bordered={false}
|
||||
defaultActiveKey={Object.keys(typedDataSet.categories)}
|
||||
style={{
|
||||
background: 'var(--ifm-background-color)',
|
||||
border: '1px solid var(--ifm-border-color)',
|
||||
borderRadius: 10,
|
||||
}}
|
||||
items={Object.entries(typedDataSet.categories).map(([category, items]) => {
|
||||
const logoItems = items.filter(({ logo }) => logo?.trim());
|
||||
const textItems = items.filter(({ logo }) => !logo?.trim());
|
||||
|
||||
return {
|
||||
key: category,
|
||||
label: (
|
||||
<Text strong style={{ fontSize: 16, lineHeight: '22px' }}>
|
||||
{category} ({items.length})
|
||||
</Text>
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
{logoItems.length > 0 && (
|
||||
<Row gutter={[16, 16]} style={{ marginBottom: textItems.length > 0 ? 24 : 0 }}>
|
||||
{logoItems.map(({ name, url, logo, contributors }) => (
|
||||
<Col xs={24} sm={12} md={8} key={name}>
|
||||
<a href={url} target="_blank" rel="noreferrer">
|
||||
<Card
|
||||
hoverable
|
||||
style={{ height: 150, position: 'relative' }}
|
||||
styles={{ body: { padding: 16, height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' } }}
|
||||
>
|
||||
<img
|
||||
src={`/img/logos/${logo}`}
|
||||
alt={name}
|
||||
style={{ maxHeight: 80, maxWidth: '100%', objectFit: 'contain' }}
|
||||
/>
|
||||
{contributors?.length && (
|
||||
<div style={{ position: 'absolute', bottom: 8, right: 8 }}>
|
||||
<ContributorAvatars contributors={contributors} />
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</a>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
)}
|
||||
|
||||
{textItems.length > 0 && (
|
||||
<Row gutter={[8, 8]}>
|
||||
{textItems.map(({ name, url, contributors }) => (
|
||||
<Col xs={24} sm={12} md={8} key={name}>
|
||||
<a href={url} target="_blank" rel="noreferrer">
|
||||
<Card
|
||||
size="small"
|
||||
hoverable
|
||||
styles={{ body: { padding: '8px 12px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 } }}
|
||||
>
|
||||
<Text ellipsis style={{ flex: 1 }}>{name}</Text>
|
||||
<ContributorAvatars contributors={contributors} />
|
||||
</Card>
|
||||
</a>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
};
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
@@ -19,15 +19,43 @@
|
||||
import { useRef, useState, useEffect, JSX } from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
import Link from '@docusaurus/Link';
|
||||
import { Carousel } from 'antd';
|
||||
import { Card, Carousel, Flex } from 'antd';
|
||||
import styled from '@emotion/styled';
|
||||
import GitHubButton from 'react-github-btn';
|
||||
import { mq } from '../utils';
|
||||
import { Databases } from '../resources/data';
|
||||
import SectionHeader from '../components/SectionHeader';
|
||||
import BlurredSection from '../components/BlurredSection';
|
||||
import DataSet from '../../../RESOURCES/INTHEWILD.yaml';
|
||||
import '../styles/main.less';
|
||||
|
||||
interface Organization {
|
||||
name: string;
|
||||
url: string;
|
||||
logo?: string;
|
||||
}
|
||||
|
||||
interface DataSetType {
|
||||
categories: Record<string, Organization[]>;
|
||||
}
|
||||
|
||||
const typedDataSet = DataSet as DataSetType;
|
||||
|
||||
// Extract all organizations with logos for the carousel
|
||||
const companiesWithLogos = Object.values(typedDataSet.categories)
|
||||
.flat()
|
||||
.filter((org) => org.logo?.trim());
|
||||
|
||||
// Fisher-Yates shuffle for fair randomization
|
||||
function shuffleArray<T>(array: T[]): T[] {
|
||||
const shuffled = [...array];
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
||||
}
|
||||
return shuffled;
|
||||
}
|
||||
|
||||
const features = [
|
||||
{
|
||||
image: 'powerful-yet-easy.jpg',
|
||||
@@ -452,6 +480,7 @@ export default function Home(): JSX.Element {
|
||||
const slider = useRef(null);
|
||||
|
||||
const [slideIndex, setSlideIndex] = useState(0);
|
||||
const [shuffledCompanies, setShuffledCompanies] = useState(companiesWithLogos);
|
||||
|
||||
const onChange = (current, next) => {
|
||||
setSlideIndex(next);
|
||||
@@ -479,6 +508,11 @@ export default function Home(): JSX.Element {
|
||||
}
|
||||
};
|
||||
|
||||
// Shuffle companies on mount for fair rotation
|
||||
useEffect(() => {
|
||||
setShuffledCompanies(shuffleArray(companiesWithLogos));
|
||||
}, []);
|
||||
|
||||
// Set up dark <-> light navbar change
|
||||
useEffect(() => {
|
||||
changeToDark();
|
||||
@@ -747,6 +781,74 @@ export default function Home(): JSX.Element {
|
||||
</span>
|
||||
</StyledIntegrations>
|
||||
</BlurredSection>
|
||||
{/* Only show carousel when we have enough logos (>10) for a good display */}
|
||||
{companiesWithLogos.length > 10 && (
|
||||
<BlurredSection>
|
||||
<div style={{ padding: '0 20px' }}>
|
||||
<SectionHeader
|
||||
level="h2"
|
||||
title="Trusted by teams everywhere"
|
||||
subtitle="Join thousands of companies using Superset to explore and visualize their data"
|
||||
/>
|
||||
<div style={{ maxWidth: 1160, margin: '25px auto 0' }}>
|
||||
<Carousel
|
||||
autoplay
|
||||
autoplaySpeed={2000}
|
||||
slidesToShow={6}
|
||||
slidesToScroll={1}
|
||||
dots={false}
|
||||
responsive={[
|
||||
{ breakpoint: 1024, settings: { slidesToShow: 4 } },
|
||||
{ breakpoint: 768, settings: { slidesToShow: 3 } },
|
||||
{ breakpoint: 480, settings: { slidesToShow: 2 } },
|
||||
]}
|
||||
>
|
||||
{shuffledCompanies.map(({ name, url, logo }) => (
|
||||
<div key={name}>
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
aria-label={`Visit ${name}`}
|
||||
>
|
||||
<Card
|
||||
style={{ margin: '0 8px' }}
|
||||
styles={{
|
||||
body: {
|
||||
height: 80,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: 16,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={`/img/logos/${logo}`}
|
||||
alt={name}
|
||||
title={name}
|
||||
style={{ maxHeight: 48, maxWidth: '100%', objectFit: 'contain' }}
|
||||
/>
|
||||
</Card>
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</Carousel>
|
||||
</div>
|
||||
<Flex justify="center" style={{ marginTop: 30, fontSize: 17 }}>
|
||||
<Link to="/inTheWild">See all companies</Link>
|
||||
<span style={{ margin: '0 8px' }}>·</span>
|
||||
<a
|
||||
href="https://github.com/apache/superset/edit/master/RESOURCES/INTHEWILD.yaml"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Add yours to the list!
|
||||
</a>
|
||||
</Flex>
|
||||
</div>
|
||||
</BlurredSection>
|
||||
)}
|
||||
</StyledMain>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
28
docs/src/types/yaml.d.ts
vendored
Normal file
28
docs/src/types/yaml.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
declare module '*.yaml' {
|
||||
const content: unknown;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.yml' {
|
||||
const content: unknown;
|
||||
export default content;
|
||||
}
|
||||
@@ -25,6 +25,13 @@ export default function webpackExtendPlugin(): Plugin<void> {
|
||||
name: 'custom-webpack-plugin',
|
||||
configureWebpack(config) {
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
// Add YAML loader rule directly to existing rules
|
||||
config.module?.rules?.push({
|
||||
test: /\.ya?ml$/,
|
||||
use: 'js-yaml-loader',
|
||||
});
|
||||
|
||||
return {
|
||||
devtool: isDev ? 'eval-source-map' : config.devtool,
|
||||
...(isDev && {
|
||||
|
||||
Reference in New Issue
Block a user