konsta-ui
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseKonsta UI Design Guide
Konsta UI 设计指南
Build pixel-perfect iOS and Material Design apps with Konsta UI.
使用Konsta UI构建像素级完美的iOS和Material Design应用。
When to Use This Skill
何时使用该技能
- User wants native-looking UI without Ionic
- User asks about Konsta UI
- User wants iOS/Material Design components
- User is using React/Vue/Svelte
- User wants lightweight UI framework
- 用户想要无需Ionic的原生风格UI
- 用户咨询Konsta UI相关内容
- 用户需要iOS/Material Design组件
- 用户正在使用React/Vue/Svelte
- 用户想要轻量级UI框架
What is Konsta UI?
什么是Konsta UI?
Konsta UI provides:
- Pixel-perfect iOS and Material Design components
- Works with React, Vue, and Svelte
- Tailwind CSS integration
- ~40 mobile-optimized components
- Small bundle size (~30KB gzipped)
Konsta UI提供:
- 像素级完美的iOS和Material Design组件
- 支持React、Vue和Svelte
- Tailwind CSS集成
- 约40个移动端优化组件
- 小巧的包体积(约30KB gzip压缩后)
Getting Started
快速开始
Installation
安装
bash
undefinedbash
undefinedReact
React
bun add konsta
bun add konsta
Vue
Vue
bun add konsta
bun add konsta
Svelte
Svelte
bun add konsta
bun add konsta
Required: Tailwind CSS
必需依赖:Tailwind CSS
bun add -D tailwindcss postcss autoprefixer
bunx tailwindcss init -p
undefinedbun add -D tailwindcss postcss autoprefixer
bunx tailwindcss init -p
undefinedTailwind Configuration
Tailwind 配置
javascript
// tailwind.config.js
const konstaConfig = require('konsta/config');
module.exports = konstaConfig({
content: [
'./src/**/*.{js,ts,jsx,tsx,vue,svelte}',
],
// Extend or override Konsta config
theme: {
extend: {},
},
});javascript
// tailwind.config.js
const konstaConfig = require('konsta/config');
module.exports = konstaConfig({
content: [
'./src/**/*.{js,ts,jsx,tsx,vue,svelte}',
],
// 扩展或覆盖Konsta配置
theme: {
extend: {},
},
});Setup (React)
React 项目配置
tsx
// App.tsx
import { App, Page, Navbar, Block } from 'konsta/react';
export default function MyApp() {
return (
<App theme="ios"> {/* or theme="material" */}
<Page>
<Navbar title="My App" />
<Block>
<p>Hello Konsta UI!</p>
</Block>
</Page>
</App>
);
}tsx
// App.tsx
import { App, Page, Navbar, Block } from 'konsta/react';
export default function MyApp() {
return (
<App theme="ios"> {/* 或 theme="material" */}
<Page>
<Navbar title="My App" />
<Block>
<p>Hello Konsta UI!</p>
</Block>
</Page>
</App>
);
}Setup (Vue)
Vue 项目配置
vue
<!-- App.vue -->
<template>
<k-app theme="ios">
<k-page>
<k-navbar title="My App" />
<k-block>
<p>Hello Konsta UI!</p>
</k-block>
</k-page>
</k-app>
</template>
<script setup>
import { kApp, kPage, kNavbar, kBlock } from 'konsta/vue';
</script>vue
<!-- App.vue -->
<template>
<k-app theme="ios">
<k-page>
<k-navbar title="My App" />
<k-block>
<p>Hello Konsta UI!</p>
</k-block>
</k-page>
</k-app>
</template>
<script setup>
import { kApp, kPage, kNavbar, kBlock } from 'konsta/vue';
</script>Core Components
核心组件
Page Structure
页面结构
tsx
import {
App,
Page,
Navbar,
NavbarBackLink,
Block,
BlockTitle,
} from 'konsta/react';
function MyPage() {
return (
<App theme="ios">
<Page>
<Navbar
title="Page Title"
subtitle="Subtitle"
left={<NavbarBackLink onClick={() => history.back()} />}
/>
<BlockTitle>Section Title</BlockTitle>
<Block strong inset>
<p>Block content with rounded corners and padding.</p>
</Block>
</Page>
</App>
);
}tsx
import {
App,
Page,
Navbar,
NavbarBackLink,
Block,
BlockTitle,
} from 'konsta/react';
function MyPage() {
return (
<App theme="ios">
<Page>
<Navbar
title="Page Title"
subtitle="Subtitle"
left={<NavbarBackLink onClick={() => history.back()} />}
/>
<BlockTitle>Section Title</BlockTitle>
<Block strong inset>
<p>Block content with rounded corners and padding.</p>
</Block>
</Page>
</App>
);
}Lists
列表组件
tsx
import {
List,
ListItem,
ListInput,
ListButton,
} from 'konsta/react';
import { ChevronRight } from 'framework7-icons/react';
function MyList() {
return (
<>
{/* Simple list */}
<List>
<ListItem title="Item 1" />
<ListItem title="Item 2" />
<ListItem title="Item 3" />
</List>
{/* List with details */}
<List strong inset>
<ListItem
title="John Doe"
subtitle="Designer"
text="Additional info text"
media={<img src="/avatar.jpg" className="w-10 h-10 rounded-full" />}
link
/>
<ListItem
title="Settings"
after="On"
link
/>
</List>
{/* Form list */}
<List strongIos insetIos>
<ListInput
label="Email"
type="email"
placeholder="Enter email"
/>
<ListInput
label="Password"
type="password"
placeholder="Enter password"
/>
<ListButton>Login</ListButton>
</List>
</>
);
}tsx
import {
List,
ListItem,
ListInput,
ListButton,
} from 'konsta/react';
import { ChevronRight } from 'framework7-icons/react';
function MyList() {
return (
<>
{/* 简单列表 */}
<List>
<ListItem title="Item 1" />
<ListItem title="Item 2" />
<ListItem title="Item 3" />
</List>
{/* 带详情的列表 */}
<List strong inset>
<ListItem
title="John Doe"
subtitle="Designer"
text="Additional info text"
media={<img src="/avatar.jpg" className="w-10 h-10 rounded-full" />}
link
/>
<ListItem
title="Settings"
after="On"
link
/>
</List>
{/* 表单列表 */}
<List strongIos insetIos>
<ListInput
label="Email"
type="email"
placeholder="Enter email"
/>
<ListInput
label="Password"
type="password"
placeholder="Enter password"
/>
<ListButton>Login</ListButton>
</List>
</>
);
}Forms
表单组件
tsx
import {
List,
ListInput,
Toggle,
Radio,
Checkbox,
Stepper,
Range,
} from 'konsta/react';
import { useState } from 'react';
function MyForm() {
const [toggle, setToggle] = useState(false);
const [gender, setGender] = useState('male');
return (
<List strongIos insetIos>
{/* Text inputs */}
<ListInput
label="Name"
type="text"
placeholder="Your name"
clearButton
/>
<ListInput
label="Email"
type="email"
placeholder="Email address"
/>
<ListInput
label="Bio"
type="textarea"
placeholder="About yourself"
inputClassName="!h-20 resize-none"
/>
{/* Toggle */}
<ListItem
title="Notifications"
after={
<Toggle
checked={toggle}
onChange={() => setToggle(!toggle)}
/>
}
/>
{/* Radio */}
<ListItem
title="Male"
media={
<Radio
checked={gender === 'male'}
onChange={() => setGender('male')}
/>
}
/>
<ListItem
title="Female"
media={
<Radio
checked={gender === 'female'}
onChange={() => setGender('female')}
/>
}
/>
{/* Checkbox */}
<ListItem
title="Agree to terms"
media={<Checkbox />}
/>
{/* Stepper */}
<ListItem
title="Quantity"
after={<Stepper value={1} min={1} max={10} />}
/>
{/* Range */}
<ListItem
title="Volume"
innerChildren={<Range value={50} />}
/>
</List>
);
}tsx
import {
List,
ListInput,
Toggle,
Radio,
Checkbox,
Stepper,
Range,
} from 'konsta/react';
import { useState } from 'react';
function MyForm() {
const [toggle, setToggle] = useState(false);
const [gender, setGender] = useState('male');
return (
<List strongIos insetIos>
{/* 文本输入框 */}
<ListInput
label="Name"
type="text"
placeholder="Your name"
clearButton
/>
<ListInput
label="Email"
type="email"
placeholder="Email address"
/>
<ListInput
label="Bio"
type="textarea"
placeholder="About yourself"
inputClassName="!h-20 resize-none"
/>
{/* 开关组件 */}
<ListItem
title="Notifications"
after={
<Toggle
checked={toggle}
onChange={() => setToggle(!toggle)}
/>
}
/>
{/* 单选框 */}
<ListItem
title="Male"
media={
<Radio
checked={gender === 'male'}
onChange={() => setGender('male')}
/>
}
/>
<ListItem
title="Female"
media={
<Radio
checked={gender === 'female'}
onChange={() => setGender('female')}
/>
}
/>
{/* 复选框 */}
<ListItem
title="Agree to terms"
media={<Checkbox />}
/>
{/* 步进器 */}
<ListItem
title="Quantity"
after={<Stepper value={1} min={1} max={10} />}
/>
{/* 滑块组件 */}
<ListItem
title="Volume"
innerChildren={<Range value={50} />}
/>
</List>
);
}Buttons
按钮组件
tsx
import { Button, Segmented, SegmentedButton } from 'konsta/react';
import { useState } from 'react';
function Buttons() {
const [active, setActive] = useState(0);
return (
<div className="space-y-4 p-4">
{/* Button variants */}
<Button>Default</Button>
<Button large>Large</Button>
<Button small>Small</Button>
<Button rounded>Rounded</Button>
<Button outline>Outline</Button>
<Button clear>Clear</Button>
<Button tonal>Tonal</Button>
{/* Colors */}
<Button colors={{ fillBg: 'bg-red-500', fillText: 'text-white' }}>
Custom Color
</Button>
{/* Disabled */}
<Button disabled>Disabled</Button>
{/* Segmented control */}
<Segmented strong>
<SegmentedButton active={active === 0} onClick={() => setActive(0)}>
Tab 1
</SegmentedButton>
<SegmentedButton active={active === 1} onClick={() => setActive(1)}>
Tab 2
</SegmentedButton>
<SegmentedButton active={active === 2} onClick={() => setActive(2)}>
Tab 3
</SegmentedButton>
</Segmented>
</div>
);
}tsx
import { Button, Segmented, SegmentedButton } from 'konsta/react';
import { useState } from 'react';
function Buttons() {
const [active, setActive] = useState(0);
return (
<div className="space-y-4 p-4">
{/* 按钮变体 */}
<Button>Default</Button>
<Button large>Large</Button>
<Button small>Small</Button>
<Button rounded>Rounded</Button>
<Button outline>Outline</Button>
<Button clear>Clear</Button>
<Button tonal>Tonal</Button>
{/* 自定义颜色 */}
<Button colors={{ fillBg: 'bg-red-500', fillText: 'text-white' }}>
Custom Color
</Button>
{/* 禁用状态 */}
<Button disabled>Disabled</Button>
{/* 分段控制器 */}
<Segmented strong>
<SegmentedButton active={active === 0} onClick={() => setActive(0)}>
Tab 1
</SegmentedButton>
<SegmentedButton active={active === 1} onClick={() => setActive(1)}>
Tab 2
</SegmentedButton>
<SegmentedButton active={active === 2} onClick={() => setActive(2)}>
Tab 3
</SegmentedButton>
</Segmented>
</div>
);
}Cards
卡片组件
tsx
import { Card, Button } from 'konsta/react';
function Cards() {
return (
<Card>
<img
src="/card-image.jpg"
className="w-full h-48 object-cover"
alt=""
/>
<div className="p-4">
<h3 className="font-bold text-lg">Card Title</h3>
<p className="text-gray-500 mt-2">
Card description text goes here. This is a standard
card with image, title, and content.
</p>
<div className="flex gap-2 mt-4">
<Button small>Action 1</Button>
<Button small outline>Action 2</Button>
</div>
</div>
</Card>
);
}tsx
import { Card, Button } from 'konsta/react';
function Cards() {
return (
<Card>
<img
src="/card-image.jpg"
className="w-full h-48 object-cover"
alt=""
/>
<div className="p-4">
<h3 className="font-bold text-lg">Card Title</h3>
<p className="text-gray-500 mt-2">
Card description text goes here. This is a standard
card with image, title, and content.
</p>
<div className="flex gap-2 mt-4">
<Button small>Action 1</Button>
<Button small outline>Action 2</Button>
</div>
</div>
</Card>
);
}Dialogs and Sheets
对话框与底部弹窗
tsx
import {
Dialog,
DialogButton,
Sheet,
Popup,
Button,
Page,
Navbar,
Block,
} from 'konsta/react';
import { useState } from 'react';
function Dialogs() {
const [dialogOpen, setDialogOpen] = useState(false);
const [sheetOpen, setSheetOpen] = useState(false);
const [popupOpen, setPopupOpen] = useState(false);
return (
<>
<Button onClick={() => setDialogOpen(true)}>Open Dialog</Button>
<Button onClick={() => setSheetOpen(true)}>Open Sheet</Button>
<Button onClick={() => setPopupOpen(true)}>Open Popup</Button>
{/* Alert dialog */}
<Dialog
opened={dialogOpen}
onBackdropClick={() => setDialogOpen(false)}
title="Dialog Title"
content="Dialog content goes here."
buttons={
<>
<DialogButton onClick={() => setDialogOpen(false)}>
Cancel
</DialogButton>
<DialogButton strong onClick={() => setDialogOpen(false)}>
OK
</DialogButton>
</>
}
/>
{/* Bottom sheet */}
<Sheet
opened={sheetOpen}
onBackdropClick={() => setSheetOpen(false)}
>
<div className="p-4">
<h2 className="font-bold text-lg mb-4">Sheet Title</h2>
<p>Sheet content</p>
<Button onClick={() => setSheetOpen(false)} className="mt-4">
Close
</Button>
</div>
</Sheet>
{/* Full page popup */}
<Popup opened={popupOpen} onBackdropClick={() => setPopupOpen(false)}>
<Page>
<Navbar
title="Popup"
right={
<Button clear onClick={() => setPopupOpen(false)}>
Close
</Button>
}
/>
<Block>Popup content</Block>
</Page>
</Popup>
</>
);
}tsx
import {
Dialog,
DialogButton,
Sheet,
Popup,
Button,
Page,
Navbar,
Block,
} from 'konsta/react';
import { useState } from 'react';
function Dialogs() {
const [dialogOpen, setDialogOpen] = useState(false);
const [sheetOpen, setSheetOpen] = useState(false);
const [popupOpen, setPopupOpen] = useState(false);
return (
<>
<Button onClick={() => setDialogOpen(true)}>Open Dialog</Button>
<Button onClick={() => setSheetOpen(true)}>Open Sheet</Button>
<Button onClick={() => setPopupOpen(true)}>Open Popup</Button>
{/* 提示对话框 */}
<Dialog
opened={dialogOpen}
onBackdropClick={() => setDialogOpen(false)}
title="Dialog Title"
content="Dialog content goes here."
buttons={
<>
<DialogButton onClick={() => setDialogOpen(false)}>
Cancel
</DialogButton>
<DialogButton strong onClick={() => setDialogOpen(false)}>
OK
</DialogButton>
</>
}
/>
{/* 底部弹窗 */}
<Sheet
opened={sheetOpen}
onBackdropClick={() => setSheetOpen(false)}
>
<div className="p-4">
<h2 className="font-bold text-lg mb-4">Sheet Title</h2>
<p>Sheet content</p>
<Button onClick={() => setSheetOpen(false)} className="mt-4">
Close
</Button>
</div>
</Sheet>
{/* 全屏弹窗 */}
<Popup opened={popupOpen} onBackdropClick={() => setPopupOpen(false)}>
<Page>
<Navbar
title="Popup"
right={
<Button clear onClick={() => setPopupOpen(false)}>
Close
</Button>
}
/>
<Block>Popup content</Block>
</Page>
</Popup>
</>
);
}Tabbar Navigation
标签栏导航
tsx
import { App, Page, Tabbar, TabbarLink, Icon } from 'konsta/react';
import { Home, Search, Person } from 'framework7-icons/react';
import { useState } from 'react';
function TabsApp() {
const [activeTab, setActiveTab] = useState('home');
return (
<App theme="ios">
<Page>
{/* Page content based on active tab */}
{activeTab === 'home' && <HomeContent />}
{activeTab === 'search' && <SearchContent />}
{activeTab === 'profile' && <ProfileContent />}
{/* Tabbar */}
<Tabbar labels className="left-0 bottom-0 fixed">
<TabbarLink
active={activeTab === 'home'}
onClick={() => setActiveTab('home')}
icon={<Home />}
label="Home"
/>
<TabbarLink
active={activeTab === 'search'}
onClick={() => setActiveTab('search')}
icon={<Search />}
label="Search"
/>
<TabbarLink
active={activeTab === 'profile'}
onClick={() => setActiveTab('profile')}
icon={<Person />}
label="Profile"
/>
</Tabbar>
</Page>
</App>
);
}tsx
import { App, Page, Tabbar, TabbarLink, Icon } from 'konsta/react';
import { Home, Search, Person } from 'framework7-icons/react';
import { useState } from 'react';
function TabsApp() {
const [activeTab, setActiveTab] = useState('home');
return (
<App theme="ios">
<Page>
{/* 根据激活标签显示页面内容 */}
{activeTab === 'home' && <HomeContent />}
{activeTab === 'search' && <SearchContent />}
{activeTab === 'profile' && <ProfileContent />}
{/* 标签栏 */}
<Tabbar labels className="left-0 bottom-0 fixed">
<TabbarLink
active={activeTab === 'home'}
onClick={() => setActiveTab('home')}
icon={<Home />}
label="Home"
/>
<TabbarLink
active={activeTab === 'search'}
onClick={() => setActiveTab('search')}
icon={<Search />}
label="Search"
/>
<TabbarLink
active={activeTab === 'profile'}
onClick={() => setActiveTab('profile')}
icon={<Person />}
label="Profile"
/>
</Tabbar>
</Page>
</App>
);
}Theming
主题配置
Theme Selection
主题选择
tsx
import { App } from 'konsta/react';
// Auto-detect platform
<App theme="parent">
// Force iOS style
<App theme="ios">
// Force Material style
<App theme="material">tsx
import { App } from 'konsta/react';
// 自动检测平台
<App theme="parent">
// 强制使用iOS风格
<App theme="ios">
// 强制使用Material风格
<App theme="material">Dark Mode
深色模式
tsx
import { App } from 'konsta/react';
// Auto dark mode (follows system)
<App dark>
// Explicit dark mode
<App dark={true}>
// Explicit light mode
<App dark={false}>tsx
import { App } from 'konsta/react';
// 自动深色模式(跟随系统设置)
<App dark>
// 强制深色模式
<App dark={true}>
// 强制浅色模式
<App dark={false}>Custom Colors with Tailwind
结合Tailwind自定义颜色
javascript
// tailwind.config.js
const konstaConfig = require('konsta/config');
module.exports = konstaConfig({
theme: {
extend: {
colors: {
primary: {
DEFAULT: '#6366f1',
dark: '#4f46e5',
},
},
},
},
// Override Konsta's primary color
konpistaConfig: {
colors: {
primary: '#6366f1',
},
},
});javascript
// tailwind.config.js
const konstaConfig = require('konsta/config');
module.exports = konstaConfig({
theme: {
extend: {
colors: {
primary: {
DEFAULT: '#6366f1',
dark: '#4f46e5',
},
},
},
},
// 覆盖Konsta的主色调
konpistaConfig: {
colors: {
primary: '#6366f1',
},
},
});Component-Level Styling
组件级样式自定义
tsx
// Override individual component colors
<Button
colors={{
fillBg: 'bg-indigo-500',
fillActiveBg: 'bg-indigo-600',
fillText: 'text-white',
}}
>
Custom Button
</Button>
<Toggle
colors={{
bgChecked: 'bg-green-500',
}}
/>tsx
// 覆盖单个组件的颜色
<Button
colors={{
fillBg: 'bg-indigo-500',
fillActiveBg: 'bg-indigo-600',
fillText: 'text-white',
}}
>
Custom Button
</Button>
<Toggle
colors={{
bgChecked: 'bg-green-500',
}}
/>With Capacitor
与Capacitor结合使用
Safe Area Handling
安全区域处理
tsx
import { App, Page } from 'konsta/react';
function MyApp() {
return (
<App
theme="ios"
safeAreas // Enable safe area handling
>
<Page>
{/* Content respects safe areas */}
</Page>
</App>
);
}tsx
import { App, Page } from 'konsta/react';
function MyApp() {
return (
<App
theme="ios"
safeAreas // 启用安全区域处理
>
<Page>
{/* 内容会自动适配安全区域 */}
</Page>
</App>
);
}Capacitor Integration
Capacitor集成
tsx
import { App, Page, Button } from 'konsta/react';
import { Capacitor } from '@capacitor/core';
function MyApp() {
const isNative = Capacitor.isNativePlatform();
return (
<App
theme={Capacitor.getPlatform() === 'ios' ? 'ios' : 'material'}
safeAreas={isNative}
>
<Page>
<Button onClick={handleNativeAction}>
Native Action
</Button>
</Page>
</App>
);
}tsx
import { App, Page, Button } from 'konsta/react';
import { Capacitor } from '@capacitor/core';
function MyApp() {
const isNative = Capacitor.isNativePlatform();
return (
<App
theme={Capacitor.getPlatform() === 'ios' ? 'ios' : 'material'}
safeAreas={isNative}
>
<Page>
<Button onClick={handleNativeAction}>
Native Action
</Button>
</Page>
</App>
);
}Comparison: Konsta vs Ionic
对比:Konsta vs Ionic
| Feature | Konsta UI | Ionic |
|---|---|---|
| Bundle Size | ~30KB | ~200KB |
| Components | ~40 | ~100+ |
| Tailwind Integration | Native | Possible |
| Routing | External | Built-in |
| Framework Support | React, Vue, Svelte | React, Vue, Angular |
| Native Features | UI only | UI + Plugins |
Choose Konsta when:
- You want Tailwind-first approach
- You need smaller bundle size
- You're using Svelte
- You want simpler setup
Choose Ionic when:
- You need comprehensive component library
- You want built-in routing
- You need more complex components
- You prefer all-in-one solution
| 特性 | Konsta UI | Ionic |
|---|---|---|
| 包体积 | ~30KB | ~200KB |
| 组件数量 | ~40个 | ~100+个 |
| Tailwind集成 | 原生支持 | 可实现 |
| 路由功能 | 依赖外部库 | 内置 |
| 框架支持 | React, Vue, Svelte | React, Vue, Angular |
| 原生功能 | 仅UI | UI + 插件 |
选择Konsta的场景:
- 你偏好Tailwind优先的开发方式
- 你需要更小的包体积
- 你正在使用Svelte
- 你想要更简单的配置流程
选择Ionic的场景:
- 你需要全面的组件库
- 你想要内置路由功能
- 你需要更复杂的组件
- 你偏好一站式解决方案
Best Practices
最佳实践
Performance
性能优化
tsx
// Lazy load heavy components
import { lazy, Suspense } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
);
}tsx
// 懒加载重型组件
import { lazy, Suspense } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
);
}Accessibility
无障碍访问
tsx
// Konsta components are accessible by default
// Add labels for screen readers
<ListInput
label="Email"
type="email"
placeholder="Enter email"
// aria-label is automatically set from label
/>
// For icon-only buttons
<Button aria-label="Close menu">
<Icon name="close" />
</Button>tsx
// Konsta组件默认支持无障碍访问
// 为屏幕阅读器添加标签
<ListInput
label="Email"
type="email"
placeholder="Enter email"
// aria-label会自动从label属性生成
/>
// 纯图标按钮
<Button aria-label="Close menu">
<Icon name="close" />
</Button>Resources
相关资源
- Konsta UI Documentation: https://konstaui.com/
- Konsta React Docs: https://konstaui.com/react
- Konsta Vue Docs: https://konstaui.com/vue
- Konsta Svelte Docs: https://konstaui.com/svelte
- GitHub: https://github.com/konstaui/konsta
- Konsta UI 官方文档: https://konstaui.com/
- Konsta React 文档: https://konstaui.com/react
- Konsta Vue 文档: https://konstaui.com/vue
- Konsta Svelte 文档: https://konstaui.com/svelte
- GitHub 仓库: https://github.com/konstaui/konsta